Patterned Tape Line Rendering
This example replaces default relation-graph edges with filled tape-like SVG ribbons and lets the user switch those ribbons between translucent color and multiple static or animated pattern fills. It also updates existing nodes between circle and rectangle shapes at runtime, keeps line clicks wired into relation-graph, and includes shared canvas settings plus image export.
Tape-Style Line Rendering with Pattern Switching and Live Node Shape Updates
What This Example Builds
This example builds a small center-layout topology viewer whose edges are no longer drawn as ordinary strokes. Each relation is rendered as a filled tape-like SVG area, so the graph looks more like layered bands on a dark technical canvas than a default node-link diagram.
Users can switch the line fill between a translucent color and multiple SVG patterns, change all existing nodes between circular and rectangular shapes, open the shared canvas settings panel, and export the graph as an image. The key idea is that the line surface is fully customized, but line clicks still go through relation-graph’s normal interaction pipeline.
How the Data Is Organized
The dataset is declared inline as RGJsonData inside initializeGraph. It uses rootId: '2', nine nodes, and eight lines, with each line represented in the standard relation-graph format of from, to, and text. The payload is intentionally small and static so the example can focus on rendering behavior instead of data loading.
There is no business-data preprocessing before setJsonData. The special processing happens during rendering: for each visible line, the example computes a closed four-point area path from the source and target node geometry. In a real system, the same structure could represent subsystem dependencies, equipment links, process connections, or network topology segments, while the ribbon fill could encode category, status, or traffic style.
How relation-graph Is Used
RGProvider wraps the demo so relation-graph hooks can resolve the current graph instance. RelationGraph receives options that keep the presentation simple and consistent: a center layout, border junction points, a default blue line color, white node color, zero node border width, and a defaultNodeShape that is bound to React state. On mount, setJsonData, moveToCenter, and zoomToFit load and frame the graph.
The main extension point is RGSlotOnLine. Instead of using the built-in edge renderer, the example passes each line into MyLineContent, where RGHooks.useGraphInstance() is used again to access relation-graph APIs. That component computes the custom ribbon path from the live from and to nodes, keeps relation-graph line state such as checked and selected, and forwards clicks with graphInstance.onLineClick(...).
The runtime styling path is split between React state, SVG defs, and SCSS. fillStyleId is written to the --rg-line-fill-style CSS variable on the outer graph container, MySvgDefs defines the available static and animated patterns, and my-relation-graph.scss applies the selected fill to .rg-line, removes the normal stroke, adds a checked outline, and uses blend mode plus hover brightness to make the bands feel like translucent tape. The same stylesheet also creates the dark grid background and the magenta node treatment.
The example is a viewer rather than an editor. It does not let users add or rewire graph data, but it does mutate presentation state at runtime. When the node-shape selector changes, the graph instance iterates over existing nodes and calls updateNode so already-rendered nodes switch shape immediately. The shared DraggableWindow component also exposes a canvas settings panel driven by RGHooks.useGraphStore(), where wheel mode, drag mode, and image export are handled through relation-graph instance APIs.
Key Interactions
- Clicking a custom ribbon line still triggers relation-graph’s line-click handling because the custom
<path>stops propagation and forwards the native event throughgraphInstance.onLineClick(...). - The
Line Fill Styleselector swaps the fill between a translucent solid color and named SVG pattern ids such as dots, stripes, circuit, lava, arrows, and rainbow. - The
Node Shapeselector updates all current nodes from circle to rectangle, or back again, by iterating the live node collection and callingupdateNode. - The floating window can be dragged and toggled into a shared settings panel.
- The settings panel changes wheel behavior, changes canvas drag behavior, and downloads an image after
prepareForImageGeneration()andrestoreAfterImageGeneration().
Key Code Fragments
This block shows that the viewer uses a center layout and binds the default node shape to React state.
const graphOptions: RGOptions = {
defaultNodeShape: nodeShape,
defaultJunctionPoint: RGJunctionPoint.border,
defaultLineColor: '#2E74B5',
defaultNodeColor: '#ffffff',
defaultNodeBorderWidth: 0,
layout: {
layoutName: 'center'
}
};
This block shows the inline topology data before it is loaded into relation-graph.
const myJsonData: RGJsonData = {
rootId: '2',
nodes: [
{ id: '2', text: 'ALTXX' },
{ id: '3', text: 'CH2 TTN' },
// ...
],
lines: [
{ from: '2', to: '5', text: 'Subsystem' },
{ from: '2', to: '3', text: 'Subsystem' },
// ...
]
};
This block shows the initial graph load and the post-load viewport framing.
await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();
This block shows how the node-shape selector affects nodes that are already on the canvas.
const updateGraphOptions = () => {
graphInstance.getNodes().forEach(node => {
graphInstance.updateNode(node, {
nodeShape
});
});
};
This block shows the slot override that replaces every built-in line with MyLineContent.
<RelationGraph options={graphOptions}>
<RGSlotOnLine>
{({ lineConfig, checked }: RGLineSlotProps) => (
<MyLineContent lineConfig={lineConfig} checked={checked} />
)}
</RGSlotOnLine>
</RelationGraph>
This block shows the custom line component computing a ribbon path and forwarding clicks back into relation-graph.
const onLineClick = (e: React.MouseEvent | React.TouchEvent) => {
e.stopPropagation();
graphInstance.onLineClick(line, e.nativeEvent as RGUserEvent);
};
const path = generateLinePathAsSimpleArea(
lineConfig.from,
lineConfig.to
);
This block shows the helper turning opposite-side support points into one closed SVG area.
const side1 = findStartXyAndEndXy(fromNode, toNode, false);
const side2 = findStartXyAndEndXy(fromNode, toNode, true);
return `M ${ax} ${ay}
L ${cx} ${cy}
L ${dx_point} ${dy_point}
L ${bx} ${by}
Z`;
This block shows how the shared settings panel uses relation-graph APIs to export the graph image.
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 in the same family as customer-line1, adv-line-slot, adv-line-slot-1, custom-line-style, and custom-line-animation, but with a narrower and more geometry-driven focus. Its most distinctive trait is the combination of RGSlotOnLine, a closed area-path helper, CSS-variable-driven fill switching, and a library of static and animated SVG patterns. That makes it a strong reference when the goal is to replace the visible edge surface itself instead of only restyling built-in strokes.
Compared with customer-line1, this example goes further on live graph mutation because it adds graph-wide node-shape switching and uses a centered topology view rather than a fixed tree presentation. Compared with adv-line-slot and adv-line-slot-1, it is less about annotating or animating relation-graph’s native line primitives and more about turning each connection into a reusable filled band. Compared with custom-line-style and custom-line-animation, it changes line appearance through slot-based geometry replacement rather than CSS retheming of the built-in line renderer.
The rarity data also supports a conservative stronger claim: the mix of a dark neon canvas, pattern-filled ribbon lines, click-preserving custom paths, a node-shape toggle, and the shared canvas/export panel is uncommon across the example set. It is not presented as the only line-slot demo, but it is a notably concentrated reference for ribbon-style edge rendering.
Where Else This Pattern Applies
This pattern transfers well to topology viewers, subsystem maps, industrial process diagrams, network route views, and dependency visualizations where the connection itself needs to carry visual meaning. The same approach can be extended to severity bands, direction-coded transport channels, branded edge skins, or themed monitoring dashboards that need multiple line treatments from one renderer without changing the underlying graph data model.