JavaScript is required

Line Shapes, Junctions, and Custom Arrows

This example builds a center-layout reference graph that compares many built-in line behaviors at once, including shape, width, junction anchors, arrow visibility, text placement, and custom marker-based arrows. It keeps the graph data static, adds CSS-based label styling and a dark-theme switch, and includes helper controls for canvas interaction modes and image export.

Line Shapes, Junction Anchors, and Custom Arrows in One Reference Graph

What This Example Builds

This example builds a full-height relation-graph canvas that works as a visual reference board for line rendering. The viewer sees one prepared center-layout graph with generic lettered nodes and many annotated connections that compare line width, line shape, junction points, arrow visibility, text placement, and color treatment in one scene.

Users do not edit the graph structure, but they can inspect the prepared comparison board, toggle a dark theme, open the floating settings panel, change wheel and drag behavior, and export the canvas as an image. The main point is breadth: the example shows many built-in line options at the same time, then extends them with CSS label styling and custom SVG arrow markers.

How the Data Is Organized

The graph data is declared inline inside initializeGraph() as one RGJsonData object with rootId: 'a', 22 nodes, and 28 lines. There is no preprocessing step before setJsonData(). The example constructs the final dataset directly in code and loads it as-is.

Most of the meaning lives in the lines array. Each edge record can carry its own lineShape, lineWidth, color, fontColor, showStartArrow, showEndArrow, startMarkerId, endMarkerId, fromJunctionPoint, toJunctionPoint, useTextOnPath, and className. The node data is mostly placeholder content used to hold the comparison layout, although a few nodes override size, shape, or fixed position. In a real product, the same structure could represent workflow branches, integration routes, lineage edges, dependency links, or annotated network paths where each connection needs its own rendering rules.

How relation-graph Is Used

index.tsx wraps the demo in RGProvider, and MyGraph.tsx retrieves the active instance through RGHooks.useGraphInstance(). The graph uses the built-in center layout with explicit levelGaps, circular node defaults, a 60x60 default node size, and a white default node color.

The graph loads once on mount. initializeGraph() calls setJsonData(), then moveToCenter() and zoomToFit() so the prepared gallery is immediately visible. The example does not use node slots, line slots, canvas slots, or editing APIs. Instead, it pushes most variation into built-in line metadata fields.

The example also layers two non-data customization techniques on top of the built-in renderer. MyLineArrowDefine injects SVG <marker> definitions so selected lines can use custom start and end arrowheads by marker id. The local SCSS file styles built-in line labels through per-line classes such as .my-text-bg-001 through .my-text-bg-004, and the wrapper class switches to .my-graph-dark when the checkbox is enabled to restyle the canvas, line text, nodes, and toolbar.

The floating helper window comes from a shared local component, but it is part of the rendered example. That helper uses RGHooks.useGraphStore() to read the current interaction modes, graphInstance.setOptions() to switch wheel and drag behavior, and prepareForImageGeneration() plus restoreAfterImageGeneration() to export the current graph view as an image.

Key Interactions

The most visible interaction is the local dark-theme toggle in the floating description window. It does not change the graph data, but it changes how the same line styles read against light and dark backgrounds.

The settings panel inside the floating helper window adds operational controls around the graph. Users can switch the wheel event between scrolling and zooming, switch canvas dragging between selection and movement, and download an image of the current canvas. Those controls affect the viewing environment rather than the graph structure.

The description window itself can be dragged, minimized, and reopened through its built-in helper controls. Node and line clicks are wired, but they only log objects to the console, so they are inspection hooks rather than a meaningful end-user workflow.

Key Code Fragments

This fragment shows that the overall scene uses relation-graph’s built-in center layout and default node options.

const graphOptions: RGOptions = {
    defaultNodeShape: RGNodeShape.circle,
    defaultNodeBorderWidth: 1,
    defaultNodeWidth: 60,
    defaultNodeHeight: 60,
    defaultNodeColor: '#ffffff',
    layout: {
        layoutName: 'center',
        levelGaps: [300, 200, 200]
    }
};

This fragment shows that most of the visible variation is expressed directly in line records.

