Corporate Group Relationship Map
This example renders a dense corporate relationship map from a static inline dataset and fits it into a centered relation-graph canvas. Users can switch live nodes between circular and rectangular presentations, optionally replace built-in nodes with custom slot content, adjust canvas interaction modes, and export the current view as an image.
Corporate Group Relationship Map with Live Node Skin Switching
What This Example Builds
This example builds a read-focused corporate relationship viewer on a single centered canvas. It loads a prebuilt graph of 111 nodes and 209 labeled relationships, mixes controller-like people nodes with company nodes, and presents them as a dense network instead of a hierarchy. Users can switch the same loaded graph between circle and rect node presentations, turn custom slot rendering on or off, open a floating utility panel, change wheel and drag behavior, and export the current canvas as an image. The most useful technical point is that the presentation changes happen on the live graph instance instead of rebuilding the dataset.
How the Data Is Organized
The data lives in my-data.ts as a static inline RGJsonData object returned by the async getMyJsonData() helper. The object contains a rootId, a nodes array, and a lines array. Each node carries display fields such as id, text, color, and borderColor, and most nodes also include data.nodetype so the renderer can distinguish ctrler entities from ent entities; the dataset also contains one main node type. Each line contains from, to, text, and fontColor, and those labels mix percentages with executive-role text such as director or manager titles, so the graph represents a broader relationship board rather than a pure equity tree.
There is no real preprocessing before setJsonData(...). initializeGraph() simply awaits getMyJsonData() and passes the object directly to relation-graph. In a production system, the same structure could come from shareholder analysis, board-control data, affiliate networks, partner ownership data, or compliance review outputs.
How relation-graph Is Used
The entry file wraps the demo in RGProvider, which allows hooks to resolve the active graph instance. Inside MyGraph.tsx, RGHooks.useGraphInstance() drives the main workflow: loading the static dataset, centering the viewport, fitting the graph to the canvas, changing runtime options, and updating already rendered nodes. The graph starts with layoutName: 'center', RGLineShape.StandardCurve, RGJunctionPoint.border, no default node border, and a default node size of 60 x 60.
The key implementation detail is the shape switch. defaultNodeShape is bound to React state, but the code also calls getNodes() and updateNode(...) after load because changing defaults alone does not restyle nodes that already exist in the graph. When the user switches to rectangular nodes, the example also changes the junction point from border to ltrb so connectors attach in a way that suits the new geometry.
RGSlotOnNode is optional rather than mandatory. When enabled, the same data renders through custom business-oriented markup: circle mode shows an icon centered inside the node with a detached label below it, while rect mode shows a white chip with icon, text, and a border that reuses var(--rg-node-color). The icon choice depends on node.data.nodetype, so controller nodes and enterprise nodes remain visually distinct.
The floating helper window comes from the shared DraggableWindow component. Its settings overlay uses RGHooks.useGraphStore() to read the current interaction options and uses graph instance APIs to switch wheelEventAction and dragEventAction. The same shared panel also runs the export flow through prepareForImageGeneration(), modern-screenshot, and restoreAfterImageGeneration(). Local SCSS overrides keep the canvas background white and style the detached node text, especially in the checked state.
Key Interactions
The Rect and Circle selector changes live node geometry and connector attachment behavior on already loaded nodes.
The checkbox mounts or unmounts RGSlotOnNode, so users can compare custom business-oriented node skins against built-in node rendering without changing the underlying data.
The floating description window can be dragged, minimized, and switched into a settings overlay from the gear button.
Inside the settings overlay, wheel handling can switch between scroll, zoom, and none, while canvas drag handling can switch between selection, move, and none.
The Download Image action captures the current graph canvas through the shared screenshot helper and downloads the result as a file.
Key Code Fragments
This fragment shows that the graph loads one prepared dataset, then recenters and fits the viewport instead of incrementally expanding branches.
const initializeGraph = async () => {
const myJsonData = await getMyJsonData();
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter(); // Center on canvas slot content
graphInstance.zoomToFit(); // Zoom to fit canvas slot content
};
This fragment proves that shape switching is applied to the live graph, not just to future nodes.
graphInstance.getNodes().forEach(node => {
graphInstance.updateNode(node, {
nodeShape: nodeShape,
width: nodeShape === RGNodeShape.circle ? 60 : 0,
height: nodeShape === RGNodeShape.circle ? 60 : 0
})
});
This fragment shows that custom slot rendering is optional and can be turned on or off from the example UI.
<SimpleUIBoolean
label="Use Node Slot to Render Node Content"
currentValue={enableNodeSlot}
onChange={setEnableNodeSlot}
/>
</div>
</DraggableWindow>
<RelationGraph options={graphOptions}>
{enableNodeSlot && <RGSlotOnNode>
This fragment shows how the slot renderer changes node content by shape and by business entity type.
nodeShape === RGNodeShape.circle ? (
<div className="w-full h-full flex place-items-center justify-center">
<div className="text-white w-full h-full flex place-items-center justify-center">
{node.data.nodetype === 'ctrler' ? <UserCircleIcon size={32} /> : <Building2Icon size={32} />}
</div>
<div className="my-node-text absolute transform translate-y-[45px]">{node.text}</div>
</div>
) : (
This fragment comes from the shared helper and shows how the example exposes export without rebuilding the graph.
const canvasDom = await graphInstance.prepareForImageGeneration();
let graphBackgroundColor = graphInstance.getOptions().backgroundColor;
if (!graphBackgroundColor || graphBackgroundColor === 'transparent') {
graphBackgroundColor = '#ffffff';
}
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
backgroundColor: graphBackgroundColor
});
if (imageBlob) {
downloadBlob(imageBlob, 'my-image-name');
}
What Makes This Example Distinct
Compared with nearby business examples such as scene-org, investment-penetration, and investment, this example stays on one preloaded centered network canvas instead of turning the scene into a tree, an org chart, or a lazy expansion flow. That matters when the requirement is to inspect many cross-links and mixed relationship labels at once.
Compared with runtime-style neighbors such as css-theme and drag-and-wheel-event, the controls here are tied to business-scene readability. The main lesson is not generic theming or canvas testing. It is how to keep one dense corporate graph loaded and let users switch between built-in nodes and custom slot-rendered business skins while also changing node geometry on the already rendered graph.
The comparison data also marks the combination itself as unusual: center layout, dense labeled lines, role-colored people-versus-company entities, runtime node-shape switching, optional RGSlotOnNode, and a shared floating settings or export shell on the same page. That combination makes this example a stronger starting point for compact business-network viewers than for editors or hierarchy-first charts.
Where Else This Pattern Applies
This pattern transfers well to shareholder-control review screens, affiliate-network analysis, board-and-executive relationship viewers, and due-diligence dashboards that need one dense relationship board instead of a directional tree.
It also fits cases where product teams want two presentation modes over the same graph data, such as a compact icon-first overview and a more readable label-first card view.
The live updateNode(...) restyling approach is especially useful in any graph product where users can change visual encoding after load, for example switching between risk views, entity categories, or audience-specific display modes without re-fetching the dataset.