Reuse canvas scenes across viewport and interaction metadata changes
This commit is contained in:
@@ -9,7 +9,7 @@ import { CanvasProvider, CanvasRendererCommandsContext, type CanvasRendererComma
|
||||
import { defaultCanvasRenderers } from "./canvas-renderers";
|
||||
import type { Data, ElementRecord, Geometry, Id, Json, Result } from "@/lib/canvas-core/types";
|
||||
import { equal } from "@/lib/canvas-core/values";
|
||||
import {createGeometryProjectionCache} from "@/lib/canvas-bindings/geometry-cache";
|
||||
import {createSceneProjection} from "@/lib/canvas-bindings/scene-projection";
|
||||
import {createConnectionPaintIndex} from "@/lib/canvas-bindings/connection-paint";
|
||||
import {nativeRectVisible} from "@/lib/canvas-bindings/visibility";
|
||||
import {createOverlayIndex} from "@/lib/canvas-bindings/overlays";
|
||||
@@ -23,7 +23,7 @@ import {createLoadingRendererCatalog} from '@/lib/canvas-bindings/renderers';
|
||||
import { createProjectionCache } from "@/lib/canvas-bindings/projection-cache";
|
||||
import { createResourceView, type ResourceViewSource } from "@/lib/canvas-bindings/resource-view";
|
||||
import { ancestors, commonCanvas } from "@/lib/canvas-core/document";
|
||||
import { projectCanvas, toLocal, transformPath, type ProjectionNode } from "@/lib/canvas-bindings/projection";
|
||||
import { toLocal, transformPath, type ProjectionNode } from "@/lib/canvas-bindings/projection";
|
||||
import type { ProjectEngine } from "@/lib/canvas-runtime/workspace";
|
||||
import { errorText } from "@/lib/api";
|
||||
import { IconButton } from "@/components/ui/icon-button";
|
||||
@@ -65,20 +65,21 @@ function CanvasView({ engine, board, viewId, renderers,fitLoading=true }: { engi
|
||||
const pointerStart = useRef<{ x: number; y: number;pointerId?:number } | null>(null), drag = useRef<{ token: number;pointerId?:number; start: { x: number; y: number }; positions: Map<Id, { x: number; y: number }> } | null>(null);
|
||||
const projectionCache = useRef<ReturnType<typeof createProjectionCache> | null>(null);
|
||||
projectionCache.current ??= createProjectionCache();
|
||||
const geometryCache=useRef<ReturnType<typeof createGeometryProjectionCache>|null>(null);geometryCache.current??=createGeometryProjectionCache();
|
||||
const sceneCache=useMemo(()=>createSceneProjection(),[engine,viewId]);
|
||||
const measurements = useRef(new Map<Id, { width: number; height: number; measured: { width: number; height: number } }>());
|
||||
const imageInput = useRef<HTMLInputElement>(null), groups = useRef(new Map<Id,{incarnation:number;groupId:Id}>());
|
||||
useEffect(()=>{for(const [id,group]of groups.current)if(root.document.elements.get(id)?.incarnation!==group.incarnation)groups.current.delete(id);},[root.document]);
|
||||
const catalog=useMemo(()=>loading?createLoadingRendererCatalog(engine.editor.registry,renderers.catalog):renderers.catalog,[engine,renderers,!!loading]);
|
||||
const scene=sceneCache.project(engine,root.document,view,sessions,engine.editor.registry,catalog,engine.editor.getQueries(root.document));
|
||||
const projection = useMemo(() => {
|
||||
const result = projectCanvas(root.document, view.canvasId, engine.editor.registry, view.selection, engine.sessions.effectiveGeometry, sessions.connectionGesture,catalog,{queries:engine.editor.getQueries(root.document),geometry:geometryCache.current!,owner:engine});
|
||||
const result = scene;
|
||||
// Preserve renderer measurements across metadata/preview updates. Dropping them
|
||||
// makes React Flow discard handle bounds and unmount active edge controls.
|
||||
const visibleIds = new Set(result.nodes.map(node => node.id));
|
||||
for (const id of measurements.current.keys()) if (!visibleIds.has(id)) measurements.current.delete(id);
|
||||
for (const node of result.nodes) { const cached = measurements.current.get(node.id); if (cached && cached.width === node.width && cached.height === node.height && projectionCache.current!.canRetainMeasurement(engine,root.document,view.canvasId,node)) node.measured = cached.measured; }
|
||||
return projectionCache.current!.reuse(engine,root.document,view.canvasId,result);
|
||||
}, [engine, root.document, sessions, view,renderers,catalog]);
|
||||
}, [engine, root.document, scene,view.canvasId]);
|
||||
const surface=useRef<HTMLDivElement>(null),overlays=useMemo(()=>createOverlayIndex(viewId),[engine,viewId]);
|
||||
const overlayScope=useMemo(()=>({index:overlays,engine}),[overlays,engine]);
|
||||
const overlaySnapshot=useSyncExternalStore(overlays.subscribe,overlays.getSnapshot,overlays.getSnapshot);
|
||||
|
||||
Reference in New Issue
Block a user