Render canvas connections overlay

This commit is contained in:
Codex
2026-05-11 22:11:44 +08:00
parent 9def9d8664
commit 5cbc0d213d

View File

@@ -11,6 +11,7 @@ import {
Position,
ReactFlow,
ReactFlowProvider,
ViewportPortal,
useReactFlow,
type Connection,
type Edge,
@@ -724,6 +725,84 @@ function clampViewport(viewport: FlowViewport, minZoom: number, maxZoom: number)
};
}
function buildConnectionPath(source: CanvasNode, target: CanvasNode) {
const sourceX = source.x + source.width + 8;
const sourceY = source.y + source.height / 2;
const targetX = target.x - 8;
const targetY = target.y + target.height / 2;
const distance = Math.max(80, Math.abs(targetX - sourceX) * 0.45);
return `M ${sourceX} ${sourceY} C ${sourceX + distance} ${sourceY}, ${targetX - distance} ${targetY}, ${targetX} ${targetY}`;
}
function CanvasConnectionOverlay({
nodes,
connections,
edgeStroke,
edgeZIndex,
}: {
nodes: CanvasNode[];
connections: CanvasConnection[];
edgeStroke: string;
edgeZIndex: number;
}) {
const nodeMap = useMemo(() => new Map(nodes.map(node => [node.id, node])), [nodes]);
const visibleConnections = connections
.map(connection => {
const source = nodeMap.get(connection.sourceNodeId);
const target = nodeMap.get(connection.targetNodeId);
return source && target ? { connection, source, target } : null;
})
.filter((item): item is { connection: CanvasConnection; source: CanvasNode; target: CanvasNode } => !!item);
if (visibleConnections.length === 0) return null;
return (
<ViewportPortal>
<svg
className="canvas-connection-overlay"
style={{
position: 'absolute',
left: 0,
top: 0,
width: 1,
height: 1,
overflow: 'visible',
pointerEvents: 'none',
zIndex: edgeZIndex,
}}
aria-hidden="true"
>
<defs>
<marker
id="canvas-connection-arrow"
markerWidth="12"
markerHeight="12"
refX="10"
refY="6"
orient="auto"
markerUnits="strokeWidth"
>
<path d="M 2 2 L 10 6 L 2 10 z" fill={edgeStroke} />
</marker>
</defs>
{visibleConnections.map(({ connection, source, target }) => (
<path
key={connection.id}
d={buildConnectionPath(source, target)}
fill="none"
stroke={edgeStroke}
strokeWidth={3}
strokeLinecap="round"
strokeLinejoin="round"
markerEnd="url(#canvas-connection-arrow)"
opacity={0.95}
/>
))}
</svg>
</ViewportPortal>
);
}
function FlowCanvasInner({
nodes,
connections,
@@ -1020,6 +1099,12 @@ function FlowCanvasInner({
>
<Background gap={20} size={1.15} color={dotColor} />
<Background gap={100} size={1.8} color={dotAccentColor} />
<CanvasConnectionOverlay
nodes={nodes}
connections={connections}
edgeStroke={edgeStroke}
edgeZIndex={edgeZIndex}
/>
<style jsx global>{`
.canvas-flow .react-flow__edges {
z-index: ${edgeZIndex};