So I am implementing undo for my project with the stringify and loadFromJSON approach, but it seems that after the JSON is loaded, only textboxes got their ‘selectable’ and ‘hasControls’ automatically set to false.
Below is my implementation:
const saveHistory = useCallback(() => {
if (!canvas) return;
const state = JSON.stringify(canvas.toJSON(['selectable', 'hasControls', 'evented', 'hoverCursor', 'name']));
setHistoryUndo((prevState) => {
let historyUndoClone = [...prevState];
if (historyUndoClone.length === HISTORY_LIMIT) {
historyUndoClone.shift();
}
return [...historyUndoClone, state];
});
setHistoryRedo([]);
}, [canvas, setHistoryRedo, setHistoryUndo]);
useEffect(() => {
if (canvas) {
// Other event listeners...
canvas.on('object:modified', (event) => {
saveHistory();
});
canvas.on('text:changed', (event) => {
saveHistory();
});
}
return () => {
if (canvas) {
canvas.off();
}
};
}, [canvas, activeTool, setActiveTool, setExpanded, setSelectedObjects, historyRedo, historyUndo, saveHistory]);
I used text:changed to watch for text edit. I also included ‘selectable’, ‘hasControls’ in the toObject method.
Below is the logic for undo:
if (historyUndo.length > 1) {
let historyUndoClone = [...historyUndo];
const previousState = historyUndoClone.pop();
setHistoryUndo(historyUndoClone);
if (previousState) {
const selectedObjects = canvas.getActiveObjects();
const lastState = historyUndoClone[historyUndoClone.length - 1];
canvas.loadFromJSON(lastState, () => {
canvas.renderAll();
});
}
}
Currently, I don’t know what caused this, I can go another approach to fix the issue by get all objects which are type of ‘textbox’ after load the canvas from JSON and manually set their ‘selectable’ and ‘hasControls’ to true
canvas.loadFromJSON(nextState, () => {
const newObjects = canvas.getObjects();
newObjects.forEach(object => {
if (object.type === 'textbox') {
object.set({
selectable: true,
hasControls: true,
});
}
});
canvas.renderAll();
});