JavaScript is required

Initialize Graph On Tab Reveal

This example embeds relation-graph inside a three-state page and delays both graph mounting and data initialization until the user opens the Graph tab. It uses `RGHooks.useGraphInstance()` to load a flat inline dataset, generate missing line ids, and immediately center and fit the first visible view.

Initialize a Graph on First Tab Reveal

What This Example Builds

This example builds a full-height page with three mutually exclusive panels: Basic Info, Graph, and Warning Info. The user does not see a graph on first load. Instead, the page opens on a green placeholder panel, then switches to a left-to-right tree graph only when the Graph tab is selected.

The main point is lifecycle control rather than graph styling. The example shows how to keep RelationGraph out of the DOM until its panel becomes visible, then initialize the data once and immediately center and fit the viewport for the first visible render.

How the Data Is Organized

The graph data is declared inline inside initializeGraph() as one RGJsonData object with rootId: 'a', 13 flat nodes, and 12 flat lines. The tree structure is expressed through from and to pairs, not through nested children.

There is only one preprocessing step before loading: the code iterates over every line and assigns an id when one is missing. After that, the dataset is passed directly to setJsonData(). In a real application, the same structure could represent record dependencies, troubleshooting branches, approval chains, or any detail page where a graph is one secondary tab inside a broader information screen.

How relation-graph Is Used

index.tsx wraps the example in RGProvider, and MyGraph.tsx gets the active instance through RGHooks.useGraphInstance(). The visible graph is configured as a left-to-right tree with treeNodeGapH: 120, treeNodeGapV: 20, rectangular nodes, defaultNodeWidth: 100, RGLineShape.StandardCurve, RGJunctionPoint.lr, and right-side expand holders.

No custom node, line, canvas, or viewport slots are used here. The important pattern is deferred instance-driven loading: setJsonData() injects the data only after the graph tab becomes active, then moveToCenter() and zoomToFit() normalize the first visible frame. The SCSS file is present as an override scaffold, but it does not materially restyle the graph in this example.

The graph is conditionally embedded rather than permanently mounted. A local SimpleUISelect component controls activeTabName, RelationGraph is rendered only when activeTabName === 'graph', and a useEffect() guarded by graphInitedRef ensures the initialization routine runs only on the first graph-tab activation. The reviewed source intentionally does not establish whether graph state persists after leaving and re-entering the tab.

Key Interactions

  • Clicking the selector switches between Basic Info, Graph, and Warning Info.
  • The first switch to Graph mounts RelationGraph, builds the inline dataset, loads it through setJsonData(), and then centers and fits the viewport.
  • Switching to Basic Info or Warning Info replaces the graph panel with placeholder content instead of merely hiding the graph with CSS.
  • The selector itself is a reusable local component whose active-state styling is driven by currentValue.

Key Code Fragments

This wrapper shows that the page and the graph component share the same relation-graph provider context.

const Demo = () => {
    return (
        <RGProvider>
            <MyGraph />
        </RGProvider>
    );
};

This block shows that the visible graph is a left-to-right tree with rectangular nodes and curved links.

const graphOptions: RGOptions = {
    layout: {
        layoutName: 'tree',
        from: 'left',
        treeNodeGapH: 120,
        treeNodeGapV: 20
    },
    defaultExpandHolderPosition: 'right',
    defaultNodeShape: RGNodeShape.rect,
    defaultNodeWidth: 100,
    defaultLineShape: RGLineShape.StandardCurve,
    defaultJunctionPoint: RGJunctionPoint.lr
};

This fragment proves that the graph payload is a flat inline nodes and lines structure rather than nested children.

const myJsonData: RGJsonData = {
    rootId: 'a',
    nodes: [
        { id: 'a', text: 'a' },
        { id: 'b', text: 'b' },
        { id: 'b1', text: 'b1' },
        // ... more nodes ...
    ],
    lines: [
        { from: 'a', to: 'b', text: 'line1' },
        // ... more lines ...
    ]
};

This fragment shows the only preprocessing step and the immediate viewport normalization after the first load.

myJsonData.lines.forEach((line, index) => {
    if (!line.id) {
        line.id = `line-${index}`;
    }
});
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();

This effect is the core lifecycle pattern: do nothing until the graph tab is active, then initialize only once.

useEffect(() => {
    if (activeTabName === 'graph') {
        if (!graphInitedRef.current) {
            graphInitedRef.current = true;
            initializeGraph();
        }
    }
}, [activeTabName]);

This render branch makes the graph one panel inside a three-state workspace instead of the page’s permanent surface.

{activeTabName === 'graph' && (
    <div className="h-full">
        <RelationGraph options={graphOptions} />
    </div>
)}
{activeTabName === 'warning' && (
    <div className="h-full bg-yellow-100 flex justify-center place-items-center text-4xl">
        Warning Information
    </div>
)}

What Makes This Example Distinct

The comparison data places this example near customize-fullscreen-action, tree-data, and graph-instance-api, which all share provider-scoped instance access, tree rendering, and post-load centering. What distinguishes adv-hide-2-show is the first-visibility lifecycle pattern: RelationGraph is absent until the user selects the Graph tab, then the example loads a flat inline dataset, generates missing line ids, and normalizes the viewport immediately after that first reveal.

Compared with customize-fullscreen-action, this example is not about wrapper composition or fullscreen targeting. It swaps among three full-height content panels and focuses on hidden-container timing. Compared with tree-data, it emphasizes deferred reveal and flat nodes plus lines data instead of immediate mount with nested children. Compared with graph-instance-api, it uses the same hook and instance APIs only for initial reveal and viewport setup, not for ongoing programmatic expand or collapse controls.

Within the simpler placeholder-panel examples, the distinctive combination is tab-driven lazy reveal plus a one-time initialization guard. That makes it a better starting point for screens where the graph is an optional inspection mode rather than the default page surface.

Where Else This Pattern Applies

This pattern transfers directly to tabs, drawers, accordions, steppers, and modal detail views where a graph should not be initialized while its container is hidden. It is also useful for mixed-content record pages where users first review summary or warning information, then open a graph as a secondary analysis panel.

The same structure also fits API-driven loading. Instead of hard-coded data, an application could fetch relationships only when the graph tab becomes active, assign missing edge ids before loading, and then call center-and-fit so the first visible frame is ready for use immediately.