Node Drag Alignment Guides
This example shows how to mount relation-graph's alignment-guide overlay so dragged nodes can display temporary reference lines. It also combines an optional adsorption toggle, selection-state coordination, runtime canvas settings, and image export inside a compact editor-style workspace.
Dragging Nodes with Alignment Guides and Optional Snapping
What This Example Builds
This example builds a compact graph editing workspace that shows temporary alignment guides while a node is being dragged. The screen combines a full-height dotted canvas, a floating instruction window, a small inline graph, and a checkbox that turns the alignment helper’s adsorption behavior on or off at runtime.
Users can drag nodes, click nodes and lines to change the current editing target, clear editing state by clicking empty canvas space, and, when the canvas drag mode is set to selection, replace the current editing-node set with a selection rectangle. The main point of the demo is not general graph authoring. It is a focused reference for drag-time placement guidance with just enough surrounding selection logic to make that overlay practical.
How the Data Is Organized
The graph data is declared inline inside initializeGraph() as one RGJsonData object. It uses a single rootId, a flat nodes array with id and text, and a lines array with id, from, and to. Most lines inherit the default graph options, while one line overrides its shape and junction points directly in the dataset.
There is no preprocessing pipeline before relation-graph receives the data. The component creates the dataset, calls setJsonData(...), and immediately follows with zoomToFit(). That keeps the example centered on runtime interaction instead of on data transformation.
In a production system, the same structure could represent workflow steps, topology elements, dependency items, or diagram blocks that users may need to reposition precisely after the graph is already rendered.
How relation-graph Is Used
The example does not introduce a custom layout algorithm. It relies on relation-graph’s normal rendering behavior for a small root-based dataset, then fits the initial viewport after loading.
The graph options are intentionally narrow and support the visual baseline of the demo: defaultLineShape is RGLineShape.StandardCurve, defaultJunctionPoint is RGJunctionPoint.ltrb, and defaultLineColor is #00a63e. That keeps the example’s attention on drag behavior instead of layout configuration.
RGProvider wraps the page so RGHooks.useGraphInstance() can control loading, viewport fitting, editing-node state, editing-line state, checked state, and selection queries. The floating settings panel also uses RGHooks.useGraphStore() so it can read the current wheel and drag modes and update them with setOptions(...).
The key graph-specific UI is mounted through RGSlotOnView. Instead of replacing nodes or lines with custom renderers, the example adds RGEditingReferenceLine into the view layer and passes adsorption={adsorption} so alignment guidance can react to the current checkbox state. Around that overlay, RelationGraph binds four handlers: node click, line click, canvas selection end, and canvas click.
The surrounding helper UI is small but relevant. SimpleUIBoolean exposes the snapping-related toggle, and the shared DraggableWindow can open a settings panel for wheelEventAction, dragEventAction, and image export. The local SCSS finishes the editor feel by drawing a scale-aware dotted canvas background from relation-graph canvas variables and by making checked line labels invert against the line color.
Key Interactions
- Dragging a node can show alignment reference lines through
RGEditingReferenceLine, and the checkbox lets the user enable or disable the overlay’s adsorption behavior at runtime. - Clicking a node without modifiers replaces the editing-node set with that node. Clicking with
Shift,Ctrl, orMetawithoutAlttoggles the clicked node in the current editing set. - Clicking a line sets that line as the active editing line, even though this example does not add a separate custom line-edit controller.
- When the canvas is in selection mode,
onCanvasSelectionEndconverts the dragged selection region into node objects and replaces the current editing-node set with those results. - Clicking empty canvas space clears editing nodes, clears the active editing line, and removes checked-state highlighting.
- The floating window can be dragged, minimized, switched into a settings panel, and used to export the current graph as an image.
Key Code Fragments
This fragment shows the narrow option set that establishes the default curve style, junction behavior, and line color for the whole graph.
const graphOptions: RGOptions = {
defaultLineShape: RGLineShape.StandardCurve,
defaultJunctionPoint: RGJunctionPoint.ltrb,
defaultLineColor: '#00a63e'
};
This fragment shows that the graph data is created inline and loaded directly at mount time.
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{ id: 'a', text: 'Border color' },
{ id: 'a1', text: 'No border' },
{ id: 'a2', text: 'Plain' },
{ id: 'a1-1', text: 'Text Node' }
]
};
This fragment shows the mount-time handoff into relation-graph and the immediate viewport fit.
// setJsonData is async
await graphInstance.setJsonData(myJsonData);
graphInstance.zoomToFit();
This fragment shows how plain click and modifier click both feed the same editing-node model.
const onNodeClick = (nodeObject: RGNode, $event: RGUserEvent) => {
if ($event.shiftKey || $event.ctrlKey || ($event.metaKey && !$event.altKey)) {
graphInstance.toggleEditingNode(nodeObject);
} else {
graphInstance.setEditingNodes([nodeObject]);
}
graphInstance.setEditingLine(null);
};
This fragment shows that selection-box completion is delegated to relation-graph instead of custom hit testing.
const onCanvasSelectionEnd = (selectionView: RGSelectionView) => {
const willSelectedNodes = graphInstance.getNodesInSelectionView(selectionView) || [];
// 3.x recommends directly setting editing node set, not recommended to manually modify node.selected
graphInstance.setEditingNodes(willSelectedNodes);
};
This fragment shows the exact view-layer overlay that makes drag-time alignment guidance visible and runtime-configurable.
<DraggableWindow>
When dragging a node, it will look for a position close to the dragged node and display alignment reference lines.
<br />
You can set whether to enable adsorption effect.
<SimpleUIBoolean currentValue={adsorption} onChange={setAdsorption} label="Enable Adsorption Effect" />
</DraggableWindow>
This fragment shows where the alignment-guide component is mounted in the graph view layer.
<RGSlotOnView>
{/* Node alignment reference line when dragging */}
<RGEditingReferenceLine adsorption={adsorption} />
</RGSlotOnView>
This fragment shows that the shared floating panel also exposes runtime canvas-mode switches and 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 }); }}
/>
This fragment shows the SCSS that turns the graph into a dotted editing surface that stays aligned with relation-graph’s canvas transforms.
background-position: var(--rg-canvas-offset-x) var(--rg-canvas-offset-y);
background-size: calc(var(--rg-canvas-scale) * 15px) calc(var(--rg-canvas-scale) * 15px);
background-image: radial-gradient(
circle,
rgb(197, 197, 197) calc(var(--rg-canvas-scale) * 1px),
transparent 0
);
What Makes This Example Distinct
The comparison data places this example near gee-node-resize, batch-operations-on-nodes, canvas-selection, change-line-path, and line-vertex-on-node, all of which reuse parts of the same dotted-canvas and floating-window editing scaffold. What separates this one is the lesson it isolates: view-layer alignment guidance during node dragging, with a runtime adsorption toggle, instead of resize handles, batch mutation commands, selection instrumentation, line-path editing, or connection creation.
Its other distinctive strength is the way that several editing-state inputs are coordinated around that one overlay. Node clicks, modifier-based multi-selection, line clicks, selection-box completion, and blank-canvas clearing all feed a shared editing model that the alignment workflow can live inside. That makes it a better starting point than the broader neighbors when the goal is to add placement assistance to an existing editor without also adopting a much larger mutation surface.
The comparison data also puts a useful boundary on the claim. This is not a full authoring demo, and the selection rectangle is not the main feature. The durable pattern here is drag-time positioning assistance with lightweight selection management around it.
Where Else This Pattern Applies
This pattern transfers well to workflow builders, topology editors, process designers, and diagramming tools where users frequently drag existing nodes and need help lining them up without switching to a separate layout step. The same overlay-and-toggle approach can also help teams retrofit optional snapping into an existing graph workspace without rebuilding the rest of the editor.
It is also useful for cleanup tools that mix auto-layout with final manual adjustment. After the graph is generated from backend data, operators can make precise visual corrections while keeping the graph model intact and using the same selection-handling APIs for related editing features.