Christopher Chedeau 5 år sedan
förälder
incheckning
9e5c5daf64
1 ändrade filer med 51 tillägg och 0 borttagningar
  1. 51 0
      src/index.tsx

+ 51 - 0
src/index.tsx

@@ -20,6 +20,34 @@ const LOCAL_STORAGE_KEY_STATE = "excalidraw-state";
 
 const elements = Array.of<ExcalidrawElement>();
 
+let skipHistory = false;
+const stateHistory: string[] = [];
+function generateHistoryCurrentEntry() {
+  return JSON.stringify(
+    elements.map(element => ({ ...element, isSelected: false }))
+  );
+}
+function pushHistoryEntry(newEntry: string) {
+  if (
+    stateHistory.length > 0 &&
+    stateHistory[stateHistory.length - 1] === newEntry
+  ) {
+    // If the last entry is the same as this one, ignore it
+    return;
+  }
+  stateHistory.push(newEntry);
+}
+function restoreHistoryEntry(entry: string) {
+  const newElements = JSON.parse(entry);
+  elements.splice(0, elements.length);
+  newElements.forEach((newElement: ExcalidrawElement) => {
+    generateDraw(newElement);
+    elements.push(newElement);
+  });
+  // When restoring, we shouldn't add an history entry otherwise we'll be stuck with it and can't go back
+  skipHistory = true;
+}
+
 // https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316
 const LCG = (seed: number) => () =>
   ((2 ** 31 - 1) & (seed = Math.imul(48271, seed))) / 2 ** 31;
@@ -901,6 +929,17 @@ class App extends React.Component<{}, AppState> {
       event.preventDefault();
     } else if (shapesShortcutKeys.includes(event.key.toLowerCase())) {
       this.setState({ elementType: findElementByKey(event.key) });
+    } else if (event.metaKey && event.code === "KeyZ") {
+      let lastEntry = stateHistory.pop();
+      // If nothing was changed since last, take the previous one
+      if (generateHistoryCurrentEntry() === lastEntry) {
+        lastEntry = stateHistory.pop();
+      }
+      if (lastEntry !== undefined) {
+        restoreHistoryEntry(lastEntry);
+      }
+      this.forceUpdate();
+      event.preventDefault();
     }
   };
 
@@ -1301,6 +1340,8 @@ class App extends React.Component<{}, AppState> {
                   });
                   lastX = x;
                   lastY = y;
+                  // We don't want to save history when resizing an element
+                  skipHistory = true;
                   this.forceUpdate();
                   return;
                 }
@@ -1319,6 +1360,8 @@ class App extends React.Component<{}, AppState> {
                   });
                   lastX = x;
                   lastY = y;
+                  // We don't want to save history when dragging an element to initially size it
+                  skipHistory = true;
                   this.forceUpdate();
                   return;
                 }
@@ -1347,6 +1390,8 @@ class App extends React.Component<{}, AppState> {
               if (this.state.elementType === "selection") {
                 setSelection(draggingElement);
               }
+              // We don't want to save history when moving an element
+              skipHistory = true;
               this.forceUpdate();
             };
 
@@ -1384,6 +1429,8 @@ class App extends React.Component<{}, AppState> {
             window.addEventListener("mousemove", onMouseMove);
             window.addEventListener("mouseup", onMouseUp);
 
+            // We don't want to save history on mouseDown, only on mouseUp when it's fully configured
+            skipHistory = true;
             this.forceUpdate();
           }}
         />
@@ -1407,6 +1454,10 @@ class App extends React.Component<{}, AppState> {
       viewBackgroundColor: this.state.viewBackgroundColor
     });
     save(this.state);
+    if (!skipHistory) {
+      pushHistoryEntry(generateHistoryCurrentEntry());
+    }
+    skipHistory = false;
   }
 }