JavaScript is required

Industrial Chain Card-Anchored Mixed Layout

A viewer-oriented relation-graph demo that combines a fixed outer graph with a custom mixed-layout pipeline for an industrial value chain dashboard. Ordinary canvas-slot card rows become graph anchors through `RGConnectTarget` and `addFakeLines(...)`, while per-group tree layouters and dependency refs keep attached subtrees synchronized during expand, collapse, and depth-based bulk expansion.

Card-Anchored Mixed Layout for an Industrial Value Chain Dashboard

What This Example Builds

This example builds a viewer-oriented industrial value chain dashboard where three large stage cards sit inside the graph canvas and each card row anchors a separate relation-graph tree. Users see an upstream, midstream, and downstream board in the background, orthogonal bridge connectors that attach those rows to hidden graph roots, and multiple tree clusters arranged around the cards rather than one single hierarchy.

Users can expand or collapse branches, open all groups to a chosen depth from the floating helper window, click blank canvas to clear checked and editing state, drag or minimize the helper window, and open a secondary settings overlay for wheel mode, drag mode, and image export. The main point of the example is the composition technique: ordinary HTML inside RGSlotOnCanvas becomes the visible anchor layer, while the real graph nodes stay behind it and are repositioned by a custom mixed-layout controller.

How the Data Is Organized

The source data comes from getMyAllColumnsData(), which returns three column objects: c1, c2, and c3. Each column includes a stage name, subtitle, icon name, theme colors, and an items array of nested JsonNode trees. In the shipped data, those trees describe upstream materials and research, midstream manufacturing, and downstream applications and service. The stage shell is static, but the important structure is reusable: column metadata describes the canvas cards, while nested node trees describe the graph content that will hang from each card row.

Before anything is laid out, MyMixLayout.loadData(...) converts the three columns into multiple groups. analysisDataForColumn3(...) splits each column into group-level roots, adds refs so some groups depend on the bounds of earlier or later groups, and chooses different layout rules by column. flatNodeData(...) then flattens each tree into nodes and lines, adds hasChildren and deep metadata, and buildMyGroup(...) tags every node with myGroupId, removes children, and shrinks the real root into a tiny hidden anchor node. In a production system, the same pattern could represent supply chain stages, service journey stages, product lifecycle segments, platform capability columns, or any staged dashboard where each card row needs an attached explainer tree.

How relation-graph Is Used

index.tsx wraps the example in RGProvider, and MyGraph.tsx uses RGHooks.useGraphInstance() to drive the graph imperatively. The outer graph is configured with layoutName: 'fixed', so relation-graph does not perform one whole-canvas automatic layout. Instead, MyMixLayout creates a separate tree layouter for each group through createLayout(...), locks the root in place with fixedRootNode = true, and positions each group from RGConnectTarget coordinates, column-specific offsets, dependency refs, and the rendered height of the canvas card container.

The graph options make the composition visually consistent: rectangular nodes, orthogonal connectors, rounded polyline corners, no default node border, and left-right junction behavior. initializeGraph() enables XY animation, loads the column data, derives all groups, waits for canvas-slot DOM rendering, connects card rows to hidden roots through addFakeLines(...), applies all group layouts, and then fits the viewport with zoomToFit().

The slots matter more than default node rendering in this sample. RGSlotOnCanvas renders the whole industrial dashboard, and each row exposes an RGConnectTarget endpoint so non-node DOM can participate in graph connectivity. RGSlotOnNode reduces visible graph nodes to centered text labels, while the real group root nodes are kept tiny and blank. The example does not implement authoring workflows, but it does reuse shared viewer tooling through DraggableWindow: CanvasSettingsPanel reads live options with RGHooks.useGraphStore(), updates wheel and drag behavior with setOptions(...), and exports the graph image through prepareForImageGeneration() and restoreAfterImageGeneration(). The local SCSS file mainly contains light wrapper overrides, so most of the behavior and appearance come from graph options, slot content, and per-group styles rather than heavy CSS customization.

Key Interactions

  • Clicking a built-in expand holder opens or closes one branch, then relayoutIfNeed(...) reruns layout for that group and recursively reruns layout for dependent groups listed in refs.
  • Clicking one of the depth buttons in SimpleUISelect expands or collapses every group according to node.data.deep, refreshes node visibility, reruns all group layouts, and refits the viewport.
  • Clicking blank canvas clears checked state and clears the editing-node list, which resets the viewer without changing the underlying dataset.
  • Dragging the helper window repositions the floating control surface, and minimizing it hides the descriptive panel while leaving the graph visible.
  • Opening the settings overlay switches wheel behavior, switches canvas drag behavior, and can export the current graph as an image through the shared screenshot helper.

