Layout Rotation Controls
This example shows how to rotate a mounted relation-graph layout at runtime while switching the same dataset between the built-in center and tree layouts. A floating tool window provides angle controls, layout switching, canvas behavior settings, and image export so the graph can be studied as a small layout-tuning workspace.
Rotate Built-in Layouts with Live Angle Offsets
What This Example Builds
This example builds a full-viewport relation graph workspace for studying how one fixed dataset reflows when the layout angle changes at runtime. The main view shows a small labeled graph with circular nodes, path-mounted edge labels, and a floating control window above the canvas.
Users can rotate the current layout with a slider or step buttons, switch the same graph between the built-in center and tree layouts, open a secondary settings panel, and export the current graph as an image. The most important point is that the example does not reload new business data for each comparison. It keeps one graph in memory and changes layout.rotate plus layout.layoutName on the mounted instance.
How the Data Is Organized
The graph data is declared inline inside initializeGraph() as one RGJsonData object with rootId: '2', 15 declared nodes, and 15 declared lines. There is no preprocessing step before setJsonData(): the sample object is built and loaded directly.
That makes the data structure easy to replace with real application data such as an ownership graph, a reporting tree, a dependency structure, or any hierarchy where the same entities need to be viewed under different layout orientations. One detail worth noting is that one edge points from node 1 to node 5, even though node 1 is not declared in the node list, so this example should be read as a layout-control reference rather than a data-validation reference.
How relation-graph Is Used
index.tsx wraps the page in RGProvider, and MyGraph.tsx uses RGHooks.useGraphInstance() to control the mounted graph instance. The graph is initialized once with setJsonData(), then centered and fitted with moveToCenter() and zoomToFit().
The runtime layout changes happen through updateOptions({ layout }) followed by doLayout(). React state stores two parameters: layoutName and layoutRotate. When the angle changes, the example rewrites layout.rotate and relayouts the graph. When the layout family changes, it switches between center and tree, resets the angle state to 0, and triggers another relayout.
The graph options stay intentionally small: debug mode is off, line labels are rendered on the path, and the default node geometry is a circular 80 x 80 shape. There are no graph slots, no graph editing APIs, and no custom node rendering in this example. The local SCSS file only keeps empty selector placeholders, so most of the visible behavior comes from RelationGraph options and the shared floating helper components rather than local style overrides.
The floating window is not a relation-graph slot. It is a separate overlay component that shares the graph context through RGProvider. Its settings panel uses RGHooks.useGraphStore() to read the current wheel and drag modes, calls setOptions() to change those canvas behaviors at runtime, and uses prepareForImageGeneration() plus restoreAfterImageGeneration() during export.
Key Interactions
- The angle slider writes
layoutRotatewith a0to360range and5degree steps, which triggers a relayout through auseEffect. - The
Rotate 5deg CWandRotate 5deg CCWbuttons increment or decrement the same state directly, so fine rotation is possible without dragging the slider. These button updates are not clamped in code. - The segmented layout selector switches the same dataset between
centerandtree, then relayouts the mounted graph instead of rebuilding the dataset. - The floating window can be dragged, minimized, and switched into a settings overlay.
- The settings overlay can change
wheelEventActionanddragEventAction, and it also exposes aDownload Imageaction for the current canvas.
Key Code Fragments
This fragment shows that the example keeps one inline dataset and loads it once into the live graph instance.
const myJsonData: RGJsonData = {
rootId: '2',
nodes: [
{ id: '2', text: 'Root' }, { id: '9', text: 'Node-9' },
{ id: '4', text: 'Node-4' },
// ...
{ id: '5', text: 'Node-5' }
],
lines: [
{ id: 'l1', from: '2', to: '9', text: 'Executive' },
// ...
]
};
await graphInstance.setJsonData(myJsonData);
This fragment is the core runtime pattern: write layout options from React state, then run doLayout().
const reLayout = async () => {
graphInstance.updateOptions({
layout: {
layoutName: layoutName,
rotate: layoutRotate
}
});
await graphInstance.doLayout();
};
This fragment shows how the UI drives angle updates and layout-family switching from the floating window.
<SimpleUISlider
max={360}
min={0}
step={5}
currentValue={layoutRotate}
onChange={(newValue: number) => { setLayoutRotate(newValue); }}
/>
<SimpleUISelect
data={[{ value: 'center', text: 'Center' }, { value: 'tree', text: 'Tree' }]}
currentValue={layoutName}
onChange={(newValue: string) => { setLayoutName(newValue); }}
/>
This fragment shows that the shared settings overlay changes canvas behavior and uses the graph instance for image export.
<SettingRow
label="Wheel Event:"
options={[
{ label: 'Scroll', value: 'scroll' },
{ label: 'Zoom', value: 'zoom' },
{ label: 'None', value: 'none' },
]}
value={wheelMode}
onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}
/>
What Makes This Example Distinct
According to the comparison data, this example is most useful as a compact reference for layout.rotate on a live relation graph. Its distinctive combination is a fixed dataset, a 0 to 360 angle slider, +/-5 step buttons, a center or tree selector, and explicit updateOptions({ layout }) plus doLayout() calls in one small workspace.
Compared with center-layout-options, it emphasizes orientation change and cross-layout comparison instead of spacing coefficients inside one layout family. Compared with switch-layout, it goes deeper on manual parameter tuning instead of timed playback across preset layouts. Compared with drag-and-wheel-event, the floating settings surface is only a secondary utility here; the main lesson is how the same graph silhouette changes when the layout rotates.
The visual treatment is also intentionally restrained. The comparison record highlights that the circular 80 x 80 nodes and path-mounted labels act as a neutral probe for reflow, so the viewer notices layout movement rather than custom rendering.
Where Else This Pattern Applies
This pattern can be reused for internal tools where users need to compare several readable orientations of the same graph before choosing a default view. Examples include organization maps, ownership structures, dependency trees, and knowledge-map branches that become crowded at one angle but readable at another.
It also transfers well to parameter-tuning panels around other relation-graph options. The important reusable idea is not the exact sample data. It is the combination of React state, updateOptions(), and explicit doLayout() calls to turn a mounted graph into a controlled layout-testing surface.