overview
本文回答:vjcad 撤销系统由
Engine.undoManager(UndoManager)管理;推荐用Engine.startUndoRecord('描述') / endUndoRecord()或undoMgr.start_undoMark / end_undoMark包裹一组操作;底层用*_undoMark系列方法记录单步(added_undoMark / erased_undoMark / moved_undoMark / rotate_undoMark / scaled_undoMark / mirrored_undoMark / modEntity_undoMark等)。Engine.addEntities / eraseEntities等封装方法自动记录撤销。
一、按子主题挑
| 想做的 | 子主题 |
|---|---|
| 基本 undo / redo / 状态查询 | basic |
| 撤销标记(按操作类型分别记录) | mark |
撤销组(startUndoRecord 等批量包裹) |
group |
操作描述(UndoDescriptor、历史查询、UI 显示) |
description |
二、心智模型
┌────────────────────────────────────────────────────┐
│ Engine.undoManager (UndoManager) │
│ .canUndo() / .canRedo() │
│ .undo() / .redo() │
│ .start_undoMark(description?) │
│ .end_undoMark() │
│ .added_undoMark(entities) │
│ .erased_undoMark(entities) │
│ .moved_undoMark(entities, from, to) │
│ .rotate_undoMark(entities, base, angle) │
│ .scaled_undoMark(entities, base, scale) │
│ .mirrored_undoMark(entities, p1, p2) │
│ .modEntity_undoMark(entity) │
│ .getUndoHistory() / .getRedoHistory() │
│ .undoSteps(n|name) / .redoSteps(n|name) │
│ .rollbackLastGroup() │
└────────────────────────────────────────────────────┘
↑ ↑
└──── 推荐:Engine.startUndoRecord('描述') / endUndoRecord()
(嵌套安全,等价 start/end_undoMark + 计数)
MCP 参考:vjcad/doc/undo/index.md、vjcad/doc/undo/undo-redo.md。
三、最小用法
const undoMgr = Engine.undoManager;
undoMgr.undo(); // 撤销(只改数据,不刷新画布,之后 Engine.regen())
undoMgr.redo(); // 重做(同上)
undoMgr.canUndo(); // 是否可撤销
undoMgr.canRedo(); // 是否可重做
// 推荐:用撤销组包住一组操作
Engine.startUndoRecord('批量创建');
try {
for (let i = 0; i < 10; i++) {
Engine.addEntities(new CircleEnt([i*20, 0], 5));
}
} finally {
Engine.endUndoRecord();
}
// 一次 undo 全部回滚
MCP 参考:vjcad/doc/undo/index.md、vjcad/doc/undo/undo-redo.md。
四、Engine.addEntities / eraseEntities 自动撤销
| 封装方法 | 是否自动撤销 |
|---|---|
Engine.addEntities(...) |
✅ |
Engine.eraseEntities(...) |
✅ |
Engine.setEntityColor(...) / setEntityLayer(...) |
✅ |
Engine.markModified(ent) 后改属性 |
视使用方式(手动记录) |
直接 Engine.pcanvas.addEntity(...) |
❌ 需 added_undoMark([...]) |
MCP 参考:vjcad/doc/undo/undo-redo.md。
五、startUndoRecord vs start_undoMark
Engine.startUndoRecord |
undoMgr.start_undoMark |
|
|---|---|---|
| 嵌套 | 安全(引用计数,仅最外层生效) | 不安全(每次都 push START) |
| 适用 | 命令中(命令可能互相调用) | 确定不嵌套的 UI 代码 |
| 推荐 | 不确定时优先 | 底层控制 / 性能敏感 |
详见 group。
差异:vjcad 的 undo/redo 恢复同一对象引用——
eraseEntities只是软删(isAlive=false,实体留在currentSpace.items),undo 后置回true,持有旧引用的代码继续有效。这与 vjmapext 的"克隆重建"语义相反;注意getEntities()不过滤死实体(见 selection/selection-api)。
MCP 参考:vjcad/doc/undo/undo-redo.md。
参考(官方文档 MCP)
- 文档:
vjcad/doc/undo/index.md、vjcad/doc/undo/undo-redo.md - 示例:
vjcad/example/undo/01basic.js~04description.js