feat: add dagre layout utility for React Flow node positioning
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
44
frontend/src/lib/dagreLayout.ts
Normal file
44
frontend/src/lib/dagreLayout.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import dagre from '@dagrejs/dagre'
|
||||
import type { Node, Edge } from '@xyflow/react'
|
||||
|
||||
const NODE_WIDTH = 280
|
||||
const DEFAULT_NODE_HEIGHT = 100
|
||||
|
||||
interface LayoutOptions {
|
||||
direction?: 'TB' | 'LR'
|
||||
rankSep?: number
|
||||
nodeSep?: number
|
||||
}
|
||||
|
||||
export function getLayoutedElements(
|
||||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
options: LayoutOptions = {}
|
||||
): Node[] {
|
||||
const { direction = 'TB', rankSep = 100, nodeSep = 40 } = options
|
||||
|
||||
const g = new dagre.graphlib.Graph()
|
||||
g.setDefaultEdgeLabel(() => ({}))
|
||||
g.setGraph({ rankdir: direction, ranksep: rankSep, nodesep: nodeSep })
|
||||
|
||||
nodes.forEach((node) => {
|
||||
const height = node.measured?.height ?? node.data?.estimatedHeight ?? DEFAULT_NODE_HEIGHT
|
||||
g.setNode(node.id, { width: NODE_WIDTH, height })
|
||||
})
|
||||
|
||||
edges.forEach((edge) => {
|
||||
g.setEdge(edge.source, edge.target)
|
||||
})
|
||||
|
||||
dagre.layout(g)
|
||||
|
||||
return nodes.map((node) => {
|
||||
const dagreNode = g.node(node.id)
|
||||
// dagre gives center positions — convert to top-left for React Flow
|
||||
const x = dagreNode.x - NODE_WIDTH / 2
|
||||
const y = dagreNode.y - (dagreNode.height ?? DEFAULT_NODE_HEIGHT) / 2
|
||||
return { ...node, position: { x, y } }
|
||||
})
|
||||
}
|
||||
|
||||
export { NODE_WIDTH, DEFAULT_NODE_HEIGHT }
|
||||
Reference in New Issue
Block a user