-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhistory.js
More file actions
81 lines (70 loc) · 2.18 KB
/
Copy pathhistory.js
File metadata and controls
81 lines (70 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Snapshot-based undo/redo. Because terrain is vector strokes (not a raster),
// snapshots are cheap deep clones of plain data. Camera/selection are intentionally
// excluded — panning and selecting are not undoable actions.
import { HISTORY_LIMIT } from '../constants';
function cloneObject(o) {
return {
...o,
points: o.points ? o.points.map((p) => ({ ...p })) : undefined,
style: o.style ? { ...o.style } : undefined,
};
}
function cloneStroke(s) {
return { ...s, pts: s.pts.map((p) => ({ ...p })) };
}
function cloneLayer(l) {
if (l.kind === 'object') {
return { ...l, objects: l.objects.map(cloneObject) };
}
return {
...l,
strokes: l.strokes.map(cloneStroke),
_raster: null,
_dirty: true,
};
}
export function snapshot(scene) {
return {
themeId: scene.themeId,
grid: { ...scene.grid },
size: { ...scene.size },
activeLayerId: scene.activeLayerId,
meta: { ...scene.meta },
layers: scene.layers.map(cloneLayer),
};
}
export function restore(scene, snap) {
scene.themeId = snap.themeId;
scene.grid = { ...snap.grid };
scene.size = { ...snap.size };
scene.activeLayerId = snap.activeLayerId;
scene.meta = { ...snap.meta };
// clone again so the stored snapshot is never mutated by subsequent edits
scene.layers = snap.layers.map(cloneLayer);
}
export function createHistory(scene) {
return { stack: [snapshot(scene)], index: 0 };
}
export function record(history, scene) {
// drop any redo branch, append new state
history.stack = history.stack.slice(0, history.index + 1);
history.stack.push(snapshot(scene));
if (history.stack.length > HISTORY_LIMIT) {
history.stack.shift();
}
history.index = history.stack.length - 1;
}
export function undo(history, scene) {
if (history.index <= 0) return false;
history.index -= 1;
restore(scene, history.stack[history.index]);
return true;
}
export function redo(history, scene) {
if (history.index >= history.stack.length - 1) return false;
history.index += 1;
restore(scene, history.stack[history.index]);
return true;
}
export const canUndo = (history) => history.index > 0;
export const canRedo = (history) => history.index < history.stack.length - 1;