JavaScript is required

IO Tree Layout

Input-Output Tree Layout with Bidirectional Flow

Specialized tree layout that automatically adjusts connection points based on relationship direction, clearly showing input-output flows with support for horizontal and vertical orientations.

Functional Overview

This example demonstrates the IO tree layout (Input-Output tree layout), a tree layout algorithm specifically designed to clearly display input-output relationships between nodes. Unlike regular tree layouts, IO tree layout automatically adjusts connection point positions based on relationship direction (from parent to child or from child to parent), making each connection’s flow clearly visible. Supports both horizontal and vertical directions, as well as an option to allow node size changes during layout.

Implementation of Key Features

IO Tree Layout Configuration

Use io-tree layout type:

const graphOptionsH: RGOptions = {
    layout: {
        layoutName: 'io-tree',
        treeNodeGapH: 10,
        treeNodeGapV: 10,
        from: 'left',
        changeNodeSizeDuringLayout
    },
    defaultNodeWidth: 120,
    defaultNodeHeight: 30,
    defaultLineShape: RGLineShape.StandardOrthogonal,
    defaultJunctionPoint: RGJunctionPoint.lr
};

The changeNodeSizeDuringLayout parameter controls whether the layout engine can adjust node sizes.

Dynamic Junction Point Adjustment

Dynamically set connection point positions based on node level relationships:

const updateLinesJunctionPoint = () => {
    graphInstance.getLinks().forEach((link) => {
        const lineProps: Partial<JsonLine> = {
            text: '',
            lineRadius: 13,
            lineWidth: 2,
            lineShape: 44,
            fromJunctionPoint: link.line.fromJunctionPoint,
            toJunctionPoint: link.line.toJunctionPoint
        };

        if (link.fromNode.lot?.level > link.toNode.lot?.level) {
            // Connection from higher to lower level
            if (treeFrom === 'top') {
                lineProps.fromJunctionPoint = RGJunctionPoint.right;
                lineProps.toJunctionPoint = changeNodeSizeDuringLayout ? 'horizontalLine' : RGJunctionPoint.bottom;
            } else if (treeFrom === 'left') {
                lineProps.fromJunctionPoint = RGJunctionPoint.bottom;
                lineProps.toJunctionPoint = changeNodeSizeDuringLayout ? 'verticalLine' : RGJunctionPoint.right;
            }
        } else {
            // Connection from lower to higher level
            if (treeFrom === 'top') {
                lineProps.fromJunctionPoint = changeNodeSizeDuringLayout ? 'horizontalLine' : RGJunctionPoint.bottom;
                lineProps.toJunctionPoint = RGJunctionPoint.left;
            } else if (treeFrom === 'left') {
                lineProps.fromJunctionPoint = changeNodeSizeDuringLayout ? 'verticalLine' : RGJunctionPoint.right;
                lineProps.toJunctionPoint = RGJunctionPoint.top;
            }
        }

        graphInstance.updateLine(link.line.id, lineProps);
    });
};

This ensures connection lines clearly display regardless of relationship direction.

Using Links Instead of Lines

Use getLinks() instead of getLines() for more information:

graphInstance.getLinks().forEach((link) => {
    // link.line provides the line object
    // link.fromNode and link.toNode provide source and target node objects
    // This makes it easy to compare node levels
});

Links contain both lines and connected node objects, facilitating complex connection logic.

Manual Node Size Update

Manually update node sizes before layout:

graphInstance.getNodes().forEach((node) => {
    graphInstance.updateNode(node, {
        width: targetOptions.defaultNodeWidth,
        height: targetOptions.defaultNodeHeight
    });
});

Because default sizes in options don’t affect already added nodes, manual updates are needed.

Wait for Rendering Completion

Wait for browser rendering to complete before re-layout:

await graphInstance.sleep(100); // Wait for node size property modifications to be rendered by browser
await graphInstance.doLayout();

This ensures layout calculations use correct node dimensions.

Direction Switching Support

Support both horizontal (left-to-right) and vertical (top-to-bottom) layout directions:

<SimpleUISelect
    data={[
        { value: 'left', text: 'Horizontal Tree' },
        { value: 'top', text: 'Vertical Tree' }
    ]}
    currentValue={layoutFrom}
    onChange={(newValue: string) => { setLayoutFrom(newValue); }}
/>

Switching directions automatically recalculates connection points and layout.

Creative Use Cases

Data Flow Visualization

Clearly display data flow direction in systems. For example, showing the complete path from sensors to processing units to storage systems.

Organizational Charts

Display organization reporting relationships, including upward reporting (subordinate to superior) and downward management (superior to subordinate) relationships.

Decision Tree Visualization

Display decision flows in decision trees, including forward decisions and reverse feedback loops, making the entire decision process clearly visible.

Supply Chain Networks

Visualize bidirectional relationships in supply chains, including suppliers to manufacturers (forward) and retailers to distributors (reverse) feedback.

Neural Network Architectures

Display connections between neurons in neural networks, including both forward propagation and backpropagation paths.

Project Dependency Relationships

Display task dependencies in project management, including prerequisite tasks and dependent tasks.

Financial Transaction Flows

Display complete financial transaction flows, including funds flowing in, out, and intermediate processing steps.

Workflow and Approval Processes

Visualize approval processes in workflow systems, clearly showing application submission paths and approval feedback paths.

Energy Flow Diagrams

In energy management systems, display energy production, transmission, and consumption, clearly showing bidirectional energy flows.

Message Passing Systems

Display message flows in distributed systems or message queues, including request and response paths.