JavaScript is required

Load Tree from Hierarchical Data

This example shows how to pass a nested hierarchical RGJsonData object directly into relation-graph and render it as a left-to-right tree without manually authoring line records. It also demonstrates the standard provider-scoped initialization flow, plus shared viewer utilities for canvas mode changes and image export.

Load a Left-to-Right Tree Directly from Hierarchical Data

What This Example Builds

This example renders a small hierarchy as a left-to-right tree with rectangular nodes and orthogonal connectors. The page is mostly a full-height graph canvas with a floating description window above it. Users can inspect the prepared tree, drag or minimize the helper window, open canvas settings, and export an image, but the example does not add example-specific node editing or branch-control logic. Its main point is narrower: the hierarchy is authored as nested children arrays instead of a manually flattened node-and-line dataset.

How the Data Is Organized

The dataset is declared inline as one RGJsonData object with rootId, a nodes array, and recursive children fields under each parent node. The lines array is intentionally empty, so the component hands a hierarchical tree shape to relation-graph instead of explicit edge records.

There is no preprocessing before setJsonData(). The example relies on relation-graph to recognize the nested tree and flatten it internally for rendering. In real applications, the same shape can represent organization charts, folder trees, product categories, bill-of-material structures, or approval chains. The description inside the example also states an important tradeoff: when direct tree data is used in this form, each connector is not styled individually inside the input payload.

How relation-graph Is Used

The demo uses the standard React provider pattern: index.tsx wraps MyGraph in RGProvider, and MyGraph.tsx reads the active graph instance through RGHooks.useGraphInstance(). The graph options configure a tree layout, set the origin to the left, use treeNodeGapH = 150 and treeNodeGapV = 20, and keep the geometry plain with rectangular nodes, 100-pixel node width, orthogonal connectors, left-right junction points, and right-side expand-holder placement.

The graph instance API does most of the actual work. After mount, the component calls setJsonData() with the inline hierarchy, then moveToCenter() and zoomToFit() so the first render is already framed correctly. The only extra runtime utilities come from the shared DraggableWindow helper. That helper uses RGHooks.useGraphStore() to read the current canvas behavior, graphInstance.setOptions() to switch wheel and drag modes, and prepareForImageGeneration() plus restoreAfterImageGeneration() around a modern-screenshot capture flow.

There are no custom node, line, canvas, or viewport slots in this example, and there is no editing workflow. The SCSS file mainly contains empty selector scaffolding, so the final appearance stays close to relation-graph defaults rather than a custom skin.

Key Interactions

The first interaction is automatic rather than manual: the tree loads during useEffect() and the viewport immediately centers and fits to the content. After that, the graph behaves as a viewer.

The floating helper window is the main interactive overlay. Its title bar can be dragged, it can be minimized and restored, and its settings panel can change wheel behavior between scroll, zoom, and none, plus canvas drag behavior between selection, move, and none. The same panel can export the current graph as an image. The example does not add node click handlers, post-load expand or collapse rules, inline editing, or custom selection behavior of its own.

Key Code Fragments

This options block establishes the left-to-right tree geometry and the default node and line style.

const graphOptions: RGOptions = {
    debug: false,
    layout: {
        layoutName: 'tree',
        from: 'left',
        treeNodeGapH: 150,
        treeNodeGapV: 20,
    },
    defaultExpandHolderPosition: 'right',
    defaultNodeShape: RGNodeShape.rect,
    defaultNodeWidth: 100,
    defaultLineShape: RGLineShape.StandardOrthogonal,
};

This inline payload shows the core data-shape pattern: the hierarchy is written directly with nested children arrays.

const myJsonData: RGJsonData = {
    rootId: 'a',
    nodes: [
        {
            id: 'a', text: 'a', children: [
                {
                    id: 'b', text: 'b', children: [
                        {
                            id: 'b1', text: 'b1', children: [

This mount-time sequence hands the hierarchy to relation-graph and immediately fits the initial view.

await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();

useEffect(() => {
    initializeGraph();
}, []);

This settings row proves that the floating helper can change live canvas behavior through setOptions().

<SettingRow
    label="Wheel Event:"
    options={[
        { label: 'Scroll', value: 'scroll' },
        { label: 'Zoom', value: 'zoom' },
        { label: 'None', value: 'none' },
    ]}
    value={wheelMode}
    onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}
/>

This export flow prepares the graph canvas for capture, renders it with modern-screenshot, and then restores graph state.

const canvasDom = await graphInstance.prepareForImageGeneration();
let graphBackgroundColor = graphInstance.getOptions().backgroundColor;
if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {
    graphBackgroundColor = '#ffffff';
}
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
    backgroundColor: graphBackgroundColor
});
await graphInstance.restoreAfterImageGeneration();

What Makes This Example Distinct

Comparison data positions this example as a minimal baseline for direct hierarchical input. Its strongest distinguishing combination is a nested RGJsonData payload, an empty lines array, a plain left-to-right orthogonal tree, and almost no custom SCSS or slot rendering. The graph-specific logic also stays unusually narrow for a demo that still includes the shared floating utility window: one startup load sequence plus inherited viewer utilities.

Compared with tree-distance, this example is about proving the direct hierarchical-input path rather than comparing runtime spacing strategies. Compared with expand-gradually and open-by-level, it keeps the hierarchy passively visible after initialization instead of layering branch-state logic, click-to-expand behavior, or depth resets on top of a flat nodes-and-lines dataset. Compared with line-style1, it removes explicit line records and custom node visuals, which makes it a cleaner starting point when the question is simply whether nested business data can be rendered as a tree without extra transformation first.

Where Else This Pattern Applies

  • Rendering an organization chart directly from a nested API response before introducing custom cards or editing.
  • Showing folder structures, product categories, or bill-of-material trees when the source data is already hierarchical.
  • Validating a left-to-right tree layout early in a project before deciding whether explicit line records are needed for per-edge styling.
  • Building a migration path where a plain hierarchical viewer comes first, and richer node templates or branch interactions are added later.