feat(canvas): 条件读取与历史 - 减少画布同步传输并校准版本

This commit is contained in:
ddcat666
2026-09-29 08:26:29 +08:00
parent bcccddb4e9
commit 6ad1adc197
17 changed files with 783 additions and 25 deletions

View File

@@ -12,11 +12,30 @@ export function sameCanvasContent(left: CanvasProject | undefined, right: Canvas
if (!left || !right) return false;
const a = canvasContentSnapshot(left) as Record<string, unknown>;
const b = canvasContentSnapshot(right) as Record<string, unknown>;
return [...new Set([...Object.keys(a), ...Object.keys(b)])].every((key) => a[key] === b[key] || canonicalize(a[key]) === canonicalize(b[key]));
return [...new Set([...Object.keys(a), ...Object.keys(b)])].every((key) => {
if (a[key] === b[key]) return true;
if ((key === "nodes" || key === "connections") && Array.isArray(a[key]) && Array.isArray(b[key])) {
const leftItems = a[key] as unknown[];
const rightItems = b[key] as unknown[];
return leftItems.length === rightItems.length && leftItems.every((item, index) => item === rightItems[index] || canonicalValue(item) === canonicalValue(rightItems[index]));
}
return canonicalValue(a[key]) === canonicalValue(b[key]);
});
}
type ContentSnapshot = ReturnType<typeof canvasContentSnapshot>;
const contentHashes = new WeakMap<CanvasProject["nodes"], { content: ContentSnapshot; hash: Promise<string> }>();
// Canvas content trees are immutable, so unchanged node objects can reuse their serialized comparison value.
const canonicalValueCache = new WeakMap<object, string>();
function canonicalValue(value: unknown) {
if (!value || typeof value !== "object") return canonicalize(value);
const cached = canonicalValueCache.get(value);
if (cached) return cached;
const serialized = canonicalize(value);
canonicalValueCache.set(value, serialized);
return serialized;
}
// Store updates are immutable. Reuse a hash across viewport/revision-only copies;
// any content field/reference change invalidates it. Weak keys bound its lifetime.