唯杰地图 logo唯杰地图
VJMAP
EN

diff

vjcad/references/file/diff.md 4.4 KB102 行
原文

本文回答:文档变更对比 = 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