/** * connector-router — computes the actual routed path for draw.io connectors. * * Strategy: load the diagram XML into a real maxGraph Graph+GraphView instance * via graph-loader, which calls GraphView.validate() to compute all cell states * exactly as draw.io does at render time. Edge absolutePoints are taken directly * from those states — no synthetic geometry approximation. * * This is the only correct approach: draw.io's routing algorithms (especially * OrthConnector for edgeStyle=orthogonalEdgeStyle) depend on the full graph * state including parent container bounds, so they cannot be reproduced * accurately without loading the full model. */ import { loadGraphStates } from "../maxgraph-loader/graph-loader.js"; import type { Edge } from "../drawio-parser/parser.js"; // --------------------------------------------------------------------------- // Public API // --------------------------------------------------------------------------- export interface RoutedPoint { x: number; y: number; } /** * Build a map of edgeId → routed points for ALL edges in the diagram. * * Call this once per diagram page and reuse the result for all edges. * Using `routeAllEdges` is significantly more efficient than calling * `routeEdge` in a loop because it runs `GraphView.validate()` only once. * * @param graphModelXml - Raw XML for the page * @returns Map of edge id → array of canvas-absolute routed points */ export function routeAllEdges(graphModelXml: string): Map { const { edgeRoutes } = loadGraphStates(graphModelXml); const result = new Map(); for (const [id, route] of edgeRoutes) { result.set(id, route.points); } return result; } /** * Get routed points for a single edge from a pre-computed route map. * * For efficiency, pre-compute the map once using `routeAllEdges` and pass it here. * Falls back to a straight line between shape centers if the edge is not found. * * @param edge - The edge to route * @param routeMap - Pre-computed map from `routeAllEdges` * @param shapeMidpoints - Optional fallback: map of shapeId → {midX, midY} */ export function getEdgeRoute( edge: Edge, routeMap: Map, shapeMidpoints?: Map ): RoutedPoint[] { const pts = routeMap.get(edge.id); if (pts && pts.length >= 2) return pts; // Fallback: straight line using shape midpoints if (shapeMidpoints && edge.sourceId && edge.targetId) { const src = shapeMidpoints.get(edge.sourceId); const tgt = shapeMidpoints.get(edge.targetId); if (src && tgt) { return [{ x: src.midX, y: src.midY }, { x: tgt.midX, y: tgt.midY }]; } } return []; }