Lineage canvas
Pan-and-zoom lineage graph with keyboard navigation and a minimap.
Guidance
The lineage canvas draws how data moves between assets: HTML nodes on one transformed layer, SVG edges beneath, on survey paper with a 16px dot grid that pans and zooms with the content. Layout is dagre, left to right (mirrored in right-to-left documents), run in a worker for large graphs. Pan and zoom use d3-zoom: drag, wheel and pinch.
Edges never rely on colour alone: declared edges are solid ink-3, observed edges dashed moss,
mixed edges solid with a dashed overlay, and cycle edges dotted ochre ending in a "Returns to"
node rather than doubling back. Edge chips (origin and run count, or the job) appear on hover or
focus, or always with show-edge-labels. Agents that looked an asset up are grouped into one
agent cluster that expands. Nodes with neighbours beyond the depth show a "+3 upstream" handle.
Keyboard: the canvas is one tab stop (an application with aria-activedescendant). Right moves
downstream along an edge and Left upstream (flipped right to left), Up and Down move between assets
in the same column, Enter opens (mm-node-activate), Space selects, E steps through the focused
asset's edges (Delete removes one when editable), + and - zoom, 0 fits, F returns to the current
asset, and Escape leaves full screen. The minimap is a second tab stop: arrows pan, + and - zoom.
Performance: only nodes and edges in view plus a margin are rendered, panning moves one CSS transform, and below 40% zoom nodes become plain shapes. 2,000 nodes pan at display rate.
Full screen is in-page (fullscreen); making it deep-linkable is the app's job, from
mm-fullscreen-change.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
graph | LineageGraph | { nodes: [], edges: [] } | The lineage to draw: { nodes, edges, currentId }. Replace the object to update it. | |
depth | depth | number | 10 | How many steps from the current asset to draw. Default 10, as in the product. |
maxDepth | max-depth | number | 20 | Upper bound for the depth stepper. |
showObserved | show-observed | boolean | false | Draws observed edges (OpenLineage runs, agent lookups). Off by default so chatty agents don't crowd pipeline lineage. |
hideStructure | hide-structure | boolean | false | Hides CONTAINS edges (a database holds a table), which are most of many graphs but move no data. |
showEdgeLabels | show-edge-labels | boolean | false | Shows every edge chip, not only on hover and focus. |
fullscreen | fullscreen | boolean | false | In-page full screen. Escape leaves it. |
editable | editable | boolean | false | Offers "Add upstream", "Add downstream" and edge deletion. |
loading | loading | boolean | false | Shows the topographic loading field (after 200ms, for at least 400ms). |
error | error | string | '' | An error message. Shows the error state with "Try again". |
selected | selected | string | '' | Id of the selected asset. |
label | label | string | '' | Accessible name. Defaults to "Lineage of {current asset}". |
layoutModuleUrl | layout-module-url | string | '' | URL of the dagre ES module for the layout worker, e.g. import url from '@dagrejs/dagre?url' in Vite. Graphs over 300 nodes lay out off the main thread when this (or import.meta.resolve) works. |
hideMinimap | hide-minimap | boolean | false | |
hideLegend | hide-legend | boolean | false | |
layoutComplete | Promise<void> | Resolves when the current layout has been drawn. Useful in tests and before measuring. | ||
transform | MmLineageViewportDetail | The current pan and zoom. | ||
renderedNodeCount | number | Number of asset elements currently rendered (for performance checks). |
Methods
| Method | Description |
|---|---|
fit() | Fits the whole graph in view, clear of the legend, zoom controls and minimap. |
zoomIn() | Zooms in one step around the centre. |
zoomOut() | Zooms out one step around the centre. |
panBy() | Pans by a number of screen pixels. |
focusNode() | Moves keyboard focus to an asset and brings it into view. |
collapseGroups() | Collapses every expanded agent cluster. |
Events
| Event | Detail | Description |
|---|---|---|
mm-node-activate | CustomEvent<MmLineageActivateDetail> | An asset was clicked or Enter was pressed on it. Open the asset blade. |
mm-node-select | CustomEvent<MmLineageSelectDetail> | The selected asset changed (Space or click). |
mm-expand | CustomEvent<MmLineageExpandDetail> | A "+3 upstream" handle was used, or an agent cluster expanded or collapsed. |
mm-viewport-change | CustomEvent<MmLineageViewportDetail> | A pan or zoom ended. |
mm-fullscreen-change | CustomEvent<MmLineageFullscreenDetail> | Full screen was entered or left. |
mm-options-change | CustomEvent<MmLineageOptionsDetail> | Depth, Observed or Structure changed. |
mm-edge-delete | CustomEvent<MmLineageEdgeDeleteDetail> | Delete was asked for on an edge (editable only). The app confirms and removes it. |
mm-add-lineage | CustomEvent<MmLineageAddDetail> | "Add upstream" or "Add downstream" was pressed for the selected asset (editable only). |
mm-layout | CustomEvent<MmLineageLayoutDetail> | A layout finished. |
mm-retry | CustomEvent<Record<string, never>> | "Try again" was pressed in the error state. |
Slots
| Slot | Description |
|---|---|
actions | Extra toolbar actions, at the end of the toolbar before full screen. |
legend | Replaces the compact legend in the top corner. |
CSS parts
| Part | Description |
|---|---|
toolbar | The control bar. |
viewport | The pannable paper. |
minimap | The minimap. |
zoom-controls | The zoom buttons. |
CSS custom properties
| Property | Description |
|---|---|
--mm-lineage-height | Height when not full screen. Default 560px. |
Examples
Every state of mm-lineage-canvas in Storybook, with keyboard and screen reader tests.