Undo and Redo
About 1 min
Undo and Redo
Undo / redo support, including undo marks, undo groups, and operation descriptions.
Online Examples
| Example | Description | Link |
|---|---|---|
| Basic Undo | Usage of undo and redo | Online Demo{target="_blank"} |
| Undo Marks | Usage of added_undoMark | Online Demo{target="_blank"} |
| Undo Groups | Usage of start_undoMark and end_undoMark | Online Demo{target="_blank"} |
| Operation Descriptions | UndoDescriptor and history query | Online Demo{target="_blank"} |
Core API
Basic Undo / Redo
const undoMgr = Engine.undoManager;
// Undo last operation
undoMgr.undo();
// Redo last undone operation
undoMgr.redo();
// Check whether undo / redo is available
const canUndo = undoMgr.canUndo();
const canRedo = undoMgr.canRedo();Undo Marks
Undo marks record various operations so they can be rolled back:
// Add entity with automatic undo recording (recommended)
Engine.addEntities(entity1);
// Or record manually
Engine.pcanvas.addEntity(entity2);
Engine.undoManager.added_undoMark([entity2]);
// Erase entity (auto records undo)
Engine.eraseEntities(entity1);Undo Group
// Start undo group (startUndoRecord is recommended — supports nesting)
Engine.startUndoRecord();
try {
const line1 = new LineEnt([0, 0], [100, 0]);
Engine.addEntities(line1);
const line2 = new LineEnt([100, 0], [100, 100]);
Engine.addEntities(line2);
line1.color = 1;
Engine.regen();
} finally {
Engine.endUndoRecord();
}
// Undo treats the whole group as one unit
undoMgr.undo();Operation Descriptions
Attach description info to undo groups so the operation name shows in the command line and UI on undo/redo. The API accepts string | UndoDescriptor — a plain string is shorthand for { category: 'edit', resolvedText: str }.
// Undo group with description — plain text (string shorthand)
Engine.startUndoRecord('Batch modify color');
try {
// ... modify operations ...
} finally {
Engine.endUndoRecord();
}
// Using i18n key (recommended for multi-language support)
Engine.startUndoRecord({ category: 'edit', i18nKey: 'undo.modify.color' });
try {
// ... modify color ...
} finally {
Engine.endUndoRecord();
}Query Undo History
const undoMgr = Engine.undoManager;
// Get undo history list (most recent first)
const undoHistory = undoMgr.getUndoHistory();
undoHistory.forEach(item => {
const desc = item.description;
console.log(desc?.resolvedText || desc?.i18nKey || 'Unknown operation');
});
// Get redo history list
const redoHistory = undoMgr.getRedoHistory();
// Get step counts
const undoCount = undoMgr.getUndoCount();
const redoCount = undoMgr.getRedoCount();Best Practices
Undo Handling Inside Commands
class MyCommand {
async main() {
Engine.startUndoRecord('My Command');
try {
await this.doWork();
} catch (e) {
Engine.undo();
throw e;
} finally {
Engine.endUndoRecord();
}
}
}Undo for Batch Operations
// Add 1000 entities as one undo unit
Engine.startUndoRecord('Batch create');
for (let i = 0; i < 1000; i++) {
const entity = new CircleEnt([i * 10, 0], 5);
Engine.addEntities(entity);
}
Engine.endUndoRecord();
// Undo all 1000 entities at once
undoMgr.undo();