Line Label and Endpoint Editing
This example shows how to select an existing line, edit its label text, drag the label to a new position, and reconnect its endpoints with relation-graph's built-in editing controllers. It also demonstrates selection-state handoff, runtime canvas settings, image export, and toast feedback inside a compact editor-style workspace.
Editing Existing Line Labels and Endpoints with Built-In Controllers
What This Example Builds
This example builds a compact editing workspace for maintaining existing connections in a small graph. The page shows a full-height relation-graph canvas, a floating instruction window, green curved lines, and a dotted background that makes the screen read like an editor rather than a static demo.
Users can click a line to reveal endpoint controls, drag those controls to reconnect the line, double-click the line label to change its text, and drag the label to a new position. The main point of interest is that the example isolates edge maintenance, especially label text and label placement, without expanding into a full node-and-edge authoring tool or path-shaping editor.
How the Data Is Organized
The graph data is declared inline as a single RGJsonData object. It contains a rootId, a flat nodes array with id and text, and a lines array with stable id, text, from, and to fields for each connection.
There is no preprocessing before setJsonData(). The component constructs the dataset inside initializeGraph(), loads it directly into the graph instance on mount, and then calls zoomToFit() so the starting view is immediately usable.
In a production system, the same structure could represent workflow transitions, approval links, dependency edges, or data-lineage relationships where the line label carries business meaning and may need manual correction after the graph is rendered.
How relation-graph Is Used
The example does not configure a custom layout algorithm. It loads a small inline dataset into RelationGraph, relies on the library’s default arrangement for that data, and then fits the viewport with zoomToFit().
The graph options are intentionally narrow: defaultLineShape is set to RGLineShape.StandardCurve and defaultLineColor is set to #00a63e. That keeps the lesson centered on editing behavior instead of on layout or styling complexity.
RGProvider wraps the page so RGHooks.useGraphInstance() can retrieve the active graph instance. That instance is used for setJsonData, zoomToFit, toggleEditingNode, setEditingNodes, setEditingLine, getNodesInSelectionView, clearChecked, and addLines. In the shared floating settings panel, RGHooks.useGraphStore() and setOptions() are used to expose runtime switches for wheel and drag behavior, and the same panel calls prepareForImageGeneration() and restoreAfterImageGeneration() to export the graph as an image.
The actual editing UI is mounted inside RGSlotOnView, not through custom line rendering. RGEditingConnectController provides endpoint handles for the selected line, while RGEditingLineController is mounted with pathEditable={false} and callback hooks for text changes and label dragging. That means path geometry stays fixed, while label editing remains available through the controller behavior used by this example.
The local stylesheet customizes the editor shell rather than the data model. It builds a scale-aware dotted canvas background from relation-graph CSS variables, colors line labels with each line’s current color, and turns the checked line label into a filled badge so the active connection is easy to spot. The shared DraggableWindow and SimpleGlobalMessage utilities add the floating instructions, settings overlay, export action, and toast-style edit feedback around the graph.
Key Interactions
- Clicking a line makes that line the active editing target and exposes the built-in endpoint and label editing controls.
- Double-clicking a line label starts inline text editing, and completing the edit triggers a success toast with the updated text.
- Dragging a line label changes its position and triggers a warning toast when the drag ends.
- Dragging an endpoint handle reconnects the selected line, and the example persists the emitted
lineJsonback into the graph throughonLineBeCreated. - Clicking a node without modifiers replaces the editing-node set with that node, while
Shift,Ctrl, orMetaclicks toggle membership in the current editing-node set. - Drag-box selection converts the selection rectangle into a node set by calling
getNodesInSelectionView(...). - Clicking empty canvas space clears editing nodes, clears the active editing line, and removes checked-state highlighting.
- Opening the floating settings panel lets the user switch wheel behavior, switch canvas drag behavior, and download an image of the current graph.
Key Code Fragments
This fragment shows that the example uses a small inline RGJsonData dataset with explicit line labels.
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' },
// ... more nodes ...
],
This fragment shows the direct load path with no preprocessing step between data creation and graph rendering.
// setJsonData is async
await graphInstance.setJsonData(myJsonData);
graphInstance.zoomToFit();
This fragment shows how node clicks feed the editing-node state while also clearing any previously active editing line.
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 how drag-box selection is converted into the next editing-node set.
const onCanvasSelectionEnd = (selectionView: RGSelectionView) => {
const willSelectedNodes = graphInstance.getNodesInSelectionView(selectionView) || [];
graphInstance.setEditingNodes(willSelectedNodes);
};
This fragment shows that endpoint edits are persisted through the line-creation callback because endpoint changes emit a recreated line payload.
const onLineBeCreated = (lineInfo: { lineJson: JsonLine }) => {
graphInstance.addLines([lineInfo.lineJson]);
};
This fragment shows that label editing and label dragging are treated as separate interaction outcomes with separate feedback hooks.
const onLineTextChanged = (line: RGLine) => {
SimpleGlobalMessage.success('Line Text Changed:' + line.text);
};
const onLineTextDragEnd = (line: RGLine) => {
SimpleGlobalMessage.warning('Line Text Drag End:' + line.text);
};
This fragment shows the exact overlay configuration: endpoint editing is enabled, path editing is disabled, and line-label callbacks are attached.
<RGSlotOnView>
<RGEditingConnectController />
<RGEditingLineController
pathEditable={false}
onLineTextChanged={onLineTextChanged}
onLineTextDragEnd={onLineTextDragEnd}
/>
</RGSlotOnView>
This fragment shows the stylesheet that creates the dotted editor surface and the checked-line label highlight.
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 places this example in the same family as change-line-vertices, change-line-path, and customize-line-toolbar, but its emphasis is narrower. Compared with change-line-vertices, it keeps the same selected-line editing flow while going beyond endpoint-only maintenance by adding inline label editing and draggable label placement. Compared with change-line-path, it keeps pathEditable={false} and makes the line label, not the route geometry, the primary editable surface.
It also stands out inside the editor-style VIP examples because it combines several rare features in one compact workspace: a floating instruction and settings window, selection-driven handoff between nodes and one active line, built-in endpoint controls, inline label editing, drag-to-reposition label text, and separate toast feedback for label changes versus label dragging. That combination makes it a practical starting point when a team needs existing-edge maintenance without moving to a broader workflow editor.
The comparison file also sets clear boundaries for what this example is not. It is not a custom line-toolbar demo, not a node-driven line-creation example, and not a path-editing example. Its distinct value is direct maintenance of an already existing line’s text, text position, and endpoints through built-in relation-graph controllers.
Where Else This Pattern Applies
This pattern transfers well to workflow or approval tools where connection labels describe conditions, responsibilities, or transition names and those labels need occasional correction after the graph is already laid out. It also fits dependency maps and data-lineage views where users need to reconnect a relationship or move an overlapping label without editing the entire graph structure.
A second extension is lightweight maintenance tooling. Teams can reuse the same selected-line workflow to persist label edits to a backend, audit endpoint changes, or gate reconnection with domain rules, while still avoiding the complexity of a full graph-authoring surface.