Skip to content

Commit 2fa7755

Browse files
author
HarshKhandeparkar
committed
feat: undo using snapshots
1 parent f2e096c commit 2fa7755

File tree

6 files changed

+40
-118
lines changed

6 files changed

+40
-118
lines changed

dist/gpujs-real-renderer-browser.js

Lines changed: 20 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,35 +1052,15 @@
10521052
Object.defineProperty(exports, "__esModule", { value: true });
10531053
exports.redo = exports.undo = void 0;
10541054
function undo(numUndo) {
1055-
var _this = this;
10561055
if (numUndo === void 0) { numUndo = 1; }
1057-
if (this._pathIndex >= numUndo - 1 && this._pathIndex - numUndo < this._drawnPaths.length) {
1058-
this.graphPixels = this._blankGraph(); // Start with a blank graph
1059-
var originalMode = this.mode, originalBrushColor = this.brushColor, originalBrushSize = this.brushSize, originalEraserSize = this.eraserSize;
1060-
this._removeDOMEvents();
1061-
this._drawnPaths.slice(0, this._pathIndex - numUndo + 1).forEach(function (path) {
1062-
_this.mode = path.mode;
1063-
_this.brushColor = path.color;
1064-
_this.brushSize = path.brushSize;
1065-
_this.eraserSize = path.eraserSize;
1066-
_this._lastCoords.delete('temp');
1067-
path.pathCoords.forEach(function (coord) {
1068-
if (coord[2] === false) {
1069-
_this._stroke(coord[0], coord[1], 'temp'); // Replay all strokes
1070-
_this._lastCoords.set('temp', [coord[0], coord[1]]);
1071-
}
1072-
else
1073-
_this._plot(coord[0], coord[1]);
1074-
});
1075-
});
1076-
this.mode = originalMode;
1077-
this.brushColor = originalBrushColor;
1078-
this.brushSize = originalBrushSize;
1079-
this.eraserSize = originalEraserSize;
1080-
this._pathIndex -= numUndo;
1081-
this._lastCoords.delete('temp');
1056+
if (this._currentSnapshotIndex - numUndo >= 0 &&
1057+
this._currentSnapshotIndex - numUndo < this._snapshots.length) {
1058+
var wasDrawing = this._isDrawing;
1059+
this.stopRender();
1060+
this.graphPixels = this._loadData(this._snapshots[this._currentSnapshotIndex - numUndo]);
1061+
this._currentSnapshotIndex -= numUndo;
10821062
this._display(this.graphPixels);
1083-
if (this._isDrawing)
1063+
if (wasDrawing)
10841064
this.startRender();
10851065
}
10861066
return this;
@@ -1118,10 +1098,11 @@
11181098
}
11191099
exports.changeMode = changeMode;
11201100
function clear() {
1121-
this._drawnPaths = [];
1122-
this._pathIndex = -1;
1101+
this._snapshots = [];
1102+
this._currentSnapshotIndex = 0;
11231103
this._lastCoords.clear();
11241104
this.graphPixels = this._blankGraph();
1105+
this._snapshots[0] = this.getData();
11251106
this._display(this.graphPixels);
11261107
return this;
11271108
}
@@ -1135,8 +1116,8 @@
11351116
this.eraserSize = this.options.eraserSize;
11361117
this.mode = this.options.mode;
11371118
this._isDrawing = false;
1138-
this._drawnPaths = [];
1139-
this._pathIndex = -1;
1119+
this._currentSnapshotIndex = 0;
1120+
this._snapshots = [this.getData()];
11401121
this._lastCoords.clear();
11411122
this.stopRender();
11421123
}
@@ -1169,42 +1150,23 @@
11691150
});
11701151

