Cache connection paint by immutable geometry inputs and measured anchors

This commit is contained in:
2026-11-09 18:55:21 +08:00
parent 6c4ab46413
commit 43c74a1485
5 changed files with 43 additions and 14 deletions
@@ -10,8 +10,7 @@ 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 {createPaintIndex} from "@/lib/canvas-bindings/paint-index";
import {projectedConnectionPaintOverflow} from "@/lib/canvas-bindings/connection-paint";
import {createConnectionPaintIndex} from "@/lib/canvas-bindings/connection-paint";
import {nativeRectVisible} from "@/lib/canvas-bindings/visibility";
import {createOverlayIndex} from "@/lib/canvas-bindings/overlays";
import {CanvasOverlays} from "./canvas-overlays";
@@ -92,8 +91,9 @@ function CanvasView({ engine, board, viewId, renderers,fitLoading=true }: { engi
const overlayVisible=!!overlaySnapshot.length&&(!surfaceBounds||overlays.visible(surfaceBounds,target=>root.document.elements.get(target.id)?.incarnation===target.incarnation).some(entry=>!nativeVisible(entry.target.id)));
const paintVisible=!surfaceWidth||!surfaceHeight||paint.unknown.some(id=>!nativeVisible(id))||[...paint.query(sceneViewport)].some(id=>!nativeVisible(id));
const nativeNodes=useStore(state=>state.nodes);
const connectionPaint=useMemo(()=>{const result=projectedConnectionPaintOverflow(projection,engine.editor.registry,{anchor:(node,handle,end,edge)=>{const measured=flow.getInternalNode(node.id);return node.data.__headlessRecord||edge.type==='unsupported'?measuredConnector(measured,handle,end):compatConnector(node,handle,end==='source'?'right':'left');}}),index=createPaintIndex();index.sync(result.regions);return{index,unknown:result.unknown};},[projection,engine,flow,nativeNodes]);
const connectionPaintVisible=connectionPaint.unknown.length>0||!surfaceWidth||!surfaceHeight||connectionPaint.index.query({x:-viewport.x/viewport.zoom,y:-viewport.y/viewport.zoom,width:surfaceWidth/viewport.zoom,height:surfaceHeight/viewport.zoom}).size>0;
const connectionPaintCache=useMemo(()=>createConnectionPaintIndex(),[engine,view.canvasId]);
const connectionPaint=useMemo(()=>connectionPaintCache.sync(projection,engine.editor.registry,{anchor:(node,handle,end,edge)=>{const measured=flow.getInternalNode(node.id);return node.data.__headlessRecord||edge.type==='unsupported'?measuredConnector(measured,handle,end):compatConnector(node,handle,end==='source'?'right':'left');}}),[connectionPaintCache,projection,engine,flow,nativeNodes]);
const connectionPaintVisible=connectionPaint.unknown.length>0||!surfaceWidth||!surfaceHeight||connectionPaint.query({x:-viewport.x/viewport.zoom,y:-viewport.y/viewport.zoom,width:surfaceWidth/viewport.zoom,height:surfaceHeight/viewport.zoom}).size>0;
const nodeTypes=useMemo(()=>({...renderers.nodeTypes,unsupported:UnsupportedNode}),[renderers]),edgeTypes=useMemo(()=>({...renderers.edgeTypes,unsupported:UnsupportedEdge}),[renderers]);
const current = useRef({ root, projection, view, engine, sessions }); current.current = { root, projection, view, engine, sessions };
const report = useCallback((result: Result | { enabled: boolean; code?: string }) => {