瀏覽代碼

fix fractional indices on adding new elements

Ryan Di 1 年之前
父節點
當前提交
7dfba985f9
共有 4 個文件被更改,包括 62 次插入37 次删除
  1. 18 17
      src/components/App.tsx
  2. 27 12
      src/fractionalIndex.ts
  3. 15 6
      src/scene/Scene.ts
  4. 2 2
      src/zindex.ts

+ 18 - 17
src/components/App.tsx

@@ -268,6 +268,7 @@ import {
   muteFSAbortError,
   isTestEnv,
   easeOut,
+  arrayToMap,
 } from "../utils";
 import {
   createSrcDoc,
@@ -2921,7 +2922,7 @@ class App extends React.Component<AppProps, AppState> {
       ...newElements,
     ];
 
-    this.scene.replaceAllElements(nextElements);
+    this.scene.replaceAllElements(nextElements, arrayToMap(newElements));
 
     newElements.forEach((newElement) => {
       if (isTextElement(newElement) && isBoundToContainer(newElement)) {
@@ -3147,10 +3148,10 @@ class App extends React.Component<AppProps, AppState> {
         this.scene.getElementIndex(frameId),
       );
     } else {
-      this.scene.replaceAllElements([
-        ...this.scene.getElementsIncludingDeleted(),
-        ...textElements,
-      ]);
+      this.scene.replaceAllElements(
+        [...this.scene.getElementsIncludingDeleted(), ...textElements],
+        arrayToMap(textElements),
+      );
     }
 
     this.setState({
@@ -6137,10 +6138,10 @@ class App extends React.Component<AppProps, AppState> {
       height,
     });
 
-    this.scene.replaceAllElements([
-      ...this.scene.getElementsIncludingDeleted(),
-      element,
-    ]);
+    this.scene.replaceAllElements(
+      [...this.scene.getElementsIncludingDeleted(), element],
+      arrayToMap([element]),
+    );
 
     return element;
   };
@@ -6192,10 +6193,10 @@ class App extends React.Component<AppProps, AppState> {
       validated: null,
     });
 
-    this.scene.replaceAllElements([
-      ...this.scene.getElementsIncludingDeleted(),
-      element,
-    ]);
+    this.scene.replaceAllElements(
+      [...this.scene.getElementsIncludingDeleted(), element],
+      arrayToMap([element]),
+    );
 
     return element;
   };
@@ -6473,10 +6474,10 @@ class App extends React.Component<AppProps, AppState> {
         ? newMagicFrameElement(constructorOpts)
         : newFrameElement(constructorOpts);
 
-    this.scene.replaceAllElements([
-      ...this.scene.getElementsIncludingDeleted(),
-      frame,
-    ]);
+    this.scene.replaceAllElements(
+      [...this.scene.getElementsIncludingDeleted(), frame],
+      arrayToMap([frame]),
+    );
 
     this.setState({
       multiElement: null,

+ 27 - 12
src/fractionalIndex.ts

@@ -30,14 +30,14 @@ const isValidFractionalIndex = (
 
 const getContiguousMovedIndices = (
   elements: readonly ExcalidrawElement[],
-  movedElementsMap: Record<string, ExcalidrawElement>,
+  movedElementsMap: Map<string, ExcalidrawElement>,
 ) => {
   const result: number[][] = [];
   const contiguous: number[] = [];
 
   for (let i = 0; i < elements.length; i++) {
     const element = elements[i];
-    if (movedElementsMap[element.id]) {
+    if (movedElementsMap.has(element.id)) {
       if (contiguous.length) {
         if (contiguous[contiguous.length - 1] + 1 === i) {
           contiguous.push(i);
@@ -59,9 +59,22 @@ const getContiguousMovedIndices = (
   return result;
 };
 
+export const generateFractionalIndexBetween = (
+  predecessor: FractionalIndex,
+  successor: FractionalIndex,
+) => {
+  if (predecessor && successor) {
+    if (predecessor < successor) {
+      return generateKeyBetween(predecessor, successor);
+    }
+    return null;
+  }
+  return generateKeyBetween(predecessor, successor);
+};
+
 export const fixFractionalIndices = (
   elements: readonly ExcalidrawElement[],
-  movedElementsMap: Record<string, ExcalidrawElement>,
+  movedElementsMap: Map<string, ExcalidrawElement>,
 ) => {
   const fixedElements = elements.slice();
   const contiguousMovedIndices = getContiguousMovedIndices(
@@ -95,7 +108,7 @@ export const fixFractionalIndices = (
         );
       }
     } catch (e) {
-      console.error("error generating fractional indices", e);
+      console.error("error fixing fractional indices", e);
     }
   }
 
@@ -164,6 +177,8 @@ export const normalizeFractionalIndicies = (
   let pre = -1;
   let suc = 1;
 
+  const normalized: ExcalidrawElement[] = [];
+
   for (const element of allElements) {
     const predecessor = allElements[pre]?.fractionalIndex || null;
     const successor = allElements[suc]?.fractionalIndex || null;
@@ -178,20 +193,20 @@ export const normalizeFractionalIndicies = (
           successor,
         );
 
-        mutateElement(
-          element,
-          {
-            fractionalIndex: nextFractionalIndex,
-          },
-          false,
-        );
+        normalized.push({
+          ...element,
+          fractionalIndex: nextFractionalIndex,
+        });
       } catch (e) {
         console.error("normalizing fractional index", e);
+        normalized.push(element);
       }
+    } else {
+      normalized.push(element);
     }
     pre++;
     suc++;
   }
 
-  return allElements;
+  return normalized;
 };

+ 15 - 6
src/scene/Scene.ts

@@ -11,7 +11,8 @@ import { getSelectedElements } from "./selection";
 import { AppState } from "../types";
 import { Assert, SameType } from "../utility-types";
 import { randomInteger } from "../random";
-import { normalizeFractionalIndicies } from "../fractionalIndex";
+import { fixFractionalIndices } from "../fractionalIndex";
+import { arrayToMap } from "../utils";
 
 type ElementIdKey = InstanceType<typeof LinearElementEditor>["elementId"];
 type ElementKey = ExcalidrawElement | ElementIdKey;
@@ -230,9 +231,14 @@ class Scene {
 
   replaceAllElements(
     nextElements: readonly ExcalidrawElement[],
-    mapElementIds = true,
+    mapOfIndicesToFix?: Map<string, ExcalidrawElement>,
   ) {
-    const _nextElements = normalizeFractionalIndicies(nextElements);
+    let _nextElements;
+    if (mapOfIndicesToFix) {
+      _nextElements = fixFractionalIndices(nextElements, mapOfIndicesToFix);
+    } else {
+      _nextElements = nextElements;
+    }
 
     this.elements = _nextElements;
     const nextFrameLikes: ExcalidrawFrameLikeElement[] = [];
@@ -306,7 +312,7 @@ class Scene {
       element,
       ...this.elements.slice(index),
     ];
-    this.replaceAllElements(nextElements);
+    this.replaceAllElements(nextElements, arrayToMap([element]));
   }
 
   insertElementsAtIndex(elements: ExcalidrawElement[], index: number) {
@@ -321,14 +327,17 @@ class Scene {
       ...this.elements.slice(index),
     ];
 
-    this.replaceAllElements(nextElements);
+    this.replaceAllElements(nextElements, arrayToMap(elements));
   }
 
   addNewElement = (element: ExcalidrawElement) => {
     if (element.frameId) {
       this.insertElementAtIndex(element, this.getElementIndex(element.frameId));
     } else {
-      this.replaceAllElements([...this.elements, element]);
+      this.replaceAllElements(
+        [...this.elements, element],
+        arrayToMap([element]),
+      );
     }
   };
 

+ 2 - 2
src/zindex.ts

@@ -235,9 +235,9 @@ const getTargetElementsMap = <T extends ExcalidrawElement>(
 ) => {
   return indices.reduce((acc, index) => {
     const element = elements[index];
-    acc[element.id] = element;
+    acc.set(element.id, element);
     return acc;
-  }, {} as Record<string, ExcalidrawElement>);
+  }, new Map<string, ExcalidrawElement>());
 };
 
 const shiftElementsByOne = (