normalize before replacing

mrazator/test-fractional-index-and-granular-history
Ryan Di 1 year ago
parent 00ffa08e28
commit 1e132e33ae

@ -43,7 +43,6 @@ import {
measureBaseline,
} from "../element/textElement";
import { normalizeLink } from "./url";
import { normalizeFractionalIndexing } from "../zindex";
type RestoredAppState = Omit<
AppState,
@ -583,9 +582,7 @@ export const restore = (
elementsConfig?: { refreshDimensions?: boolean; repairBindings?: boolean },
): RestoredDataState => {
return {
elements: normalizeFractionalIndexing(
restoreElements(data?.elements, localElements, elementsConfig),
),
elements: restoreElements(data?.elements, localElements, elementsConfig),
appState: restoreAppState(data?.appState, localAppState || null),
files: data?.files || {},
};

@ -11,6 +11,7 @@ import { getSelectedElements } from "./selection";
import { AppState } from "../types";
import { Assert, SameType } from "../utility-types";
import { randomInteger } from "../random";
import { normalizeFractionalIndexing } from "../zindex";
type ElementIdKey = InstanceType<typeof LinearElementEditor>["elementId"];
type ElementKey = ExcalidrawElement | ElementIdKey;
@ -231,10 +232,12 @@ class Scene {
nextElements: readonly ExcalidrawElement[],
mapElementIds = true,
) {
this.elements = nextElements;
const _nextElements = normalizeFractionalIndexing(nextElements);
this.elements = _nextElements;
const nextFrameLikes: ExcalidrawFrameLikeElement[] = [];
this.elementsMap.clear();
nextElements.forEach((element) => {
_nextElements.forEach((element) => {
if (isFrameLikeElement(element)) {
nextFrameLikes.push(element);
}

@ -1,4 +1,4 @@
import { bumpVersion } from "./element/mutateElement";
import { bumpVersion, mutateElement } from "./element/mutateElement";
import { isFrameLikeElement } from "./element/typeChecks";
import { ExcalidrawElement, ExcalidrawFrameLikeElement } from "./element/types";
import { getElementsInGroup } from "./groups";
@ -490,74 +490,75 @@ function shiftElementsAccountingForFrames(
// -----------------------------------------------------------------------------
type FractionalIndex = ExcalidrawElement["fractionalIndex"];
const fractionalIndexCompare = {
isSmallerThan(indexA: string, indexB: string) {
return indexA < indexB;
},
isGreaterThan(indexA: string, indexB: string) {
return indexA > indexB;
},
};
const isValidFractionalIndex = (
index: FractionalIndex,
predecessorFractionalIndex: FractionalIndex,
successorFractionalIndex: FractionalIndex,
predecessor: FractionalIndex,
successor: FractionalIndex,
) => {
if (index) {
if (predecessorFractionalIndex) {
if (successorFractionalIndex) {
return (
fractionalIndexCompare.isGreaterThan(
index,
predecessorFractionalIndex,
) &&
fractionalIndexCompare.isSmallerThan(index, successorFractionalIndex)
);
}
return fractionalIndexCompare.isGreaterThan(
index,
predecessorFractionalIndex,
);
if (!predecessor && !successor) {
return index.length > 0;
}
if (successorFractionalIndex) {
return fractionalIndexCompare.isSmallerThan(
index,
successorFractionalIndex,
);
if (!predecessor) {
// first element
return index < successor!;
}
return index.length > 0;
if (!successor) {
// last element
return predecessor! < index;
}
}
return false;
};
const generateFractionalIndex = (
predecessorFractionalIndex: string | null,
successorFractionalIndex: string | null,
index: FractionalIndex,
predecessor: FractionalIndex,
successor: FractionalIndex,
) => {
if (predecessorFractionalIndex && successorFractionalIndex) {
if (predecessorFractionalIndex < successorFractionalIndex) {
return generateKeyBetween(
predecessorFractionalIndex,
successorFractionalIndex,
);
} else if (predecessorFractionalIndex > successorFractionalIndex) {
return generateKeyBetween(
successorFractionalIndex,
predecessorFractionalIndex,
);
if (index) {
if (!predecessor && !successor) {
return index;
}
return generateKeyBetween(predecessorFractionalIndex, null);
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(
predecessorFractionalIndex,
successorFractionalIndex,
);
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;
});
};
/**
@ -568,47 +569,39 @@ const generateFractionalIndex = (
export const normalizeFractionalIndexing = (
allElements: readonly ExcalidrawElement[],
) => {
let predecessor = -1;
let successor = 1;
const normalizedElementsMap = arrayToMap(allElements);
let pre = -1;
let suc = 1;
for (const element of allElements) {
const predecessorFractionalIndex =
normalizedElementsMap.get(allElements[predecessor]?.id)
?.fractionalIndex || null;
const successorFractionalIndex =
normalizedElementsMap.get(allElements[successor]?.id)?.fractionalIndex ||
null;
const predecessor = allElements[pre]?.fractionalIndex || null;
const successor = allElements[suc]?.fractionalIndex || null;
try {
if (
!isValidFractionalIndex(
element.fractionalIndex,
predecessorFractionalIndex,
successorFractionalIndex,
)
) {
if (
!isValidFractionalIndex(element.fractionalIndex, predecessor, successor)
) {
try {
const nextFractionalIndex = generateFractionalIndex(
predecessorFractionalIndex,
successorFractionalIndex,
element.fractionalIndex,
predecessor,
successor,
);
normalizedElementsMap.set(element.id, {
...element,
fractionalIndex: nextFractionalIndex,
});
mutateElement(
element,
{
fractionalIndex: nextFractionalIndex,
},
false,
);
} catch (e) {
console.error(e);
}
} catch (e) {
console.error(e);
}
predecessor++;
successor++;
pre++;
suc++;
}
return [...normalizedElementsMap.values()];
return allElements;
};
// public API
@ -618,31 +611,25 @@ export const moveOneLeft = (
allElements: readonly ExcalidrawElement[],
appState: AppState,
) => {
return normalizeFractionalIndexing(
shiftElementsByOne(allElements, appState, "left"),
);
return shiftElementsByOne(allElements, appState, "left");
};
export const moveOneRight = (
allElements: readonly ExcalidrawElement[],
appState: AppState,
) => {
return normalizeFractionalIndexing(
shiftElementsByOne(allElements, appState, "right"),
);
return shiftElementsByOne(allElements, appState, "right");
};
export const moveAllLeft = (
allElements: readonly ExcalidrawElement[],
appState: AppState,
) => {
return normalizeFractionalIndexing(
shiftElementsAccountingForFrames(
allElements,
appState,
"left",
shiftElementsToEnd,
),
return shiftElementsAccountingForFrames(
allElements,
appState,
"left",
shiftElementsToEnd,
);
};
@ -650,12 +637,10 @@ export const moveAllRight = (
allElements: readonly ExcalidrawElement[],
appState: AppState,
) => {
return normalizeFractionalIndexing(
shiftElementsAccountingForFrames(
allElements,
appState,
"right",
shiftElementsToEnd,
),
return shiftElementsAccountingForFrames(
allElements,
appState,
"right",
shiftElementsToEnd,
);
};

Loading…
Cancel
Save