JavaScript is required

Graph Canvas Theme Switcher

This example renders a small left-to-right tree and switches among three full-canvas visual themes by changing a wrapper class. It shows how to skin relation-graph's built-in map, toolbar, nodes, and checked states with SCSS while keeping the same data, layout, and graph instance. A shared floating panel also exposes wheel mode, drag mode, and image export utilities.

Switching Relation Graph Canvas Themes with One Wrapper Class

What This Example Builds

This example renders a small left-to-right tree and lets the user switch the entire graph presentation among three visual themes at runtime. The graph data and the RelationGraph renderer stay the same, but the outer wrapper class changes from my-graph-theme-1 to my-graph-theme-3, which restyles the map background, toolbar, nodes, and checked-state surfaces.

The screen is a full-height viewer with a floating utility window above the canvas. Users can drag that window, minimize it, open a settings overlay, change the active theme, adjust wheel and canvas-drag behavior through the shared settings panel, and download the current graph as an image.

The most important idea is that this is a CSS skinning pattern, not a custom rendering pattern. The example keeps a standard tree graph and uses SCSS selectors against relation-graph’s built-in DOM structure to create very different visual moods.

How the Data Is Organized

The data is declared inline inside initializeGraph() as an RGJsonData object. It uses one rootId, a flat nodes array with id and text, and a flat lines array with explicit id, from, and to fields.

There is no preprocessing step before layout. The code sends the JSON directly to graphInstance.setJsonData(), then recenters and fits the result with moveToCenter() and zoomToFit().

This structure is easy to replace with real business data. The same shape could represent an organization tree, a service dependency hierarchy, a category tree, a team ownership map, or an approval chain where each node only needs a label and each edge only needs a source and target.

How relation-graph Is Used

index.tsx wraps the demo in RGProvider, so both the main graph component and the shared helper window can resolve the active graph context. Inside MyGraph.tsx, RelationGraph is rendered once with a compact graphOptions object and no custom node slots.

The layout is a built-in tree layout that grows from left to right, with treeNodeGapH: 200 and treeNodeGapV: 10. The base options intentionally keep the node and line styling neutral: nodes are rectangular, transparent, and lightly bordered; lines use a standard curve shape with left-right junction points; and the toolbar is placed horizontally at the bottom center. That combination leaves room for the imported theme files to define most of the visible chrome.

The example uses RGHooks.useGraphInstance() in two places. In MyGraph, it loads the static JSON data and then recenters and fits the graph on mount. In the shared CanvasSettingsPanel, it updates runtime options such as wheelEventAction and dragEventAction, and it runs the image export flow through prepareForImageGeneration() and restoreAfterImageGeneration().

Styling is the real focus. Each imported SCSS file targets relation-graph selectors such as .rg-map, .rg-toolbar, .rg-node, .rg-node-peel.rg-node-checked, and .rg-line. Because the wrapper class changes at the top level, the same graph instance can switch among a radial gradient glass theme, an animated multicolor theme, and an animated diagonal gradient theme without changing the dataset or rebuilding node content.

Key Interactions

The main interaction is theme switching. Clicking one of the three SimpleUISelect items updates React state, which replaces the wrapper class and immediately reskins the graph.

The floating helper window is also interactive. It can be dragged around the page, minimized, and expanded again, which keeps the graph itself uncluttered while leaving controls available.

The settings button opens the shared CanvasSettingsPanel. From there, users can switch the mouse wheel between scroll, zoom, and none; switch canvas dragging between selection, move, and none; and download the currently styled canvas as an image. Those controls are generic helper behavior reused across demos, but they are available in this example and affect the live graph instance.

The theme styles also define checked-state overrides for nodes and lines. The example does not add custom selection logic, but built-in checked visuals can still inherit the active theme styles when relation-graph applies those classes.

Key Code Fragments

This options block shows that the graph keeps a simple tree configuration and leaves much of the final appearance to CSS.

