Port history.ts to v2 scene format with diff-based restore
Replace Fabric.js Canvas dependency with SceneManager. UndoManager now serializes via sceneManager.serialize() and restores via loadScene() with diff-based reconciliation (no flicker, no CORS workarounds).
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
import { Canvas } from 'fabric';
|
import type { SceneManager } from './SceneManager';
|
||||||
|
|
||||||
export class UndoManager {
|
export class UndoManager {
|
||||||
private stack: string[] = [];
|
private stack: string[] = [];
|
||||||
private pointer: number = -1;
|
private pointer: number = -1;
|
||||||
private maxEntries: number = 50;
|
private maxEntries: number = 50;
|
||||||
private locked: boolean = false;
|
private locked: boolean = false;
|
||||||
private canvas: Canvas;
|
private sceneManager: SceneManager;
|
||||||
|
|
||||||
constructor(canvas: Canvas) {
|
constructor(sceneManager: SceneManager) {
|
||||||
this.canvas = canvas;
|
this.sceneManager = sceneManager;
|
||||||
// Save initial state
|
// Save initial state
|
||||||
this.saveState();
|
this.saveState();
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export class UndoManager {
|
|||||||
saveState(): void {
|
saveState(): void {
|
||||||
if (this.locked) return;
|
if (this.locked) return;
|
||||||
|
|
||||||
const json = JSON.stringify((this.canvas as any).toJSON(['id', 'crossOrigin']));
|
const json = JSON.stringify(this.sceneManager.serialize());
|
||||||
|
|
||||||
// If we're not at the end, discard forward history
|
// If we're not at the end, discard forward history
|
||||||
if (this.pointer < this.stack.length - 1) {
|
if (this.pointer < this.stack.length - 1) {
|
||||||
@@ -70,19 +70,7 @@ export class UndoManager {
|
|||||||
|
|
||||||
this.locked = true;
|
this.locked = true;
|
||||||
const parsed = JSON.parse(state);
|
const parsed = JSON.parse(state);
|
||||||
// Ensure images have crossOrigin to prevent canvas tainting
|
this.sceneManager.loadScene(parsed, false).then(() => {
|
||||||
if (parsed?.objects) {
|
|
||||||
for (const obj of parsed.objects) {
|
|
||||||
if (obj.type === 'image') obj.crossOrigin = 'anonymous';
|
|
||||||
if (obj.type === 'group' && obj.objects) {
|
|
||||||
for (const child of obj.objects) {
|
|
||||||
if (child.type === 'image') child.crossOrigin = 'anonymous';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.canvas.loadFromJSON(parsed).then(() => {
|
|
||||||
this.canvas.requestRenderAll();
|
|
||||||
this.locked = false;
|
this.locked = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user