Canvas and Node Interaction Locks
This example loads a centered hierarchy into relation-graph with wheel zoom, canvas dragging, and node dragging disabled in the initial options. It then shows how to re-enable those behaviors at runtime through a floating helper window, shared canvas settings controls, and image export utilities.
Locking Canvas and Node Interaction in a Centered Graph Viewer
What This Example Builds
This example builds a full-height relation-graph viewer that opens in a restricted interaction state. The graph itself is a small centered hierarchy with rectangular nodes and gray curved lines, while a floating white utility window sits above the canvas.
Users can re-enable zoom, canvas dragging, and node dragging through three top-level switches. The same floating window can also be dragged, minimized, expanded into a settings overlay, and used to export the current graph as an image.
The key point is the startup state. Instead of allowing free navigation immediately, the example declares interaction locks in the initial RGOptions and then relaxes them on the live graph instance.
How the Data Is Organized
The graph data is declared inline inside initializeGraph as one RGJsonData object. It uses the standard flat relation-graph shape: a rootId, a nodes array of { id, text } records, and a lines array of { id, from, to } records.
There is no preprocessing pipeline before setJsonData(). The only preparation built into the data itself is that every line already has an explicit id, and after loading the example immediately normalizes the viewport with moveToCenter() and zoomToFit().
In a real application, the same structure could represent an organization tree, a dependency outline, an approval hierarchy, or any embedded viewer where the data should remain readable but initially non-draggable.
How relation-graph Is Used
index.tsx wraps the page in RGProvider, and MyGraph.tsx uses RGHooks.useGraphInstance() to work with the active graph instance. The graph options are stored in React state and passed directly into <RelationGraph options={options} />, which makes the component a compact example of state-driven option control.
The configured graph stays on one center layout. It sets rectangular nodes, curved lines, left-right-top-bottom junction routing, and a minimal gray visual style. More importantly, it starts with wheelEventAction: 'none', dragEventAction: 'none', and disableDragNode: true, so both the canvas and the nodes are intentionally locked at first render.
The main instance API flow is simple and explicit: setJsonData() loads the inline hierarchy, moveToCenter() and zoomToFit() normalize the first view, and updateOptions() applies partial option changes from the three example-specific switches. No node slots, line slots, editing handles, or data mutations are used here.
The floating control window comes from the shared DraggableWindow helper. That helper uses RGHooks.useGraphStore() and RGHooks.useGraphInstance() again inside CanvasSettingsPanel, where it reads the current option state, switches wheel and canvas drag behavior with setOptions(), and exports the graph image through prepareForImageGeneration() and restoreAfterImageGeneration(). The imported SCSS file is only an empty selector scaffold, so the visible result is driven almost entirely by graph options and shared utility UI.
Key Interactions
The primary interaction is runtime option switching. Three switches in the floating panel toggle wheel zoom, canvas dragging, and node dragging by merging partial RGOptions into local React state and sending the same changes to graphInstance.updateOptions(...).
The second interaction layer comes from the shared utility window. Its title bar can be used to drag the window, the window can be minimized and restored, and the settings button opens an overlay with segmented controls for wheel mode and canvas drag mode.
The settings overlay adds one more practical action: image export. It asks relation-graph to prepare the canvas DOM for screenshot generation, renders that DOM to a blob, downloads the file, and then restores the graph state after capture.
There is no example-specific node click handler, selection workflow, or graph editing flow in the current source. The lesson is interaction restriction and release, not structural editing or selection state.
Key Code Fragments
This fragment shows that the graph starts with the center layout and all three interaction restrictions already declared in the initial options state.
const [options, setOptions] = useState<RGOptions>({
defaultNodeBorderWidth: 2,
defaultLineColor: '#666',
defaultLineWidth: 2,
defaultNodeShape: RGNodeShape.rect,
defaultLineShape: RGLineShape.StandardCurve,
defaultJunctionPoint: RGJunctionPoint.ltrb,
wheelEventAction: 'none',
dragEventAction: 'none',
disableDragNode: true,
layout: {
layoutName: 'center'
}
});
This fragment shows the flat inline RGJsonData structure that the example loads into the viewer.
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{ id: 'a', text: 'a' }, { id: 'b', text: 'b' }, { id: 'b1', text: 'b1' },
{ id: 'b2', text: 'b2' }, { id: 'b3', text: 'b3' }, { id: 'b4', text: 'b4' },
// ...
],
lines: [
{ id: 'l1', from: 'a', to: 'b' }, { id: 'l2', from: 'b', to: 'b1' },
{ id: 'l3', from: 'b', to: 'b2' }, { id: 'l4', from: 'b', to: 'b3' },
// ...
]
};
This fragment shows that initialization is a one-time load plus viewport normalization, not a repeating rebuild cycle.
const initializeGraph = async () => {
// ...build myJsonData
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
};
useEffect(() => {
initializeGraph();
}, []);
This fragment proves that the example updates live interaction behavior through partial option patches.
const handleUpdateOptions = (newOptions: Partial<RGOptions>) => {
setOptions(prev => ({ ...prev, ...newOptions }));
graphInstance.updateOptions(newOptions);
};
This fragment shows the example-specific control surface for disabling zoom, canvas drag, and node drag.
<SimpleUISwitch
currentValue={options.wheelEventAction === 'none'}
onChange={(disabled) => {
handleUpdateOptions({ wheelEventAction: disabled ? 'none' : 'zoom' });
}}
/>
<SimpleUISwitch
currentValue={options.dragEventAction === 'none'}
onChange={(disabled) => {
handleUpdateOptions({ dragEventAction: disabled ? 'none' : 'move' });
}}
/>
This fragment shows the shared settings overlay mutating the active graph instance directly and exposing screenshot export.
const graphInstance = RGHooks.useGraphInstance();
const { options } = RGHooks.useGraphStore();
<SettingRow
label="Wheel Event:"
options={[
{ label: 'Scroll', value: 'scroll' },
{ label: 'Zoom', value: 'zoom' },
{ label: 'None', value: 'none' },
]}
value={options.wheelEventAction}
onChange={(newValue: string) => { graphInstance.setOptions({ wheelEventAction: newValue }); }}
/>
This fragment shows the export path that temporarily prepares the graph canvas for image generation and then restores it.
const canvasDom = await graphInstance.prepareForImageGeneration();
const imageBlob = await domToImageByModernScreenshot(canvasDom, {
backgroundColor: graphBackgroundColor
});
if (imageBlob) {
downloadBlob(imageBlob, 'my-image-name');
}
await graphInstance.restoreAfterImageGeneration();
What Makes This Example Distinct
The comparison data places this example near drag-and-wheel-event, selections, switch-layout, and zoom, but its teaching goal is narrower. Compared with drag-and-wheel-event, it puts more weight on declaring a locked starting state in the initial RGOptions and on toggling node dragging explicitly, not just on exploring wheel and canvas drag modes from shared controls.
Compared with selections, it uses runtime drag options for the opposite purpose. That neighbor turns drag behavior into marquee selection and selected-state feedback, while this example suppresses interaction until the user chooses to re-enable it.
Compared with switch-layout and zoom, the graph here stays on one stable centered viewer. The runtime updates target interaction permissions on a fixed layout rather than layout playback or preset zoom values.
Its most distinctive combination is a nearly default-styled center-layout hierarchy, initial canvas and node interaction lockdown, three example-level disable switches, and the shared draggable utility window. That makes it a stronger starting point for protected or kiosk-style viewers than for selection, editing, or layout experimentation.
Where Else This Pattern Applies
This pattern fits embedded graph viewers that should not react to accidental mouse input on first render. Typical cases include dashboards, kiosk screens, guided presentations, approval views, training demos, and read-only graph panels inside larger business applications.
It also transfers well to products that need permission-based interaction release. A production screen could start with all movement disabled, then enable zoom or dragging only after a mode switch, a role check, or a user action in surrounding UI, while keeping the same graph data and the same mounted graph instance.