Implementation:TobikoData Sqlmesh DagreLayout
| Knowledge Sources | |
|---|---|
| Domains | Web_UI, Lineage_Visualization |
| Last Updated | 2026-02-07 20:00 GMT |
Overview
Graph layout algorithm implementation using Dagre library to automatically position lineage nodes in hierarchical left-to-right arrangement.
Description
buildLayout function uses the Dagre graph library to calculate optimal node positions for lineage visualizations. It creates a directed graph with specific layout configuration: left-to-right direction (rankdir: 'LR'), 12px node separation, 48px rank separation, and longest-path ranking algorithm. The function processes all edges first to establish graph structure, then adds nodes with their dimensions (width and height). After Dagre calculates positions, it updates the nodes map with centered coordinates by adjusting for half-width and half-height offsets. The shouldReuseExistingPosition parameter allows preserving manually adjusted node positions when true, only updating nodes with default (0, 0) positions.
Usage
Use this function when initializing lineage graph layouts or when recalculating positions after graph structure changes. It provides automatic hierarchical positioning that can be overridden by user interactions while maintaining sensible defaults.
Code Reference
Source Location
- Repository: TobikoData_Sqlmesh
- File: web/common/src/components/Lineage/layout/dagreLayout.ts
Signature
export function buildLayout<
TNodeData extends LineageNodeData = LineageNodeData,
TEdgeData extends LineageEdgeData = LineageEdgeData,
TEdgeID extends string = EdgeId,
TSourceID extends string = NodeId,
TTargetID extends string = NodeId,
TSourceHandleID extends string = PortId,
TTargetHandleID extends string = PortId,
>({
edges,
nodesMap,
shouldReuseExistingPosition = true,
}: {
edges: LineageEdge<
TEdgeData,
TEdgeID,
TSourceID,
TTargetID,
TSourceHandleID,
TTargetHandleID
>[]
nodesMap: LineageNodesMap<TNodeData>
shouldReuseExistingPosition?: boolean
}): LineageNodesMap<TNodeData>
Import
import { buildLayout } from '@sqlmesh-common/components/Lineage/layout/dagreLayout'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| edges | LineageEdge[] | Yes | Array of graph edges defining connections |
| nodesMap | LineageNodesMap | Yes | Map of nodes by ID with dimensions and positions |
| shouldReuseExistingPosition | boolean | No | Preserve manually adjusted positions (default: true) |
Outputs
| Name | Type | Description |
|---|---|---|
| nodesMap | LineageNodesMap | Updated nodes map with calculated positions |
Usage Examples
import { buildLayout } from '@sqlmesh-common/components/Lineage/layout/dagreLayout'
// Initial layout calculation
const nodesMap = {
model1: {
id: 'model1',
width: 300,
height: 100,
position: { x: 0, y: 0 },
data: { name: 'Model 1' }
},
model2: {
id: 'model2',
width: 300,
height: 100,
position: { x: 0, y: 0 },
data: { name: 'Model 2' }
}
}
const edges = [
{
id: 'e1-2',
source: 'model1',
target: 'model2',
type: 'edge'
}
]
// Calculate positions
const layoutedNodes = buildLayout({
edges,
nodesMap,
shouldReuseExistingPosition: true
})
// layoutedNodes will have calculated x, y positions:
// model1: { position: { x: 0, y: 0 } }
// model2: { position: { x: 348, y: 0 } } // 300 width + 48 ranksep
// Recalculate after user moved a node
const userMovedNodesMap = {
...layoutedNodes,
model1: {
...layoutedNodes.model1,
position: { x: 100, y: 50 } // User dragged this node
}
}
// With shouldReuseExistingPosition=true, model1 keeps user position
const updatedLayout = buildLayout({
edges,
nodesMap: userMovedNodesMap,
shouldReuseExistingPosition: true
})
// model1.position remains { x: 100, y: 50 }
// Force recalculation of all positions
const recalculatedLayout = buildLayout({
edges,
nodesMap: userMovedNodesMap,
shouldReuseExistingPosition: false
})
// All nodes get new calculated positions