Industry Chain Hierarchy Map
This example renders a semiconductor industry-chain hierarchy as a top-down relation-graph tree with custom card nodes. It uses computed node levels to control expansion depth, card styling, and semantic headers, and it adds a floating helper panel with a minimap toggle, canvas settings, and image export.
Industry Chain Hierarchy Viewer with Preset Depth Control
What This Example Builds
This example builds a read-only industry-chain viewer for a semiconductor taxonomy. The canvas opens as a top-down tree whose root is Semiconductor, then branches into areas such as raw materials, design, manufacturing, testing, packaging, and equipment.
Users can reveal different hierarchy depths from a floating control window, toggle a minimap overlay, open shared canvas settings, and export the graph as an image. The most important visual idea is that the graph does not just expand by depth: it also recolors and restyles each node card according to the computed level from the finished layout.
How the Data Is Organized
The data is a single inline RGJsonData object declared inside initializeGraph(). It uses a classic tree structure: one rootId, a flat nodes array, and a flat lines array that connects each parent to its child.
There is almost no preprocessing before setJsonData(). The only transformation is a map() over lines that assigns a generated id when a line does not already have one. The important structural processing happens after the graph has been laid out: the example reads node.lot.level and then updates each node’s expanded, color, and className fields in place.
In a real application, the same shape could represent a supply chain, a product taxonomy, a manufacturing capability map, a policy breakdown, or any other multilevel business hierarchy where the source data is parent-child rather than free-form network data.
How relation-graph Is Used
The page is wrapped in RGProvider in index.tsx, and the actual graph logic pulls the shared instance through RGHooks.useGraphInstance(). That hook is reused in the floating utility components too, so the example keeps one graph context for loading data, changing options, and exporting the current canvas.
The graph itself is configured as a top-down tree. graphOptions sets layout.layoutName = 'tree', from = 'top', a vertical gap of 120, centered alignment, rectangular nodes, bottom expand holders, and curved top-bottom connectors through RGLineShape.Curve2 with RGJunctionPoint.tb. reLayoutWhenExpandedOrCollapsed is enabled, which matches the preset-depth behavior.
The example uses several graph instance APIs in sequence. On mount it calls loading(), setJsonData(), openByLevel(1), moveToCenter(), zoomToFit(), and clearLoading(). After that, depth changes rely on getNodes(), updateNode(), and doLayout() so the visible hierarchy and styling stay synchronized.
Two slots define the presentation layer. RGSlotOnNode replaces the default node body with a custom card, and RGSlotOnView conditionally mounts RGMiniView when the minimap toggle is enabled. The node slot uses node.lot.level again to choose header labels such as Industry Chain Name, Industry Link, and Subsection Link.
Styling is split between runtime node updates and SCSS overrides. Runtime code writes a per-node color and className, while my-relation-graph.scss reads var(--rg-node-color) to paint the card border, header, body text, and expand button. Level-specific classes then adjust width and typography for different tiers.
The floating panel comes from the shared DraggableWindow component. That helper adds dragging, minimizing, a settings overlay, wheel and drag mode switches through setOptions(), and image export by calling prepareForImageGeneration() and restoreAfterImageGeneration() around a DOM screenshot step.
Key Interactions
- The graph auto-loads on mount and initially opens to one computed depth level before centering and fitting the view.
- The preset selector exposes three depth commands labeled
2,3, and4. In code those buttons pass1,2, and3intoopenByDeep(), so the labels are presentation text rather than raw internal level numbers. - Each depth change reuses the same post-layout metadata to expand or collapse nodes, assign a level color, assign a level class, rerun layout, and refit the viewport.
- The minimap checkbox toggles an
RGMiniViewoverlay on the same canvas instead of opening a separate navigator. - The floating helper window can be dragged, minimized, switched into a canvas-settings overlay, and used to download the current graph as an image.
Key Code Fragments
This fragment shows that the example uses one inline hierarchy dataset and fills in missing line IDs before loading it.
const myJsonData: RGJsonData = {
rootId: '0',
nodes: [
{ id: '0', text: 'Semiconductor' },
{ id: '1', text: 'Final Test' },
// ... many semiconductor categories omitted ...
],
lines: [
{ text: '', from: '0', to: '1' },
{ text: '', from: '1', to: '2' },
// ... hierarchy links omitted ...
].map((line, index) => ({ ...line, id: line.id || `line-${index}` }))
};
This fragment shows the load sequence: data is mounted first, then level-based expansion runs, and only after that does the viewport recenter and fit.
graphInstance.loading();
await graphInstance.setJsonData(myJsonData);
await openByLevel(1);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
graphInstance.clearLoading();
This fragment shows the core technique of the example: computed layout depth becomes the source of truth for expansion, color, and CSS class.
const nodes = graphInstance.getNodes();
const levelColors = ['#5b05f1', '#FD8B37', '#9b9903', '#247c02'];
nodes.forEach(node => {
const nodeLevel = Math.abs(node.lot.level || 0);
graphInstance.updateNode(node, {
color: levelColors[nodeLevel] || '#247c02',
expanded: nodeLevel < level,
className: 'my-industy-node-level-' + nodeLevel
});
});
await graphInstance.doLayout();
This fragment shows how the custom node slot turns the same graph data into a tier-labeled business card instead of a default text node.
<RGSlotOnNode>
{({ node }: RGNodeSlotProps) => {
const level = node.lot?.level || 0;
let headerText = "Product Type";
if (level === 0) headerText = "Industry Chain Name";
else if (level === 1) headerText = "Industry Link";
else if (level === 2) headerText = "Subsection Link";
return (
<div className={`my-industy-node my-industy-node-level-${level}`}>
This fragment shows how the minimap is treated as a view-level overlay that can be mounted only when the control panel enables it.
<SimpleUIBoolean
currentValue={showMiniView}
onChange={setShowMiniView}
label="Show graph minimap"
/>
// ...
<RGSlotOnView>
{showMiniView && <RGMiniView />}
</RGSlotOnView>
This fragment shows how SCSS consumes the runtime color and class metadata to style the cards.
.my-industy-node {
width: 160px;
border-radius: 5px;
background-color: #ffffff;
border: var(--rg-node-color) solid 1px;
.my-card-header {
background-color: var(--rg-node-color);
color: #fff;
}
.my-card-body {
color: var(--rg-node-color);
}
}
What Makes This Example Distinct
Compared with nearby examples such as open-by-level, investment, layout-tree, and layout-folder2, this example is unusually focused on one business-reading surface rather than on layout experimentation or incremental data growth. The graph stays in one top-down tree configuration and uses that stable layout to present a large inline taxonomy clearly.
Its main distinction is the combination of three behaviors that are treated as one pattern. First, depth changes are preset commands instead of manual branch-by-branch navigation. Second, the same computed node.lot.level drives disclosure state, color, and CSS class together. Third, the viewer can optionally add RGMiniView without changing the core hierarchy model.
That makes it different from open-by-level, which shares the level-based disclosure pattern but does not turn level metadata into a custom semantic card design. It also differs from investment, where the main lesson is lazy-loaded ownership expansion, and from layout-tree or layout-folder2, where the emphasis is layout tuning rather than a fixed industry-taxonomy presentation.
Where Else This Pattern Applies
This pattern transfers well to other read-only hierarchy viewers where the user needs fast jumps between overview depth and detail depth without editing the dataset.
Possible migration targets include supplier-tier maps, capability breakdowns for manufacturing lines, multilevel product catalogs, regulatory or standards taxonomies, and organization knowledge maps. In each case, the key reusable idea is to let relation-graph compute the tree level once, then use that derived level to coordinate disclosure rules, semantic labeling, and visual emphasis.