JavaScript is required

Connected Subnetwork Layout Switcher

This example shows how to click a node, detect its connected subnetwork, and relayout only that group inside a shared relation-graph canvas. It combines four preset layouts, selection-scoped editing controls, a minimap, and a floating helper window while keeping other disconnected graph islands loaded.

Switching Layouts for a Selected Connected Subnetwork

What This Example Builds

This example builds a single relation-graph canvas that contains two disconnected graph islands and lets the user relayout only the island around the currently clicked node. The screen combines the main graph, a minimap, a floating helper window, and a small preset selector that appears over the active editing group.

The main behavior is selection-scoped relayout. Instead of switching the layout for the whole canvas, the example detects the connected subnetwork of the clicked node and applies one of four presets, center, left-to-right tree, circle, or a tuned force layout, only to that group.

How the Data Is Organized

The graph data is assembled from two inline RGJsonData objects. Each dataset declares a rootId, a nodes array, and a lines array with explicit line ids. The example does not preprocess the data into a separate grouping model before layout. Instead, it appends both datasets into one mounted graph instance with addNodes() and addLines(), runs doLayout(), then relies on graph connectivity at runtime to discover the active subnetwork.

That structure maps well to real applications where several independent relationship groups share one workspace. The same shape could represent separate business units, multiple incident clusters, disconnected knowledge-graph communities, or several dependency islands loaded into one investigation canvas.

How relation-graph Is Used

The page is wrapped in RGProvider, and MyGraph uses RGHooks.useGraphInstance() to work directly with the active graph instance. The initial graph options disable debug mode, use rectangular nodes, and start with the first preset in exampleLayouts, which is the center layout with a reduced distanceCoefficient.

The example uses relation-graph instance APIs as its main control surface. It appends two datasets with addNodes() and addLines(), calls doLayout(), then aligns the viewport with moveToCenter() and zoomToFit(). After a node is clicked, it resolves the connected component with getNetworkNodesByNode(), stores that group through setEditingNodes(), and later relayouts only those nodes by creating a new layout instance and calling placeNodes(groupNodes, checkedNode).

The view-layer UI is injected through RGSlotOnView. Inside that slot, RGMiniView adds a minimap, and RGEditingNodeController anchors the layout selector to the current editing selection. This is what makes the selector feel local to the chosen subnetwork rather than global to the whole page.

The floating helper window comes from a shared DraggableWindow component. In this example it provides usage guidance, drag and minimize behavior, and access to a shared settings panel. That settings panel uses RGHooks.useGraphInstance() and RGHooks.useGraphStore() to switch wheelEventAction and dragEventAction at runtime and to export the canvas by calling prepareForImageGeneration(), getOptions(), and restoreAfterImageGeneration().

Styling is intentionally narrow. The example-specific SCSS mostly leaves graph defaults alone and recolors .simple-ui-select so the layout chips stand out with a magenta accent.

Key Interactions

  • Clicking a node sets checkedNodeId, resolves the connected component around that node, and frames that component as the active editing group.
  • Choosing a preset from the overlay selector creates a layout instance and repositions only the active group around the selected node.
  • Clicking the canvas clears checked state, removes the editing group, and exits the current relayout context.
  • The floating window can be dragged and minimized, and its settings mode can switch wheel and drag behavior or export an image of the current canvas.

Key Code Fragments

This preset table defines the four layout families that can be applied to the selected group.

const exampleLayouts: { label: string, layoutOptions: RGLayoutOptions }[] = [
    {
        label: 'Center',
        layoutOptions: {
            layoutName: 'center',
            distanceCoefficient: 0.5
        }
    },
    {
        label: 'Tree',
        layoutOptions: {
            layoutName: 'tree',
            from: 'left'
        }
    },
    // ...
];

This initialization step merges two independent datasets into one graph instance and fits the shared canvas.

graphInstance.addNodes(network1JsonData.nodes);
graphInstance.addLines(network1JsonData.lines);
graphInstance.addNodes(network2JsonData.nodes);
graphInstance.addLines(network2JsonData.lines);
await graphInstance.doLayout();
graphInstance.moveToCenter();
graphInstance.zoomToFit();

This selection flow turns one clicked node into a connected editing group.

const getGroupNodes = (node: RGNode) => {
    return graphInstance.getNetworkNodesByNode(node);
}
const selectGroupNodes = () => {
    if (!checkedNodeId) {
        return;
    }
    const checkedNode = graphInstance.getNodeById(checkedNodeId);
    if (checkedNode) {
        const groupNodes = getGroupNodes(checkedNode);
        graphInstance.setEditingNodes(groupNodes);
    }
}

This relayout handler applies the chosen preset only to the active connected component.

const onChangeNextworkLayout = (layoutLabel: string) => {
    const layoutInfo = exampleLayouts.find(n => n.label === layoutLabel);
    if (!layoutInfo) return;
    const layout = graphInstance.createLayout(layoutInfo?.layoutOptions);
    const checkedNode = graphInstance.getNodeById(checkedNodeId);
    if (!checkedNode) return;
    const groupNodes = getGroupNodes(checkedNode);
    layout.placeNodes(groupNodes, checkedNode);
    graphInstance.setEditingNodes(groupNodes);
};

This view-layer slot keeps the minimap visible and renders the selector next to the active editing selection.

<RGSlotOnView>
    <RGMiniView />
    <RGEditingNodeController>
        <div className="absolute transform translate-y-[-40px] pointer-events-auto">
            <div className="flex gap-2 flex-nowrap w-[220px]">
                <SimpleUISelect
                    data={exampleLayouts.map(n => ({ text: n.label, value: n.label }))}
                    currentValue={''}
                    onChange={(clickedLabel: string) => {
                        onChangeNextworkLayout(clickedLabel);
                    }}
                />
            </div>
        </div>
    </RGEditingNodeController>
</RGSlotOnView>

What Makes This Example Distinct

Compared with nearby layout demos such as switch-layout and layout-tree, this example does not treat layout switching as a whole-canvas operation. Its distinctive pattern is the combination of getNetworkNodesByNode(), setEditingNodes(), and createLayout(...).placeNodes(...), which keeps relayout scoped to the connected group around the clicked node.

It also differs from those neighbors by loading two disconnected datasets into the same graph instance. That makes the example a stronger reference for canvases that contain several graph islands, where one island should be rearranged without disturbing the others.

Compared with editing-focused examples such as change-line-vertices and freely-draw-lines-on-canvas, the overlay controller is used here for layout adjustment rather than topology authoring. The result sits in a middle ground between a viewer-style layout demo and a full graph editor.

Where Else This Pattern Applies

This pattern transfers well to analysis tools where users need to clean up or compare one local cluster without rebuilding the whole graph. Examples include reorganizing one department inside a larger org map, reflowing one service cluster inside a dependency graph, isolating one incident chain during operations analysis, or adjusting one community inside a knowledge graph that contains several disconnected topics.

It also fits staged editing workflows. A product can keep graph structure read-only, expose only selection-scoped layout controls, and still give users a practical way to improve readability inside a crowded shared canvas.