JavaScript is required

Depth-First Tree Expansion Playback

A relation-graph demo that loads an inline subsystem tree, collapses every expandable branch, and then replays expansion automatically from the root. It combines recursive `expandNode(...)` calls, timed pauses, canvas animation, and repeated viewport fitting so the reveal behaves like guided playback instead of manual disclosure.

Depth-First Tree Expansion Playback

What This Example Builds

This example builds a full-height tree viewer that replays a hierarchy from the root outward instead of waiting for users to click expand controls. The screen shows a rectangular-node tree with curved labeled edges, and the graph starts unfolding automatically as soon as the component mounts.

The main point is the playback behavior. The code first loads the whole hierarchy, collapses every branch that still has children, and then expands the tree step by step with short pauses. During that sequence, the viewport keeps recentering and fitting the visible graph so the reveal stays readable.

How the Data Is Organized

The data is declared inline inside initializeGraph() as a standard RGJsonData-style tree payload with rootId, nodes, and lines. Each node is a simple { id, text } object, and each edge is a { from, to, text } relation that labels the connection as Subsystem.

Before the data is passed to setJsonData(), the example maps the lines array and adds a synthetic id such as line_0 or line_1. No remote fetch, lazy loading, or server-side transformation is involved. In a production system, the same shape could represent an equipment breakdown tree, a subsystem map, an organization chart, or a product structure imported from an API.

How relation-graph Is Used

The demo is wrapped in RGProvider, and MyGraph obtains the active graph instance through RGHooks.useGraphInstance(). That hook is the center of the example: it loads data, recenters the viewport, toggles canvas animation, enumerates nodes for the reset pass, finds the root node, and drives expansion with imperative API calls.

The graph configuration uses a tree layout with treeNodeGapV: 20 and treeNodeGapH: 120. It also turns on reLayoutWhenExpandedOrCollapsed, places expand holders on the right, uses rectangular nodes, draws curved connectors, anchors lines from left to right with RGJunctionPoint.lr, and places line text directly on the path.

There are no custom slots, no event handlers, and no editor features in this example. Styling is intentionally minimal: the imported SCSS file contains selector scaffolding for nodes, lines, and checked states, but it does not add concrete declarations, so most of the appearance comes from the default relation-graph rendering plus the 100vh wrapper.

Key Interactions

The primary interaction is scripted rather than click-driven. useEffect() runs once, calls initializeGraph(), and starts playback immediately after the graph data is loaded.

The sequence itself has three important steps. First, openAll() collapses every node whose rgChildrenSize is greater than zero, which guarantees a consistent reset state even though the full hierarchy is already loaded. Second, deepExpandNode() expands one branch at a time in depth-first order, using two sleep(300) pauses around each viewport update. Third, each step calls moveToCenter() and zoomToFit(), so the camera follows the current reveal instead of staying fixed on the original bounds.

Key Code Fragments

This options fragment shows that the example is a relayout-aware tree with rectangular nodes and curved labeled edges.

defaultExpandHolderPosition: 'right',
reLayoutWhenExpandedOrCollapsed: true,
defaultNodeShape: RGNodeShape.rect,
defaultNodeBorderWidth: 1,
defaultLineShape: RGLineShape.StandardCurve,
defaultJunctionPoint: RGJunctionPoint.lr,
defaultLineTextOnPath: true,
layout:
{
    layoutName: 'tree',
    treeNodeGapV: 20,
    treeNodeGapH: 120
}

This preprocessing step proves that the demo converts the inline raw hierarchy into RGJsonData and assigns a unique id to every line before loading it.

const myJsonData: RGJsonData = {
    ...rawData,
    lines: rawData.lines.map((line, index) => ({
        ...line,
        id: `line_${index}`
    }))
};

await graphInstance.setJsonData(myJsonData);

This recursive fragment is the core playback algorithm: skip leaves, expand the current node, pause, refit the viewport, pause again, and then recurse into the children.

if (node.rgChildrenSize === 0) {
    return;
}
graphInstance.expandNode(node);
await graphInstance.sleep(300);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
await graphInstance.sleep(300);
for (const cnode of node.lot.childs) {
    await deepExpandNode(cnode);
}

This reset pass shows that playback always restarts from a collapsed tree and then begins again from the root node.

graphInstance.getNodes().forEach(n => {
    if (n.rgChildrenSize > 0) {
        graphInstance.collapseNode(n);
    }
});
await deepExpandNode(graphInstance.getRootNode());

What Makes This Example Distinct

According to the comparison data, this example is unusual because it replays expansion automatically on mount without adding playback buttons or waiting for a click on a collapsed branch. That makes it a stronger reference for guided reveal behavior than examples that focus on manual disclosure.

It is also more specific than a general graph-instance API sample. Compared with graph-instance-api, the same provider hook and imperative API style are used here to orchestrate an entire hierarchy rather than toggling one known node from an external control. Compared with expand-gradually, the emphasis shifts from user-triggered branch opening to a timed depth-first reveal. Compared with open-by-level, the reveal order comes from recursive traversal rather than a chosen level threshold.

The comparison file also highlights the camera-follow pattern as part of the example’s identity. Many samples center or fit the graph after initial load; this one repeats moveToCenter() and zoomToFit() during every expansion step, so viewport management becomes part of the playback algorithm itself.

Where Else This Pattern Applies

This pattern transfers well to onboarding walkthroughs, architecture explainers, subsystem decomposition demos, and training material where a hierarchy should unfold in a controlled order. It is also useful for presentation modes that need a deterministic replay from a known root state instead of open-ended browsing.

The same approach can be adapted to dependency trees, bill-of-material structures, infrastructure ownership graphs, or curriculum maps. The important reuse point is not the sample data itself, but the combination of collapse-before-start initialization, recursive expandNode() playback, and viewport synchronization after each step.