const graphOptions: RGOptions = {
    defaultLineColor: 'rgba(255, 255, 255, 0.6)',
    defaultNodeColor: 'transparent',
    defaultNodeBorderWidth: 1,
    defaultNodeBorderColor: 'rgba(255, 255, 255, 0.3)',
    defaultNodeShape: RGNodeShape.rect,
    defaultNodeWidth: 170,
    defaultNodeHeight: 40,
    toolBarDirection: 'h',
    toolBarPositionH: 'center',
    toolBarPositionV: 'bottom',
    defaultPolyLineRadius: 10,

This initialization sequence proves that the example uses plain RGJsonData and the graph instance API instead of a custom loader.

const myJsonData: RGJsonData = {
    rootId: 'a',
    nodes: [
        { id: 'a', text: 'a' }, { id: 'b', text: 'b' }, { id: 'b1', text: 'b1' },
        // ...
    ],
    lines: [
        { id: 'l1', from: 'a', to: 'b' }, { id: 'l2', from: 'b', to: 'b1' },
        // ...
    ]
};

await graphInstance.setJsonData(myJsonData);
graphInstance.moveToCenter();
graphInstance.zoomToFit();

This render block shows that live theme switching is only a state change on the wrapper class plus a small selector UI.

<div className={myGraphClassName} style={{ height: '100vh' }}>
    <DraggableWindow>
        <SimpleUISelect
            data={[
                { value: 'my-graph-theme-1', text: 'Canvas Theme 1' },
                { value: 'my-graph-theme-2', text: 'Canvas Theme 2' },
                { value: 'my-graph-theme-3', text: 'Canvas Theme 3' }
            ]}
            currentValue={myGraphClassName}
            onChange={(newValue: string) => {
                setMyGraphClassName(newValue);
            }}
        />
    </DraggableWindow>

This theme fragment shows how the wrapper class reaches into relation-graph’s built-in surfaces instead of replacing them with custom slots.

.my-graph-theme-2 {
    .relation-graph {
        .rg-map {
            background: radial-gradient(circle at center, #aff69e 0%, #9ed8f6 10%, #f69ee5 20%, #d4980e 30%, #daa93a 40%, #3eda3a 50%, #b9ed94 60%);
            background-size: 1000% 1000%;
            animation: backgroundGradient 30s ease infinite;
        }

        .rg-toolbar {
            background-color: #ffffff;
        }

This helper fragment shows that the settings overlay directly updates graph interaction modes and triggers image export through the shared graph instance.

<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 }); }}
/>
<SettingRow
    label="Canvas Drag Event:"

What Makes This Example Distinct

The comparison data places this demo close to css-theme, generate-image-with-background, node-style3, and node-drag-handle, but its emphasis is narrower than any of those neighbors. Its distinct value is showing that one relation-graph tree can switch among three imported full-canvas skins by changing one outer wrapper class while keeping the same data, layout, and built-in renderer.

Compared with css-theme, this example is the more focused wrapper-class skinning reference. It does not add a minimap, custom node icon slots, or a larger theme gallery. Instead, it concentrates on atmospheric gradient canvases, translucent rectangular text nodes, and toolbar skinning.

Compared with generate-image-with-background, the main lesson is live presentation switching, not a capture-preview workflow. Compared with node-style3 and node-drag-handle, it stays closer to relation-graph’s default viewer behavior and uses CSS surface theming as the center of the example rather than slot-driven node content or manual drag interaction.

Where Else This Pattern Applies

This pattern transfers well to branded dashboards where the same graph needs multiple visual skins for different customers, campaigns, or workspace modes. It is also a practical fit for white-label products that must preserve one graph implementation while swapping presentation at the CSS layer.

It also applies to internal tooling that needs temporary presentation modes, such as day versus night operations views, status-themed hierarchy dashboards, or presentation-ready graph screens for demos and screenshots. In those cases, the data model and graph behavior can stay stable while wrapper classes control the visible mood.