import { graphlib, layout } from 'dagre'; import { Graph } from '../../Graph'; import { RectangleRenderer } from '../../renderers/shapes/RectangleRenderer'; import { StaticLayout } from './StaticLayout'; type Alignment = 'UL' | 'UR' | 'DL' | 'DR' | undefined; type Direction = 'TB' | 'BT' | 'LR' | 'RL'; type Ranker = 'network-simplex' | 'tight-tree' | 'longest-path'; interface DagreOptions { align?: Alignment nodesep?: number rankdir?: Direction ranker?: Ranker ranksep?: number } class DagreLayout extends StaticLayout { apply (graph: Graph, options?: DagreOptions): void { const g = new graphlib.Graph({ multigraph: true }); g.setGraph(options ? options : { nodesep: 2 * RectangleRenderer.defaultWidth, ranksep: 2 * RectangleRenderer.defaultWidth, rankdir: 'BT' }); g.setDefaultEdgeLabel(() => ({})); graph.nodes().forEach(node => { g.setNode(node.id, { label: node.id, width: RectangleRenderer.defaultWidth, height: RectangleRenderer.defaultHeight }); }); graph.edges().forEach(edge => { g.setEdge(edge.source, edge.target); }); layout(g); const nodemap = new Map(graph.nodes().map(node => [node.id, node])); const props = g.graph(); const hw = props.width ? props.width / 2 : 0; const hh = props.height ? props.height / 2 : 0; g.nodes().forEach(id => { const node = nodemap.get(id); if (node) { const n = g.node(node.id); node.x = n.x - hw; node.y = n.y - hh; } }); } } export { DagreLayout }