diff
本文回答:文档变更对比 =
DiffUtils.diff(oldJson, newState)返回IDiffResult,包含summary.{addedEntities, deletedEntities, modifiedEntities}和allItems[].{changeType, label, description}。可视化用getDiffPanel().setDiffResult(result); panel.show()。
一、最小用法
import { DiffUtils, getDiffPanel } from 'vjcad';
// 1. 拍快照
const oldState = Engine.currentDoc.toDb();
const oldJson = JSON.stringify(oldState);
// 2. 执行修改 ...
// 3. 计算差异
const newState = Engine.currentDoc.toDb();
const result = await DiffUtils.diff(oldJson, newState);
if (result.hasChanges) {
const s = result.summary;
console.log(`+${s.addedEntities} 新增, -${s.deletedEntities} 删除, ~${s.modifiedEntities} 修改`);
result.allItems.forEach(item => {
console.log(`[${item.changeType}] ${item.label} - ${item.description}`);
});
// 可视化
const panel = getDiffPanel();
panel.setDiffResult(result);
panel.show();
}
MCP 参考:vjcad/example/file/10diff.js。
二、IDiffResult 结构
| 字段 | 说明 |
|---|---|
hasChanges |
是否有变更 |
summary.addedEntities |
新增实体数 |
summary.deletedEntities |
删除实体数 |
summary.modifiedEntities |
修改实体数 |
allItems |
所有变更项数组 |
allItems[].changeType |
变更类型:'added' | 'deleted' | 'modified' |
allItems[].label |
项目标签 |
allItems[].description |
描述(modified 项为变更属性路径列表) |
summary.addedLayers / deletedLayers / modifiedLayers |
图层增 / 删 / 改数 |
summary.modifiedTextStyles / modifiedDimStyles / modifiedDocEnv |
文字样式 / 标注样式 / 文档环境变量改动数 |
allItems[].category |
'entity' | 'layer' | 'textStyle' | 'dimStyle' | 'docEnv' |
allItems[].key / entityId / blockName |
唯一键 / 实体 id(可用于定位)/ 所在块名 |
allItems[].changes |
modified 项的属性变更 [{path, oldValue, newValue}] |
"修改"的判定:实体在新旧快照里都存在时,只有新快照里带
_modified标记(entity.setModified()会置位,toDb()输出_modified: true)的实体才会深比较属性,有差异才计入modifiedEntities。直接改字段不调setModified()的实体不会被识别为修改;SAVESERVER成功后会清掉这些标记。
MCP 参考:vjcad/example/file/10diff.js(类型 IDiffSummary / IDiffListItem)。
与原始快照对比的快捷方法
// 对比当前文档与打开时的基准(serverSource.originalJsonCompressed)
const r = await DiffUtils.diffCurrentDoc(); // 没有基准(本地新图 / 未 setOriginalJson)时返回 null
if (r?.hasChanges) getDiffPanel().setDiffResult(r);
三、典型场景
// 模式 1:审计模式 — 一次性对比快照
const baseline = JSON.stringify(Engine.currentDoc.toDb());
// ... 用户操作 ...
const result = await DiffUtils.diff(baseline, Engine.currentDoc.toDb());
// 模式 2:保存前预览
const original = await Engine.currentDoc.getOriginalJson();
const current = JSON.stringify(Engine.currentDoc.toDb());
const r = await DiffUtils.diff(original, JSON.parse(current));
if (r.summary.deletedEntities > 100) {
alert('删除超过 100 个实体,请确认!');
}
MCP 参考:vjcad/example/file/10diff.js。
四、与服务端增量保存的关系
SAVESERVER 的增量保存内部就是用 originalJson ↔ currentJson 算 diff(详见 server)。DiffUtils.diff 让你能在本地预览同样的变更集,做以下事情:
- 显示 "本次保存的变更" 给用户确认
- 实现"撤销到某一历史"的可视化对比
- 多分支合并前预览冲突点
反例
- 拿
JSON.stringify(toDb()) === JSON.stringify(toDb())比较:实体顺序、引用、序列化精度都可能造成误判,用DiffUtils.diff而非字符串比较。 - 频繁 diff 大图纸(每秒一次):性能问题,建议节流(throttle)到 1~5s。
- 语义:两个快照之间"先 addEntities 再 eraseEntities"的实体净零——既不进
addedEntities也不进deletedEntities(diff 按最终状态对比,不是操作日志)。
参考(官方文档 MCP)
- 文档:
vjcad/doc/file/file-operations.md、vjcad/doc/file/index.md - 示例:
vjcad/example/file/10diff.js