refactor code
This commit is contained in:
parent
a7154227cf
commit
d1a9c593cc
@ -18,7 +18,6 @@ import throttle from "lodash.throttle";
|
|||||||
import { newElementWith } from "../../src/element/mutateElement";
|
import { newElementWith } from "../../src/element/mutateElement";
|
||||||
import { BroadcastedExcalidrawElement } from "./reconciliation";
|
import { BroadcastedExcalidrawElement } from "./reconciliation";
|
||||||
import { encryptData } from "../../src/data/encryption";
|
import { encryptData } from "../../src/data/encryption";
|
||||||
import { normalizeFractionalIndexing } from "../../src/zindex";
|
|
||||||
|
|
||||||
class Portal {
|
class Portal {
|
||||||
collab: TCollabClass;
|
collab: TCollabClass;
|
||||||
@ -160,7 +159,7 @@ class Portal {
|
|||||||
const data: SocketUpdateDataSource[typeof updateType] = {
|
const data: SocketUpdateDataSource[typeof updateType] = {
|
||||||
type: updateType,
|
type: updateType,
|
||||||
payload: {
|
payload: {
|
||||||
elements: normalizeFractionalIndexing(syncableElements),
|
elements: syncableElements,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ExcalidrawElement } from "../../src/element/types";
|
import { ExcalidrawElement } from "../../src/element/types";
|
||||||
import { AppState } from "../../src/types";
|
import { AppState } from "../../src/types";
|
||||||
import { arrayToMap, arrayToMapWithIndex } from "../../src/utils";
|
import { arrayToMap, arrayToMapWithIndex } from "../../src/utils";
|
||||||
import { orderByFractionalIndex } from "../../src/zindex";
|
import { orderByFractionalIndex } from "../../src/fractionalIndex";
|
||||||
|
|
||||||
export type ReconciledElements = readonly ExcalidrawElement[] & {
|
export type ReconciledElements = readonly ExcalidrawElement[] & {
|
||||||
_brand: "reconciledElements";
|
_brand: "reconciledElements";
|
||||||
|
123
src/fractionalIndex.ts
Normal file
123
src/fractionalIndex.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { mutateElement } from "./element/mutateElement";
|
||||||
|
import { ExcalidrawElement } from "./element/types";
|
||||||
|
import { generateKeyBetween } from "fractional-indexing";
|
||||||
|
|
||||||
|
type FractionalIndex = ExcalidrawElement["fractionalIndex"];
|
||||||
|
|
||||||
|
const isValidFractionalIndex = (
|
||||||
|
index: FractionalIndex,
|
||||||
|
predecessor: FractionalIndex,
|
||||||
|
successor: FractionalIndex,
|
||||||
|
) => {
|
||||||
|
if (index) {
|
||||||
|
if (!predecessor && !successor) {
|
||||||
|
return index.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!predecessor) {
|
||||||
|
// first element
|
||||||
|
return index < successor!;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!successor) {
|
||||||
|
// last element
|
||||||
|
return predecessor! < index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateFractionalIndex = (
|
||||||
|
index: FractionalIndex,
|
||||||
|
predecessor: FractionalIndex,
|
||||||
|
successor: FractionalIndex,
|
||||||
|
) => {
|
||||||
|
if (index) {
|
||||||
|
if (!predecessor && !successor) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!predecessor) {
|
||||||
|
// first element in the array
|
||||||
|
// insert before successor
|
||||||
|
return generateKeyBetween(null, successor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!successor) {
|
||||||
|
// last element in the array
|
||||||
|
// insert after predecessor
|
||||||
|
return generateKeyBetween(predecessor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// both predecessor and successor exist
|
||||||
|
// insert after predecessor
|
||||||
|
return generateKeyBetween(predecessor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateKeyBetween(null, null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const compareStrings = (a: string, b: string) => {
|
||||||
|
return a < b ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const orderByFractionalIndex = (allElements: ExcalidrawElement[]) => {
|
||||||
|
return allElements.sort((a, b) => {
|
||||||
|
if (a.fractionalIndex && b.fractionalIndex) {
|
||||||
|
if (a.fractionalIndex < b.fractionalIndex) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.fractionalIndex > b.fractionalIndex) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return compareStrings(a.id, b.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normalize the fractional indicies of the elements in the given array such that
|
||||||
|
* every element in the array has a fractional index smaller than its successor's
|
||||||
|
*
|
||||||
|
* note that this function is not pure, it mutates elements whose fractional indicies
|
||||||
|
* need updating
|
||||||
|
*/
|
||||||
|
export const normalizeFractionalIndicies = (
|
||||||
|
allElements: readonly ExcalidrawElement[],
|
||||||
|
) => {
|
||||||
|
let pre = -1;
|
||||||
|
let suc = 1;
|
||||||
|
|
||||||
|
for (const element of allElements) {
|
||||||
|
const predecessor = allElements[pre]?.fractionalIndex || null;
|
||||||
|
const successor = allElements[suc]?.fractionalIndex || null;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isValidFractionalIndex(element.fractionalIndex, predecessor, successor)
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const nextFractionalIndex = generateFractionalIndex(
|
||||||
|
element.fractionalIndex,
|
||||||
|
predecessor,
|
||||||
|
successor,
|
||||||
|
);
|
||||||
|
|
||||||
|
mutateElement(
|
||||||
|
element,
|
||||||
|
{
|
||||||
|
fractionalIndex: nextFractionalIndex,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("normalizing fractional index", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pre++;
|
||||||
|
suc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allElements;
|
||||||
|
};
|
@ -11,7 +11,7 @@ import { getSelectedElements } from "./selection";
|
|||||||
import { AppState } from "../types";
|
import { AppState } from "../types";
|
||||||
import { Assert, SameType } from "../utility-types";
|
import { Assert, SameType } from "../utility-types";
|
||||||
import { randomInteger } from "../random";
|
import { randomInteger } from "../random";
|
||||||
import { normalizeFractionalIndexing } from "../zindex";
|
import { normalizeFractionalIndicies } from "../fractionalIndex";
|
||||||
|
|
||||||
type ElementIdKey = InstanceType<typeof LinearElementEditor>["elementId"];
|
type ElementIdKey = InstanceType<typeof LinearElementEditor>["elementId"];
|
||||||
type ElementKey = ExcalidrawElement | ElementIdKey;
|
type ElementKey = ExcalidrawElement | ElementIdKey;
|
||||||
@ -232,7 +232,7 @@ class Scene {
|
|||||||
nextElements: readonly ExcalidrawElement[],
|
nextElements: readonly ExcalidrawElement[],
|
||||||
mapElementIds = true,
|
mapElementIds = true,
|
||||||
) {
|
) {
|
||||||
const _nextElements = normalizeFractionalIndexing(nextElements);
|
const _nextElements = normalizeFractionalIndicies(nextElements);
|
||||||
|
|
||||||
this.elements = _nextElements;
|
this.elements = _nextElements;
|
||||||
const nextFrameLikes: ExcalidrawFrameLikeElement[] = [];
|
const nextFrameLikes: ExcalidrawFrameLikeElement[] = [];
|
||||||
|
121
src/zindex.ts
121
src/zindex.ts
@ -1,4 +1,4 @@
|
|||||||
import { bumpVersion, mutateElement } from "./element/mutateElement";
|
import { bumpVersion } from "./element/mutateElement";
|
||||||
import { isFrameLikeElement } from "./element/typeChecks";
|
import { isFrameLikeElement } from "./element/typeChecks";
|
||||||
import { ExcalidrawElement, ExcalidrawFrameLikeElement } from "./element/types";
|
import { ExcalidrawElement, ExcalidrawFrameLikeElement } from "./element/types";
|
||||||
import { getElementsInGroup } from "./groups";
|
import { getElementsInGroup } from "./groups";
|
||||||
@ -6,7 +6,6 @@ import { getSelectedElements } from "./scene";
|
|||||||
import Scene from "./scene/Scene";
|
import Scene from "./scene/Scene";
|
||||||
import { AppState } from "./types";
|
import { AppState } from "./types";
|
||||||
import { arrayToMap, findIndex, findLastIndex } from "./utils";
|
import { arrayToMap, findIndex, findLastIndex } from "./utils";
|
||||||
import { generateKeyBetween } from "fractional-indexing";
|
|
||||||
|
|
||||||
const isOfTargetFrame = (element: ExcalidrawElement, frameId: string) => {
|
const isOfTargetFrame = (element: ExcalidrawElement, frameId: string) => {
|
||||||
return element.frameId === frameId || element.id === frameId;
|
return element.frameId === frameId || element.id === frameId;
|
||||||
@ -486,124 +485,6 @@ function shiftElementsAccountingForFrames(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fractional indexing
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
type FractionalIndex = ExcalidrawElement["fractionalIndex"];
|
|
||||||
|
|
||||||
const isValidFractionalIndex = (
|
|
||||||
index: FractionalIndex,
|
|
||||||
predecessor: FractionalIndex,
|
|
||||||
successor: FractionalIndex,
|
|
||||||
) => {
|
|
||||||
if (index) {
|
|
||||||
if (!predecessor && !successor) {
|
|
||||||
return index.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!predecessor) {
|
|
||||||
// first element
|
|
||||||
return index < successor!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!successor) {
|
|
||||||
// last element
|
|
||||||
return predecessor! < index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateFractionalIndex = (
|
|
||||||
index: FractionalIndex,
|
|
||||||
predecessor: FractionalIndex,
|
|
||||||
successor: FractionalIndex,
|
|
||||||
) => {
|
|
||||||
if (index) {
|
|
||||||
if (!predecessor && !successor) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!predecessor) {
|
|
||||||
// first element in the array
|
|
||||||
return generateKeyBetween(null, successor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!successor) {
|
|
||||||
// last element in the array
|
|
||||||
return generateKeyBetween(predecessor, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// both predecessor and successor exist
|
|
||||||
// insert after predecessor
|
|
||||||
return generateKeyBetween(predecessor, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return generateKeyBetween(null, null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const compareStrings = (a: string, b: string) => {
|
|
||||||
return a < b ? -1 : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const orderByFractionalIndex = (allElements: ExcalidrawElement[]) => {
|
|
||||||
return allElements.sort((a, b) => {
|
|
||||||
if (a.fractionalIndex && b.fractionalIndex) {
|
|
||||||
if (a.fractionalIndex < b.fractionalIndex) {
|
|
||||||
return -1;
|
|
||||||
} else if (a.fractionalIndex > b.fractionalIndex) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return compareStrings(a.id, b.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* normalize the fractional indicies of the elements in the given array such that
|
|
||||||
* a. all elements have a fraction index between floor and ceiling as defined above
|
|
||||||
* b. for every element, its fractional index is greater than its predecessor's and smaller than its successor's
|
|
||||||
*/
|
|
||||||
export const normalizeFractionalIndexing = (
|
|
||||||
allElements: readonly ExcalidrawElement[],
|
|
||||||
) => {
|
|
||||||
let pre = -1;
|
|
||||||
let suc = 1;
|
|
||||||
|
|
||||||
for (const element of allElements) {
|
|
||||||
const predecessor = allElements[pre]?.fractionalIndex || null;
|
|
||||||
const successor = allElements[suc]?.fractionalIndex || null;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isValidFractionalIndex(element.fractionalIndex, predecessor, successor)
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const nextFractionalIndex = generateFractionalIndex(
|
|
||||||
element.fractionalIndex,
|
|
||||||
predecessor,
|
|
||||||
successor,
|
|
||||||
);
|
|
||||||
|
|
||||||
mutateElement(
|
|
||||||
element,
|
|
||||||
{
|
|
||||||
fractionalIndex: nextFractionalIndex,
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pre++;
|
|
||||||
suc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return allElements;
|
|
||||||
};
|
|
||||||
|
|
||||||
// public API
|
// public API
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user