Key Code Fragments

This fragment shows that the outer graph stays in fixed layout and standardizes the node and line defaults for the mixed composition:

const graphOptions: RGOptions = {
    debug: false,
    layout: { layoutName: 'fixed' },
    defaultPolyLineRadius: 10,
    defaultNodeBorderWidth: 0,
    defaultNodeShape: RGNodeShape.rect,
    defaultLineShape: RGLineShape.SimpleOrthogonal,
    defaultJunctionPoint: RGJunctionPoint.lr
};

This fragment shows how ordinary dashboard rows become graph endpoints inside the canvas slot:

<RGConnectTarget
    targetId={'col-item-ct-' + item.id}
    junctionPoint={RGJunctionPoint.lr}
    disableDrag={true}
    disableDrop={true}
>
    <div className={`w-1.5 h-1.5 rounded-full ${themeColor.dot}`} />
</RGConnectTarget>

This fragment shows how those HTML endpoints are bridged to hidden root nodes with fake orthogonal connectors:

const fakeLine: JsonLine = {
    id: 'ct-line-' + group.rootNodeId,
    fromType: RGInnerConnectTargetType.CanvasPoint,
    from: connectTargetId,
    toType: RGInnerConnectTargetType.Node,
    to: group.rootNodeId,
    lineShape: RGLineShape.SimpleOrthogonal,
    color: group.groupStyles.lineStyles.color || 'rgba(0,0,0,0.1)',
    showEndArrow: false
};

This fragment shows that the group layout starts from connect-target coordinates and then creates a dedicated tree layouter with a fixed root:

const connectTarget: RGConnectTargetData = this.graphInstance.getConnectTargetById(connectTargetId);
const groupRootNodeXy = {
    x: connectTarget.offsetX,
    y: connectTarget.offsetY
};
// ... column-specific offsets and dependency adjustments
const myGroupLayout = this.graphInstance.createLayout(layoutOptions as RGLayoutOptions);
myGroupLayout.isMainLayouer = false;
myGroupLayout.layoutOptions.fixedRootNode = true;
myGroupLayout.placeNodes(groupNodes, groupRootNode);

This fragment shows the preprocessing step that tags each flattened node with reusable metadata for expansion and grouping:

const nodeJson = {
    id: thisOrignNode.id,
    text: thisOrignNode.text,
    data: {
        ...orignData,
        hasChildren,
        deep
    }
};

This fragment shows why expand or collapse in one tree can reposition other trees as well:

relayoutAffectedGroups(group: MyGroup) {
    const affectedGroupsList = this.allGroups.filter(g => g.refs.includes(group.groupId));
    for (const affectedGroup of affectedGroupsList) {
        this.layoutGroup(affectedGroup);
        this.relayoutAffectedGroups(affectedGroup);
    }
}

What Makes This Example Distinct

The comparison data shows that mix-layout-tree is the closest grouped-layout neighbor, but the lesson is different. mix-layout-tree is the cleaner reference for splitting one hierarchy around a visible shared root. mix-layout-2 goes further by turning canvas-slot card rows into graph anchors, hiding the actual group roots, and propagating relayout through explicit inter-group dependencies. That makes this example more useful when a product needs dashboard content and graph structure to stay synchronized.

Compared with mix-layout-editor, this sample keeps the same card-anchored mixed-layout family but shifts the emphasis from authoring to presentation. It removes editing overlays, insertion and deletion workflows, and minimap-heavy tooling, so the reusable idea is easier to isolate: viewer-side composition with bulk depth control and automatic dependent relayout.

The comparison file also makes an important boundary clear. DOM-anchor wiring is not unique to this example, because inventory-structure-diagram and other demos also use RGConnectTarget plus fake-line connections. What stands out here is the feature combination: an industrial dashboard backdrop, hidden-root staged tree clusters, column-specific growth directions, orthogonal bridge connectors without arrows, and recursive relayout when one group’s size changes. That combination is relatively rare in the example set and makes this a strong starting point for synchronized dashboard-plus-tree views rather than a plain multi-tree viewer.

Where Else This Pattern Applies

This pattern transfers well to supply chain overviews, product lifecycle dashboards, service journey boards, platform capability maps, and compliance or risk surfaces where each visible stage card needs a connected explanation tree. The same approach also fits operations dashboards where HTML summaries should remain the dominant visual layer and the graph should act as a structured explainer behind them.

It is also a good extension point for staged process tools that need selective disclosure without losing spatial context. A team could reuse the group preprocessing, connect-target anchoring, and dependency-based relayout logic for onboarding flows, manufacturing process maps, procurement chains, partner ecosystems, or any multi-column narrative where one expanded subtree should push related clusters above or below it.