Enterprise Quadrant Fixed Layout
This example builds a four-quadrant enterprise relationship graph in relation-graph's fixed layout mode. It generates RGJsonData from category lists, computes manual coordinates in a separate layout pass, and lets users retune spacing at runtime from a floating control window.
Build a Four-Quadrant Enterprise Graph with Fixed Coordinates
What This Example Builds
This example renders one company at the center of the canvas and places four relationship categories around it: investors, persons, outbound investments, and branch offices. Each category gets its own group node, its own color, and its own line treatment, so the result reads as a quadrant-style enterprise relationship map instead of a generic tree.
The user does not edit graph structure here. The main interaction is live retuning of a manual layout: a floating panel lets the user change line length and node spacing, and the graph is repositioned immediately. The key point is that relation-graph is used as a fixed-position rendering surface while custom code decides every node coordinate.
How the Data Is Organized
The data starts as inline arrays inside initializeGraph(): one root company plus four category lists. generateGraphData(...) converts those lists into RGJsonData by creating the center node, four group nodes, and all leaf nodes and lines before the graph is loaded.
The important preprocessing step is that the initial JSON does not contain final coordinates. Instead, the generator adds metadata such as type, quadrantKey, and index, and applyLayout(...) uses that metadata later to compute x and y positions. In a real system, the same structure could represent shareholders, executives, subsidiaries, offices, suppliers, distributors, or any category-based network around one primary entity.
How relation-graph Is Used
The graph runs in fixed layout mode, so relation-graph does not choose node positions. RelationGraph is configured with rectangular nodes, zero default borders, left-right junction points, and a straight-line default, while the generated line data overrides individual routes to mix curved center links with orthogonal leaf links.
RGProvider supplies graph context, and RGHooks.useGraphInstance() is the main integration point. The example uses it to load JSON data with setJsonData(...), read the live node list with getNodes(), write coordinates back with updateNode(...), and then recenter and fit the viewport with moveToCenter() and zoomToFit(). The shared CanvasSettingsPanel also uses the graph instance to change wheelEventAction and dragEventAction at runtime and to export the canvas as an image.
There are no graph slots and no structural editing tools in this example. The extra UI comes from shared subcomponents: DraggableWindow provides the floating shell, and CanvasSettingsPanel provides canvas-mode toggles and image export. Styling is customized through generated class names such as my-nodes-invs and SCSS overrides for node colors, line-label backgrounds, expand holders, and checked-state line styling.
Key Interactions
Two range inputs drive the example-specific behavior. Changing leafLineLength or leafNodeGap updates React state, and a follow-up effect reruns the custom coordinate pass over the current graph nodes.
The helper window itself can be dragged, minimized, and switched into a settings view. Inside that settings view, the user can change wheel behavior between scroll, zoom, and none; change drag behavior between selection, move, and none; and export the current graph as an image.
Node and line click handlers are present, but they only log the clicked object. They do not control selection, highlighting, or editing.
Key Code Fragments
This option block shows that the graph is intentionally put into fixed mode and given rectangular, left-right defaults.
const userGraphOptions: RGOptions = {
layout: {
layoutName: 'fixed'
},
defaultNodeBorderWidth: 0,
defaultNodeShape: RGNodeShape.rect,
defaultJunctionPoint: RGJunctionPoint.lr,
defaultLineShape: RGLineShape.StandardStraight
};
This fragment shows that structural graph JSON is assembled first, while each leaf keeps quadrant metadata for the later layout pass.
nodes.push({
...item,
className: `my-nodes-${rule.nodeClassSuffix}`,
data: { type: 'leaf', quadrantKey: rule.key, index: index }
});
lines.push(createLine(rule.rootId, item.id, {
text: item.desc || '',
color: rule.color,
showEndArrow: false,
lineShape: RGLineShape.SimpleOrthogonal
}));
This coordinate fragment is the core manual-layout logic: it grows leaves upward or downward by category and places them to the left or right of the group node.
if (rule.isTop) {
leafY = groupOriginY - (index * (LEAF_NODE_H + leafNodeGap)) + 30;
} else {
leafY = groupOriginY + (index * (LEAF_NODE_H + leafNodeGap));
}
const leafX = rule.isLeft
? groupOriginX - leafLineLength - node.el_W
: (groupOriginX + 140) + leafLineLength;
nodesPosition.push({ nodeId: node.id, x: leafX, y: leafY });
This runtime pass shows how the custom coordinates are pushed back into the live relation-graph instance.
const nodes = graphInstance.getNodes();
const nodesPosition = applyLayout(
nodes,
leafNodeInitialWidth,
leafLineLength,
leafNodeGap
);
for (const nodePos of nodesPosition) {
graphInstance.updateNode(nodePos.nodeId, {
x: nodePos.x,
y: nodePos.y
});
}
What Makes This Example Distinct
Based on the prepared comparison data, this example is distinct because it is a direct reference for deterministic manual coordinate assignment, not a showcase of relation-graph’s built-in layout presets. Compared with layout-center, it is the stronger starting point when the placement rules come from application logic and must be written back as explicit x and y values. Compared with bothway-tree and bothway-tree2, it is not teaching tree orientation or branch restyling; it is teaching category-based quadrant placement in fixed mode. Compared with deep-each, the meaningful live interaction is parameterized relayout rather than click-driven focus highlighting.
Its rare combination is also important: a corporate relationship scene, four color-coded rectangular quadrants around one company node, curved center links plus orthogonal labeled leaf links, and a floating white helper window with runtime canvas utilities. That combination makes it a practical bridge example for teams that need a predictable layout region for each category instead of a layout chosen by the library.
Where Else This Pattern Applies
This pattern transfers well to shareholder maps, corporate control diagrams, vendor or customer relationship summaries, branch or region maps, and compliance dashboards where each category needs a stable visual region. The same separation between generateGraphData(...) and applyLayout(...) can also be used when positions come from an external service or an in-house algorithm rather than from hand-written quadrant rules.
It is also a useful migration pattern for teams bringing existing layout math into relation-graph. You can generate RGJsonData once, compute positions in a separate pass, and then push those coordinates into the live graph instance without rewriting the rendering layer.