JavaScript is required

Show All Preloaded Branch Nodes

This example shows how to preload several company-relationship branches, keep most branch members hidden, and reveal an entire branch through a synthetic `Show More(...)` node rendered inside the graph. It also demonstrates typed node-slot rendering, a left-to-right orthogonal tree layout, and a shared floating settings panel for interaction tuning and image export.

Reveal Preloaded Branch Members with an In-Graph Show More Node

What This Example Builds

This example builds a viewer-style corporate relationship tree around one focal company. The canvas shows a large blue root card, four typed branch control nodes for investment and shareholder categories, a compact first slice of company nodes under each branch, and a blue Show More(...) chip when a branch still has hidden members.

The main interaction is branch-local disclosure without fetching new data. All branch members are prepared during startup, but most of them stay hidden until the user clicks the synthetic reveal node inside that branch. A shared floating window above the graph also provides help text, a settings panel, and image export.

How the Data Is Organized

The graph starts from an inline RGJsonData seed with one root node and four branch nodes. Each branch node carries a data.myType value such as investment-button or shareholder-button, and the initial lines array connects the root to those four typed categories.

Before the graph is fully shown, appendTypeData calls the local loadMockCompanys(myType) helper to generate branch-specific company arrays. The current helper returns fixed branch sizes of 83, 45, 121, and 23, so the example behaves like a dense but fully known dataset rather than a remote API fetch.

Each generated company node is tagged with data.ownerType = myType, which later lets the reveal handler find all hidden members for one branch. The append step also injects a synthetic more-btn node into the same branch data and copies the parent branch coordinates onto every new node so the later append animation starts from the branch position instead of from arbitrary coordinates.

In a real application, the same structure could represent one company with current investments, historical investments, current shareholders, and historical shareholders. More generally, it fits any preloaded hierarchy where one parent category owns a long list of sibling records that should not all be visible at once.

How relation-graph Is Used

RGProvider supplies the relation-graph context, and RGHooks.useGraphInstance() drives the main workflow in both MyGraph and the shared settings panel. The component seeds the graph with setJsonData(...), appends branch members with addNodes(...) and addLines(...), waits for rendering with sleep(400), reruns layout with doLayout(), and finally frames the result with moveToCenter() and zoomToFit().

The layout is a left-to-right tree with layoutName: 'tree', from: 'left', orthogonal connectors, treeNodeGapH: 100, treeNodeGapV: 10, alignItemsX: 'start', and alignParentItemsX: 'end'. Those settings produce a broad horizontal corporate tree where dense sibling groups remain readable after a branch is revealed.

The example relies heavily on slot rendering. RGSlotOnNode renders four node roles differently: the root card, the typed branch controls, the synthetic Show More(...) action node, and ordinary company pills. The graph itself stays in viewer mode, but the slot makes the control nodes feel native to the diagram instead of external page UI.

Several instance APIs support the disclosure behavior. getNodes() finds the owner branch and later filters nodes by ownerType; updateNode(...) clears hidden; removeNodeById(...) deletes the reveal chip; clearChecked() resets selection styling when the canvas is clicked; and the shared CanvasSettingsPanel uses setOptions(...), prepareForImageGeneration(), getOptions(), and restoreAfterImageGeneration() for runtime interaction changes and export.

Styling is split between relation-graph options and local SCSS overrides. The options set a white default node color, rectangular nodes, right-side expand holders, left-right junction points, and rounded orthogonal line corners. The SCSS adds the tiled analysis background, checked-state emphasis, blue branch controls, blue reveal chips, and white rounded company pills.

Key Interactions

  • Clicking a Show More(...) node reveals all hidden members for one branch, removes that action node, and reruns layout.
  • The branch categories still participate in relation-graph’s built-in expand and collapse behavior, with relayout enabled after those state changes.
  • Clicking empty canvas space clears the current checked styling from nodes and lines.
  • The floating helper window can be dragged, minimized, and switched into a settings panel that changes wheel and drag behavior.
  • The same shared settings panel can export the current graph canvas as an image.
  • Ordinary node clicks are informational in this demo; the custom disclosure flow is attached to the synthetic more-btn node instead.

Key Code Fragments

This fragment shows that the graph is seeded with one focal company and four typed branch nodes before any company lists are appended.

