History tweaks (#1641)

Co-authored-by: Pete Hunt <phunt@twitter.com>
This commit is contained in:
David Luzar 2020-05-25 00:17:14 +02:00 committed by GitHub
parent d315e3dc4d
commit 35049e3de7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 46 deletions

View File

@ -6,7 +6,7 @@ import { randomInteger } from "../random";
type ElementUpdate<TElement extends ExcalidrawElement> = Omit< type ElementUpdate<TElement extends ExcalidrawElement> = Omit<
Partial<TElement>, Partial<TElement>,
"id" | "seed" "id" | "seed" | "version" | "versionNonce"
>; >;
// This function tracks updates of text elements for the purposes for collaboration. // This function tracks updates of text elements for the purposes for collaboration.
@ -52,7 +52,7 @@ export const newElementWith = <TElement extends ExcalidrawElement>(
updates: ElementUpdate<TElement>, updates: ElementUpdate<TElement>,
): TElement => ({ ): TElement => ({
...element, ...element,
...updates,
version: element.version + 1, version: element.version + 1,
versionNonce: randomInteger(), versionNonce: randomInteger(),
...updates,
}); });

View File

@ -1,6 +1,5 @@
import { AppState } from "./types"; import { AppState } from "./types";
import { ExcalidrawElement } from "./element/types"; import { ExcalidrawElement } from "./element/types";
import { newElementWith } from "./element/mutateElement";
import { isLinearElement } from "./element/typeChecks"; import { isLinearElement } from "./element/typeChecks";
import { deepCopyElement } from "./element/newElement"; import { deepCopyElement } from "./element/newElement";
@ -11,12 +10,11 @@ export interface HistoryEntry {
interface DehydratedExcalidrawElement { interface DehydratedExcalidrawElement {
id: string; id: string;
version: number;
versionNonce: number; versionNonce: number;
} }
interface DehydratedHistoryEntry { interface DehydratedHistoryEntry {
appState: ReturnType<typeof clearAppStatePropertiesForHistory>; appState: string;
elements: DehydratedExcalidrawElement[]; elements: DehydratedExcalidrawElement[];
} }
@ -29,10 +27,7 @@ const clearAppStatePropertiesForHistory = (appState: AppState) => {
}; };
export class SceneHistory { export class SceneHistory {
private elementCache = new Map< private elementCache = new Map<string, Map<number, ExcalidrawElement>>();
string,
Map<number, Map<number, ExcalidrawElement>>
>();
private recording: boolean = true; private recording: boolean = true;
private stateHistory: DehydratedHistoryEntry[] = []; private stateHistory: DehydratedHistoryEntry[] = [];
private redoStack: DehydratedHistoryEntry[] = []; private redoStack: DehydratedHistoryEntry[] = [];
@ -43,18 +38,16 @@ export class SceneHistory {
elements, elements,
}: DehydratedHistoryEntry): HistoryEntry { }: DehydratedHistoryEntry): HistoryEntry {
return { return {
appState, appState: JSON.parse(appState),
elements: elements.map((dehydratedExcalidrawElement) => { elements: elements.map((dehydratedExcalidrawElement) => {
const element = this.elementCache const element = this.elementCache
.get(dehydratedExcalidrawElement.id) .get(dehydratedExcalidrawElement.id)
?.get(dehydratedExcalidrawElement.version)
?.get(dehydratedExcalidrawElement.versionNonce); ?.get(dehydratedExcalidrawElement.versionNonce);
if (!element) { if (!element) {
throw new Error( throw new Error(
`Element not found: ${dehydratedExcalidrawElement.id}:${dehydratedExcalidrawElement.version}:${dehydratedExcalidrawElement.versionNonce}`, `Element not found: ${dehydratedExcalidrawElement.id}:${dehydratedExcalidrawElement.versionNonce}`,
); );
} }
return element; return element;
}), }),
}; };
@ -65,22 +58,17 @@ export class SceneHistory {
elements, elements,
}: HistoryEntry): DehydratedHistoryEntry { }: HistoryEntry): DehydratedHistoryEntry {
return { return {
appState, appState: JSON.stringify(appState),
elements: elements.map((element) => { elements: elements.map((element: ExcalidrawElement) => {
if (!this.elementCache.has(element.id)) { if (!this.elementCache.has(element.id)) {
this.elementCache.set(element.id, new Map()); this.elementCache.set(element.id, new Map());
} }
const versions = this.elementCache.get(element.id)!; const versions = this.elementCache.get(element.id)!;
if (!versions.has(element.version)) { if (!versions.has(element.versionNonce)) {
versions.set(element.version, new Map()); versions.set(element.versionNonce, deepCopyElement(element));
}
const nonces = versions.get(element.version)!;
if (!nonces.has(element.versionNonce)) {
nonces.set(element.versionNonce, deepCopyElement(element));
} }
return { return {
id: element.id, id: element.id,
version: element.version,
versionNonce: element.versionNonce, versionNonce: element.versionNonce,
}; };
}), }),
@ -162,7 +150,6 @@ export class SceneHistory {
!prev || !prev ||
!next || !next ||
prev.id !== next.id || prev.id !== next.id ||
prev.version !== next.version ||
prev.versionNonce !== next.versionNonce prev.versionNonce !== next.versionNonce
) { ) {
return true; return true;
@ -199,17 +186,6 @@ export class SceneHistory {
} }
} }
private restoreEntry(entrySerialized: DehydratedHistoryEntry): HistoryEntry {
const entry = this.hydrateHistoryEntry(entrySerialized);
if (entry) {
entry.elements = entry.elements.map((element) => {
// renew versions
return newElementWith(element, {});
});
}
return entry;
}
clearRedoStack() { clearRedoStack() {
this.redoStack.splice(0, this.redoStack.length); this.redoStack.splice(0, this.redoStack.length);
} }
@ -223,7 +199,7 @@ export class SceneHistory {
if (entryToRestore !== undefined) { if (entryToRestore !== undefined) {
this.stateHistory.push(entryToRestore); this.stateHistory.push(entryToRestore);
return this.restoreEntry(entryToRestore); return this.hydrateHistoryEntry(entryToRestore);
} }
return null; return null;
@ -240,7 +216,7 @@ export class SceneHistory {
if (currentEntry !== undefined) { if (currentEntry !== undefined) {
this.redoStack.push(currentEntry); this.redoStack.push(currentEntry);
return this.restoreEntry(entryToRestore); return this.hydrateHistoryEntry(entryToRestore);
} }
return null; return null;

View File

@ -3697,8 +3697,8 @@ Object {
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 1, "strokeWidth": 1,
"type": "rectangle", "type": "rectangle",
"version": 3, "version": 4,
"versionNonce": 1014066025, "versionNonce": 1116226695,
"width": 10, "width": 10,
"x": 10, "x": 10,
"y": 10, "y": 10,
@ -3720,8 +3720,8 @@ Object {
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 1, "strokeWidth": 1,
"type": "rectangle", "type": "rectangle",
"version": 3, "version": 4,
"versionNonce": 238820263, "versionNonce": 1014066025,
"width": 10, "width": 10,
"x": 30, "x": 30,
"y": 10, "y": 10,
@ -12061,8 +12061,8 @@ Object {
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 1, "strokeWidth": 1,
"type": "rectangle", "type": "rectangle",
"version": 3, "version": 6,
"versionNonce": 941653321, "versionNonce": 1006504105,
"width": 10, "width": 10,
"x": 10, "x": 10,
"y": 10, "y": 10,
@ -12084,8 +12084,8 @@ Object {
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 1, "strokeWidth": 1,
"type": "rectangle", "type": "rectangle",
"version": 3, "version": 6,
"versionNonce": 908564423, "versionNonce": 289600103,
"width": 10, "width": 10,
"x": 30, "x": 30,
"y": 10, "y": 10,
@ -12121,8 +12121,8 @@ Object {
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 1, "strokeWidth": 1,
"type": "arrow", "type": "arrow",
"version": 9, "version": 11,
"versionNonce": 1349943049, "versionNonce": 1315507081,
"width": 10, "width": 10,
"x": 10, "x": 10,
"y": 30, "y": 30,