{ id: 'line-2', from: 'a', to: 'c', text: 'useTextOnPath Line 1', useTextOnPath: true, fontSize: 10, color: 'rgba(30, 144, 255, 1)' },
{ id: 'line-5', from: 'a', to: 'd', text: 'Thick Line', lineWidth: 3 },
{ id: 'line-6', from: 'a', to: 'e', text: 'Hide Arrow', showEndArrow: false },
{ id: 'line-11', from: 'a', to: 'd', text: 'Polyline', lineShape: RGLineShape.StandardOrthogonal, fromJunctionPoint: RGJunctionPoint.left, toJunctionPoint: RGJunctionPoint.top, className: 'my-text-bg-001' },

This fragment shows how selected lines attach custom marker ids instead of relying only on default arrows.

{ id: 'line-18', from: 'c', to: 'm1', text: 'RGJunctionPoint.bottom', endMarkerId: 'my-arrow-001', startMarkerId: 'my-arrow-001-start', showStartArrow: true, lineShape: RGLineShape.StandardCurve, toJunctionPoint: RGJunctionPoint.bottom, lineWidth: 6, color: '#00ced1' },
{ id: 'line-19', from: 'c', to: 'm2', text: 'Custom Line Arrow', endMarkerId: 'my-arrow-001', startMarkerId: 'my-arrow-001-start', showStartArrow: true, lineShape: RGLineShape.StandardCurve, fromJunctionPoint: RGJunctionPoint.border, lineWidth: 7, color: '#00ced1' },

This fragment shows the hidden SVG definitions that make those custom marker ids available to the graph renderer.

<svg className="absolute opacity-0" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <marker id="my-arrow-001" markerWidth="80" markerHeight="80" refX="2" refY="3"
            markerUnits="userSpaceOnUse" orient="auto" viewBox="0 0 12 12">
            <path d="M 4 6, V 0, L 0 3, Z" style={{ fill: 'context-stroke' }}></path>
        </marker>
        <marker id="my-arrow-001-start" markerWidth="80" markerHeight="80" refX="2" refY="3"
            markerUnits="userSpaceOnUse" orient="auto-start-reverse" viewBox="0 0 12 12">
            <path d="M 4 6, V 0, L 0 3, Z" style={{ fill: 'context-stroke' }}></path>
        </marker>
    </defs>
</svg>

This fragment shows that label presentation is also customized through CSS classes and a dark-theme wrapper.

.my-text-bg-003 {
    .rg-line-label {
        background-color: rgb(13, 179, 1);
        color: #ffffff;
        border-radius: 20px;
        padding: 3px 10px;
    }
}

.my-graph-dark {
    .relation-graph {
        .rg-map {
            background-color: #333;
        }
    }
}

This fragment shows that the shared helper window changes graph interaction modes through relation-graph APIs.

<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 }); }}
/>

What Makes This Example Distinct

The comparison data shows that this example stands out because one static center-layout graph gathers many built-in line behaviors in one place: mixed line shapes, explicit junction anchors, width changes, hidden or reversed arrows, text-on-path labels, custom marker ids, and per-line label classes. Its distinct value is not that any one technique is exclusive, but that the example combines so many of them in one prepared reference board.

Compared with advanced-line-usage, this example is broader and denser. Both demos use inline data and console-only click handlers, but line adds more visible variants, custom SVG marker definitions, a dark-theme toggle, and the floating utility window. Compared with custom-line-style, the difference is method: custom-line-style emphasizes runtime batch restyling, while this example keeps most variation visible simultaneously through per-edge data and CSS classes loaded from the start.

Compared with line-style1 and layout-center, this example is less about one narrow preset family or whole-graph presentation controls and more about using one prepared dataset as a broad edge-behavior gallery. That makes it a strong starting point when a team wants to compare built-in line capabilities before moving into custom line slots or a full editor.

Where Else This Pattern Applies

This pattern transfers well to product areas where the connection itself carries multiple meanings. A team can adapt it into a QA board for workflow branches, dependency directions, network routes, integration links, or lineage paths, with each edge using different width, arrow, anchor, or label rules to represent status or semantics.

It also works as internal documentation. Before designing custom renderers, a team can build a compact reference graph like this to decide which requirements are already covered by relation-graph’s built-in line fields, CSS theming, and injected SVG markers. In training material, the same structure can serve as a reusable visual catalog for edge configuration options.