const myJsonData: RGJsonData = {
    rootId: 'root',
    nodes: [
        { id: 'root', text: 'Tian Technology Co., Ltd.', expandHolderPosition: 'hide', data: { myType: 'root' } },
        { id: 'root-invs', text: 'Investment', disablePointEvent: true, data: { myType: 'investment-button', childrenLoaded: false } },
        { id: 'root-history-invs', text: 'Historical Investment', data: { myType: 'historical-investment-button', childrenLoaded: false } },
        { id: 'root-sh', text: 'Share Holder', disablePointEvent: true, data: { myType: 'shareholder-button', childrenLoaded: false } },
        { id: 'root-history-shareholder', text: 'Historical Share Holder', data: { myType: 'historical-shareholder-button', childrenLoaded: false } }
    ],

This fragment shows how branch members are preloaded, tagged by owner type, and hidden after the initial visible portion.

const defaultVisibleCount = 3;
const allItems = await loadMockCompanys(myType);
const total = allItems.length;
const thisTypeJsonData: RGJsonData = {
    nodes: [],
    lines: []
};
for (const entItem of allItems) {
    const companyNode: JsonNode = { id: entItem.companyId, text: entItem.companyName, data: { ownerType: myType } };
    if (thisTypeJsonData.nodes.length > defaultVisibleCount) {
        companyNode.hidden = true;
    }

This fragment shows that the reveal control is itself a synthetic graph node added into the branch structure.

const loadNextPageButtonNode = {
    id: loadNextPageButtonNodeId, text: `Show More(${remainingItemCount})`,
    data: { myType: 'more-btn', loadType: myType, fromIndex: (fromIndex + 1) }
};
currentPageGraphJsonData.nodes.push(loadNextPageButtonNode);
currentPageGraphJsonData.lines.push({ from: typeNodeId, to: loadNextPageButtonNode.id });

This fragment shows that clicking the synthetic action node unhides every staged node for that branch and then relayouts the graph.

const showAllNodes = async(buttonNode: RGNode) => {
    const myType = buttonNode.data.loadType;
    const typeNodes = graphInstance.getNodes().filter(n => n.data.ownerType === myType);
    typeNodes.forEach(n => {
        graphInstance.updateNode(n.id, { hidden: false });
    });
    graphInstance.removeNodeById(buttonNode.id);
    await graphInstance.doLayout();
};

This fragment shows that RGSlotOnNode renders the reveal node as a clickable graph-native control instead of ordinary node text.

{myType === 'more-btn' && (
  <div className="my-node more-btn px-2" onClick={() => {showAllNodes(node)}}>
    {node.text}
  </div>
)}
{!myType && (
  <div className="my-node">
    {node.text}
  </div>
)}

This fragment shows that the shared floating settings panel can switch interaction modes and export the graph canvas as an image.

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

The comparison data places this example closest to show-more-nodes-by-page, investment-penetration, expand-gradually, and open-by-level, but the implemented lesson is different from each of them. Relative to show-more-nodes-by-page, this demo is not about pagination or lazy loading. It preloads all four branch datasets on mount, keeps overflow members hidden, and reveals an entire branch in one step without refetching.

Relative to investment-penetration, the emphasis is not branch growth into newly fetched fragments or branch-direction management. The distinctive pattern here is branch-density control inside preseeded groups: the branch is already known, but the UI keeps it compact until the user asks to see the rest.

Relative to expand-gradually and open-by-level, the control surface is also more local and diagram-native. Disclosure is not driven by a global depth preset or a generic reopen flow. Instead, one branch receives a dedicated Show More(...) node inside the graph itself, and that node disappears after the reveal is complete.

The rarity signals reinforce that positioning. This example combines a left-to-right orthogonal corporate tree, typed branch control nodes, hidden-node staging by ownerType, a patterned canvas, and a synthetic reveal-all node rendered through the same node slot system as the rest of the graph. That combination makes it a strong starting point when the data is already available but one branch would otherwise become visually noisy immediately after load.

Where Else This Pattern Applies

This pattern transfers well to corporate ownership viewers, supplier or distributor maps, and project dependency trees where the full branch data is already available locally but long sibling lists should stay compact until requested.

It also fits dashboards that need graph-native call-to-action controls instead of external toolbars or side panels. A branch-local reveal chip is easier to understand when the action should apply to exactly one branch and should visually live beside the affected nodes.

Another extension is review tooling where analysts need a compact default graph, optional branch disclosure, and a quick image export from the same screen. The current demo does not implement workflow-specific review actions, but its hidden-node staging and floating utility panel are a practical base for that kind of interface.