唯杰地图 logo唯杰地图
VJMAP
EN

overview

vjcad/references/undo/overview.md 4.4 KB93 行
原文

本文回答: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