Selected Node Line Creation With Target Endpoint Selection
This example shows a compact graph authoring workflow where selecting one node reveals directional chips for launching a new outgoing connection. It combines a custom around-node toolbar with relation-graph's built-in connect overlay, so users can start from a preset source side and then choose where the new line attaches on the target node before it is saved.
Selected-Node Line Creation With Target Endpoint Selection
What This Example Builds
This example builds a compact connection-authoring workspace on top of a small seeded graph. The page uses a full-height dotted canvas, a floating helper window, and a custom around-node toolbar that only appears when exactly one node is in editing state.
Users can click nodes, adjust selection with modifier keys, clear the canvas state, and launch a new outgoing line from directional chips above, below, left, or right of the selected node. The main lesson is that the flow does not stop at choosing a destination node: the demo also mounts relation-graph’s built-in connect overlay so the user can choose where the new line lands on the target node.
How the Data Is Organized
The graph data is assembled inline inside initializeGraph() as one RGJsonData object with a rootId, a flat nodes array, and a flat lines array. The seed dataset is small and literal, so it is easy to replace with business entities such as workflow steps, services, approvals, or dependency items.
There is no preprocessing step before setJsonData(...) beyond building that JSON object in code. A mount-time effect loads the data and immediately calls zoomToFit(). New connections are not stored in a separate draft model either; once the create-line callback resolves to a valid target node, the example appends the new edge directly through addLines(...).
How relation-graph Is Used
The entry component wraps the demo in RGProvider, and MyGraph uses RGHooks.useGraphInstance() as the central control surface. That instance loads the graph, fits the viewport, updates editing-node and editing-line state, launches the line-creation gesture, generates ids, appends accepted lines, clears checked state, and supports the floating settings and export utilities.
The example does not define a custom layout object. It relies on relation-graph’s normal handling of the inline dataset and then frames the result with zoomToFit().
RelationGraph is configured with showToolBar: false, so the page replaces the built-in toolbar with its own editing shell. The component registers handlers for node clicks, line clicks, canvas clicks, and selection-box completion, and those handlers all feed the same editing-state model.
The overlay structure is the key relation-graph pattern. RGSlotOnView mounts RGEditingNodeController for the custom MyNodeToolbar, and it also mounts RGEditingConnectController so the runtime can expose target-side attachment picking during the same gesture. The custom toolbar uses RGHooks.useEditingNodes() to enforce single-node gating, then passes preset JsonLineLike templates into startCreatingLinePlot(...) with color, width, RGLineShape.StandardCurve, and side-specific fromJunctionPoint values.
The floating DraggableWindow is shared scaffolding, but it still demonstrates useful integration points. Its settings panel reads live canvas mode values through RGHooks.useGraphStore(), applies mode changes through setOptions(...), and exports the graph with prepareForImageGeneration(), getOptions(), restoreAfterImageGeneration(), and the modern-screenshot helper. The local stylesheet adds the dotted work-surface background and makes checked line labels inherit the active line color.
Key Interactions
- Clicking a node without modifiers replaces the editing-node set with that node and clears the active editing line.
- Clicking a node with
Shift,Ctrl, or supportedMetabehavior toggles that node into or out of the editing selection. - When the canvas is in selection mode, finishing a drag-box selection resolves the nodes inside that region and replaces the editing-node collection with them.
- Clicking empty canvas clears editing nodes, clears the active editing line, and resets checked state.
- Clicking a line marks that line as the current editing line.
- When exactly one node is selected, small chips appear around that node and launch
startCreatingLinePlot(...)with top, bottom, left, or right source presets. - The line-creation flow only persists a new edge when the chosen target exposes an
id; otherwise the callback ignores the result. - The floating helper window can be dragged, minimized, expanded into a settings panel, and used to change wheel or drag behavior or download an image.
Key Code Fragments
This fragment shows the inline seed dataset and the mount-time load path.
const initializeGraph = async () => {
const myJsonData: RGJsonData = {
rootId: 'a',
nodes: [
{ id: 'a', text: 'Border color' },
{ id: 'a1', text: 'No border' },
// ...
],
lines: [
{ id: 'l1', from: 'a', to: 'b' },
// ...
]
};
await graphInstance.setJsonData(myJsonData);
graphInstance.zoomToFit();
};
This fragment shows how click-based and box-based selection converge on 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);
};
const onCanvasSelectionEnd = (selectionView: RGSelectionView) => {
const willSelectedNodes = graphInstance.getNodesInSelectionView(selectionView) || [];
graphInstance.setEditingNodes(willSelectedNodes);
};
This fragment shows that the example delegates the interactive drag to relation-graph and only saves accepted node targets.
graphInstance.startCreatingLinePlot(e.nativeEvent, {
template: lineTemplate,
fromNode: fromNode,
onCreateLine: (fromNode, toNode, newLineJson) => {
if (toNode.id) {
const newLineId = graphInstance.generateNewUUID(8);
const newLineJsonData = Object.assign({}, newLineJson, {
from: fromNode.id,
to: toNode.id,
text: 'New Line ' + newLineId
});
graphInstance.addLines([newLineJsonData]);
}
}
});
This fragment shows how the demo combines a custom around-node overlay with relation-graph’s built-in target attachment overlay.
<RGSlotOnView>
<RGEditingNodeController>
<MyNodeToolbar onStartCreateLine={onStartCreateLine} />
</RGEditingNodeController>
{/* Node connection point selector component */}
<RGEditingConnectController />
</RGSlotOnView>
This fragment shows the single-node gate and the source-side preset injected by one toolbar button.
const editingNodes = RGHooks.useEditingNodes();
const onlyOneNodeBeSelected = editingNodes.nodes.length === 1;
return onlyOneNodeBeSelected ? (
<div onClick={(e) => {
onStartCreateLine(editingNodes.nodes[0], {
lineWidth: 3,
color: '#e85f84',
fromJunctionPoint: RGJunctionPoint.top,
lineShape: RGLineShape.StandardCurve,
text: 'New Line'
}, e);
}}>T1</div>
) : null;
This fragment shows the stylesheet override that turns the canvas into an editor-like surface and highlights checked line labels with the line color.
.relation-graph {
--rg-canvas-scale: 1;
--rg-canvas-offset-x: 0px;
--rg-canvas-offset-y: 0px;
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);
}
.rg-line-peel.rg-line-checked .rg-line-label {
background-color: var(--rg-line-color);
color: #fff;
}
What Makes This Example Distinct
The comparison data makes the main distinction clear: this is not just a selected-node quick-create demo. Compared with create-line-from-node, it keeps the same contextual toolbar pattern but adds RGEditingConnectController, so the gesture includes target-side attachment choice instead of stopping at a simpler node-to-node connection.
It also differs from nearby line-editing examples such as change-line-vertices and change-line-path. Those examples use connect overlays while editing existing edges, but this one uses the overlay during new-edge authoring. The user starts from a selected node, launches a preset outgoing line, and then decides how that new edge should land on the destination.
Compared with batch-operations-on-nodes, the editing-node overlay is intentionally narrower. Modifier-based multi-select and selection-box handoff still exist, but the visible controls are deliberately limited to the single-node case, which makes the example a focused connection-authoring micro-editor rather than a broader node-maintenance tool.
Where Else This Pattern Applies
This pattern can be adapted to workflow builders where each step should expose approved outgoing transitions from specific sides of the node and where destination attachment geometry affects readability.
It also fits service-topology editors, dependency maps, approval routing tools, and knowledge-graph curation screens when users need a fast “connect from selected item” action without opening a separate form.
The same structure can be extended in internal tools that need constrained graph authoring: keep the contextual launcher, preserve the built-in target attachment picker, and replace the inline seed data with domain records from a backend or editor state store.