Tree Layout and Line Options
This example turns a fixed tree dataset into a live tuning playground for relation-graph. Users can change tree direction and spacing, batch-restyle existing lines, switch canvas interaction modes, and export the current view as an image without rebuilding the data.
Tune a Tree Graph with Live Layout and Line Controls
What This Example Builds
This example builds a full-height tree-layout playground around one prepared hierarchy. The canvas shows a compact monochrome blue tree with boxed line labels, a built-in toolbar at the bottom center, and a floating white control window above the graph.
Users can switch the tree orientation, change horizontal and vertical spacing, restyle every rendered line, move line-label offsets, change wheel and drag behavior, and export the current canvas as an image. The main point is not data editing. It is live presentation tuning on an already loaded graph instance.
How the Data Is Organized
The graph data is declared inline as one RGJsonData object with a rootId, a flat nodes array, and a flat lines array. Each node uses a simple id and text, and each line uses id, text, from, and to. That keeps the sample focused on layout and styling behavior instead of domain-specific content.
There is no preprocessing step before setJsonData(). initializeGraph() loads the prepared tree directly, then centers and fits it. A separate React state object stores the control values that drive the runtime behavior: layoutFrom, rangeHorizontal, rangeVertical, lineShape, junctionPoint, lineRadius, textOffsetX, and textOffsetY.
In a real project, the same structure could represent an org chart, a product category tree, a dependency tree, or a navigation hierarchy. The control-state object could come from user preferences, a preset selector, or an admin tuning panel.
How relation-graph Is Used
index.tsx wraps the demo in RGProvider, so child components can access the active graph instance through hooks. RelationGraph is rendered with graph-level defaults that make the example visually stable: a tree layout, a shared blue color for nodes and lines, 60 by 60 node boxes, and a horizontal toolbar positioned at the bottom center.
The main example component uses RGHooks.useGraphInstance() for all graph work. It calls setJsonData() once during initialization, then uses updateOptions({ layout }) plus doLayout() whenever the direction or spacing controls change. For edge tuning, it reads the current rendered edges with getLines() and applies updateLine() to each one, so line geometry and label placement change without rebuilding the dataset.
The floating utility shell comes from DraggableWindow. Inside that shared helper, CanvasSettingsPanel uses RGHooks.useGraphStore() to read the active dragEventAction and wheelEventAction, then uses setOptions() to switch those behaviors at runtime. The same panel calls prepareForImageGeneration() and restoreAfterImageGeneration() around DOM-to-image export.
This example does not define node, line, canvas, or viewport slots. It relies on the default relation-graph renderers and customizes them through SCSS overrides. The stylesheet turns node labels white and bold, and it gives line labels a white background with a blue border so they read as detached chips.
Key Interactions
- A direction selector forwards
left,right,top, orbottomintolayout.from, then reruns the tree layout. - Two range sliders map directly to
treeNodeGapHandtreeNodeGapV, so users can widen or compress the hierarchy without changing the data. - A line-shape selector changes every current edge together. When an orthogonal shape is selected, a radius slider appears so corner rounding can be tuned.
- A junction-point selector updates both ends of every line, and two offset sliders reposition the line labels.
- The floating window can be dragged, minimized, and switched into a settings overlay.
- The settings overlay changes wheel behavior between scroll, zoom, and none; changes canvas drag behavior between selection, move, and none; and exports the graph as an image.
Key Code Fragments
This block establishes a fixed tree-layout baseline and a consistent visual palette before any runtime tuning starts.
const graphOptions: RGOptions = {
defaultLineColor: '#2E74B5',
defaultLineWidth: 3,
defaultNodeColor: '#2E74B5',
defaultNodeWidth: 60,
defaultNodeHeight: 60,
toolBarDirection: 'h',
toolBarPositionH: 'center',
toolBarPositionV: 'bottom',
layout: {
layoutName: 'tree'
}
};
This relayout path shows how React state is translated into live tree options and then applied to the current graph instance.
graphInstance.updateOptions({
layout: {
layoutName: 'tree',
from: myTreeGraphOptions.layoutFrom,
treeNodeGapH: myTreeGraphOptions.rangeHorizontal,
treeNodeGapV: myTreeGraphOptions.rangeVertical
}
});
await graphInstance.doLayout();
graphInstance.moveToCenter();
graphInstance.zoomToFit();
This loop is the core batch-restyling pattern: it reads the rendered edges and mutates each one in place.
graphInstance.getLines().forEach((line) => {
graphInstance.updateLine(line, {
lineShape: myTreeGraphOptions.lineShape,
lineRadius: myTreeGraphOptions.lineRadius,
fromJunctionPoint: myTreeGraphOptions.junctionPoint,
toJunctionPoint: myTreeGraphOptions.junctionPoint,
textOffsetX: myTreeGraphOptions.textOffsetX,
textOffsetY: myTreeGraphOptions.textOffsetY,
placeText: (myTreeGraphOptions.lineShape === RGLineShape.StandardOrthogonal) ? 'end' : undefined
});
});
This selector makes the example a four-way tree-orientation playground instead of a single-direction viewer.
<SimpleUISelect
data={[
{ value: 'left', text: 'Left to Right' },
{ value: 'right', text: 'Right to Left' },
{ value: 'top', text: 'Top to Bottom' },
{ value: 'bottom', text: 'Bottom to Top' }
]}
currentValue={myOptions.layoutFrom}
onChange={(newValue: string) => { myOptionsUpdater({ ...myOptions, layoutFrom: newValue }); }}
/>
This shared helper shows that image export is implemented through relation-graph’s preparation and restoration APIs rather than a raw screenshot call alone.
const canvasDom = await graphInstance.prepareForImageGeneration();
let graphBackgroundColor = graphInstance.getOptions().backgroundColor;
if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {
graphBackgroundColor = '#ffffff';
}
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
backgroundColor: graphBackgroundColor
});
if (imageBlob) {
downloadBlob(imageBlob, 'my-image-name');
}
await graphInstance.restoreAfterImageGeneration();
What Makes This Example Distinct
The comparison data places this example near tree-distance, layout-tree, and custom-line-style, but it emphasizes a different combination of controls. Its strongest distinguishing trait is that one floating panel controls both tree relayout parameters and graph-wide line geometry on the same static dataset.
- Compared with
tree-distance, this example goes beyond spacing-only control by adding four-way orientation switching and batch edge-geometry updates. - Compared with
layout-tree, it behaves less like a curated preset switcher and more like a continuous parameter workbench. - Compared with
custom-line-style, it focuses on relation-graph line properties such as shape, junction points, corner radius, and label offsets, not on CSS skin families. - Compared with
layout-folder2, it removes domain-specific node cards and folder-layout semantics so the reusable lesson stays centered on tree and line APIs.
The shared draggable window, wheel-mode switching, drag-mode switching, and image export are useful supporting features, but the comparison record does not support treating those utilities as the unique identity of this example. The distinct value is the combined runtime control over tree direction, spacing, and edge geometry.
Where Else This Pattern Applies
- An org-chart viewer that lets users tune hierarchy density and connector style before exporting presentation screenshots.
- A taxonomy or category browser where different teams prefer different tree directions and spacing presets on the same data.
- A dependency or workflow tree inspector that needs live edge-label repositioning to reduce overlap during debugging.
- An internal playground for testing relation-graph layout parameters on representative sample data before hard-coding product defaults.