11711152
var stroke = createCommonjsModule(function (module, exports) {
1172-
var __spreadArrays = (commonjsGlobal && commonjsGlobal.__spreadArrays) || function () {
1173-
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
1174-
for (var r = Array(s), k = 0, i = 0; i < il; i++)
1175-
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
1176-
r[k] = a[j];
1177-
return r;
1178-
};
11791153
Object.defineProperty(exports, "__esModule", { value: true });
11801154
exports._doStroke = exports._endStroke = exports._startStroke = void 0;
11811155
function _startStroke(coords, identifier) {
1182-
this._drawnPaths[this._pathIndex + 1] = {
1183-
pathCoords: [],
1184-
color: this.brushColor.map(function (x) { return x; }),
1185-
mode: this.mode,
1186-
brushSize: this.brushSize,
1187-
eraserSize: this.eraserSize
1188-
};
1189-
this._plot.apply(this, coords);
1156+
if (this._currentSnapshotIndex < this._snapshots.length - 1)
1157+
this._snapshots.splice(this._currentSnapshotIndex + 1); // Delete all redo snapshots
1158+
this._plot.apply(// Delete all redo snapshots
1159+
this, coords);
11901160
this._lastCoords.set(identifier, coords);
11911161
}
11921162
exports._startStroke = _startStroke;
11931163
function _endStroke(endCoords, identifier) {
11941164
this._plot.apply(this, endCoords);
1195-
if (this._drawnPaths[this._pathIndex + 1])
1196-
this._drawnPaths[this._pathIndex + 1].pathCoords.push(__spreadArrays(endCoords, [true]));
11971165
this._lastCoords.delete(identifier);
1198-
if (this._drawnPaths[this._pathIndex + 1].pathCoords.length === 0)
1199-
this._drawnPaths.splice(-1, 1);
1200-
else {
1201-
this._drawnPaths = this._drawnPaths.slice(0, this._pathIndex + 2); // Overwrite further paths to prevent wrong redos
1202-
this._pathIndex++;
1203-
}
1166+
this._snapshots[++this._currentSnapshotIndex] = this.getData();
12041167
}
12051168
exports._endStroke = _endStroke;
12061169
function _doStroke(coords, identifier) {
1207-
this._drawnPaths[this._pathIndex + 1].pathCoords.push(__spreadArrays(coords, [false]));
12081170
this._plot.apply(this, coords);
12091171
this._stroke(coords[0], coords[1], identifier);
12101172
this._lastCoords.set(identifier, coords);
@@ -1293,8 +1255,8 @@
12931255
// *****DEFAULTS*****
12941256
_super.call(this, options) || this;
12951257
_this._isDrawing = false;
1296-
_this._drawnPaths = [];
1297-
_this._pathIndex = -1; // Index of path in _drawnPaths
1258+
_this._snapshots = []; // Undo snapshots
1259+
_this._currentSnapshotIndex = 0; // Current snapshot
12981260
/** key -> identifier, value -> coordinate
12991261
* For mouse, the key is 'mouse', for touches, stringified identifier -> https://developer.mozilla.org/en-US/docs/Web/API/Touch/identifier
13001262
*/
@@ -1375,6 +1337,7 @@
13751337
_this.mode = options.mode;
13761338
// *****DEFAULTS*****
13771339
_this._initializeKernels();
1340+
_this._snapshots[0] = _this.getData();
13781341
return _this;
13791342
}
13801343
// --- Touch Events ---

dist/gpujs-real-renderer-browser.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/renderers/RealDrawBoard/RealDrawBoard.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,8 @@ export class RealDrawBoard extends RealRenderer {
4242
eraserSize: number;
4343
mode: DrawMode;
4444
_isDrawing: boolean = false;
45-
_drawnPaths: {
46-
pathCoords: [number, number, boolean][], // [x, y, isAPoint][]
47-
color: Color,
48-
mode: DrawMode,
49-
brushSize: number,
50-
eraserSize: number
51-
}[] = [];
52-
_pathIndex: number = -1; // Index of path in _drawnPaths
45+
_snapshots: number[][] = []; // Undo snapshots
46+
_currentSnapshotIndex = 0; // Current snapshot
5347
_plotKernel: IKernelRunShortcut;
5448
_previewPlot: IKernelRunShortcut;
5549
_strokeKernel: IKernelRunShortcut;
@@ -98,6 +92,7 @@ export class RealDrawBoard extends RealRenderer {
9892
// *****DEFAULTS*****
9993

10094
this._initializeKernels();
95+
this._snapshots[0] = this.getData();
10196
}
10297
// --- DOM Event Listeners ---
10398

src/renderers/RealDrawBoard/boardManip.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ export function changeMode(this: RealDrawBoard, newMode: DrawMode) {
2424
}
2525

2626
export function clear(this: RealDrawBoard) {
27-
this._drawnPaths = [];
28-
this._pathIndex = -1;
27+
this._snapshots = [];
28+
this._currentSnapshotIndex = 0;
2929
this._lastCoords.clear();
3030

3131
this.graphPixels = <Texture>this._blankGraph();
32+
this._snapshots[0] = this.getData();
3233
this._display(this.graphPixels);
3334

3435
return this;
@@ -44,8 +45,8 @@ export function _resetBoard(this: RealDrawBoard) {
4445
this.mode = this.options.mode;
4546

4647
this._isDrawing = false;
47-
this._drawnPaths = [];
48-
this._pathIndex = -1;
48+
this._currentSnapshotIndex = 0;
49+
this._snapshots = [this.getData()];
4950
this._lastCoords.clear();
5051

5152
this.stopRender();

src/renderers/RealDrawBoard/stroke.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
import { RealDrawBoard } from './RealDrawBoard';
2-
import { Color } from '../../types/RealRendererTypes';
32

43
export function _startStroke(
54
this: RealDrawBoard,
65
coords: [number, number],
76
identifier: string
87
) {
9-
this._drawnPaths[this._pathIndex + 1] = {
10-
pathCoords: [],
11-
color: <Color>this.brushColor.map(x => x),
12-
mode: this.mode,
13-
brushSize: this.brushSize,
14-
eraserSize: this.eraserSize
15-
}
8+
if (this._currentSnapshotIndex < this._snapshots.length - 1) this._snapshots.splice(this._currentSnapshotIndex + 1); // Delete all redo snapshots
169
this._plot(...coords);
1710

1811
this._lastCoords.set(identifier, coords);
@@ -24,23 +17,17 @@ export function _endStroke(
2417
identifier: string
2518
) {
2619
this._plot(...endCoords);
27-
if(this._drawnPaths[this._pathIndex + 1]) this._drawnPaths[this._pathIndex + 1].pathCoords.push([...endCoords, true]);
2820

2921
this._lastCoords.delete(identifier);
3022

31-
if (this._drawnPaths[this._pathIndex + 1].pathCoords.length === 0) this._drawnPaths.splice(-1, 1);
32-
else {
33-
this._drawnPaths = this._drawnPaths.slice(0, this._pathIndex + 2); // Overwrite further paths to prevent wrong redos
34-
this._pathIndex++;
35-
}
23+
this._snapshots[++this._currentSnapshotIndex] = this.getData();
3624
}
3725

3826
export function _doStroke(
3927
this: RealDrawBoard,
4028
coords: [number, number],
4129
identifier: string
4230
) {
43-
this._drawnPaths[this._pathIndex + 1].pathCoords.push([...coords, false]);
4431
this._plot(...coords);
4532
this._stroke(coords[0], coords[1], identifier);
4633

src/renderers/RealDrawBoard/undo.ts

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,19 @@ import { RealDrawBoard } from './RealDrawBoard';
22
import { Texture } from 'gpu.js';
33

44
export function undo(this: RealDrawBoard, numUndo: number = 1) {
5-
if (this._pathIndex >= numUndo - 1 && this._pathIndex - numUndo < this._drawnPaths.length) {
6-
this.graphPixels = <Texture>this._blankGraph(); // Start with a blank graph
5+
if (
6+
this._currentSnapshotIndex - numUndo >= 0 &&
7+
this._currentSnapshotIndex - numUndo < this._snapshots.length
8+
) {
9+
const wasDrawing = this._isDrawing;
10+
this.stopRender();
711

8-
const originalMode = this.mode,
9-
originalBrushColor = this.brushColor,
10-
originalBrushSize = this.brushSize,
11-
originalEraserSize = this.eraserSize;
12+
this.graphPixels = <Texture>this._loadData(this._snapshots[this._currentSnapshotIndex - numUndo]);
13+
this._currentSnapshotIndex -= numUndo;
1214

13-
this._removeDOMEvents();
14-
15-
this._drawnPaths.slice(0, this._pathIndex - numUndo + 1).forEach(path => {
16-
this.mode = path.mode;
17-
this.brushColor = path.color;
18-
this.brushSize = path.brushSize;
19-
this.eraserSize = path.eraserSize;
20-
21-
this._lastCoords.delete('temp');
22-
path.pathCoords.forEach(coord => {
23-
if (coord[2] === false) {
24-
this._stroke(coord[0], coord[1], 'temp'); // Replay all strokes
25-
this._lastCoords.set('temp', [coord[0], coord[1]]);
26-
}
27-
else this._plot(coord[0], coord[1])
28-
})
29-
})
30-
31-
this.mode = originalMode;
32-
this.brushColor = originalBrushColor;
33-
this.brushSize = originalBrushSize;
34-
this.eraserSize = originalEraserSize;
35-
36-
this._pathIndex -= numUndo;
37-
38-
this._lastCoords.delete('temp');
3915
this._display(this.graphPixels);
4016

41-
if (this._isDrawing) this.startRender();
17+
if (wasDrawing) this.startRender();
4218
}
4319

4420
return this;

0 commit comments

Comments
 (0)