JavaScript is required

IO Tree 布局

输入输出树布局与双向流向

专门优化的树布局算法,根据关系方向自动调整连接点,清晰显示输入输出流向,支持水平和垂直两种方向。

功能概述

此示例展示了 IO 树布局(输入-输出树布局),这是一种专门为清晰显示节点间输入输出关系而设计的树形布局算法。与普通树布局不同,IO 树布局会根据关系的方向(从父节点到子节点或从子节点到父节点)自动调整连接点的位置,使每条线的流向都清晰可见。支持水平和垂直两种方向,以及是否允许布局过程中改变节点大小的选项。

核心特性实现

IO 树布局配置

使用 io-tree 布局类型:

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

changeNodeSizeDuringLayout 参数控制是否允许布局引擎调整节点大小。

基于层级的连接点动态调整

根据节点层级关系动态设置连接点位置:

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) {
            // 从高层级到低层级的连接
            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 {
            // 从低层级到高层级的连接
            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);
    });
};

这确保了无论关系的方向如何,连接线都能清晰显示。

使用 Links 而非 Lines

使用 getLinks() 而不是 getLines() 以获取更多信息:

graphInstance.getLinks().forEach((link) => {
    // link.line 提供线条对象
    // link.fromNode 和 link.toNode 提供起始和目标节点对象
    // 这样可以方便地比较节点层级
});

Links 包含线条和连接的节点对象,便于实现复杂的连接逻辑。

节点大小手动更新

在布局前手动更新节点大小:

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

因为 options 中的默认大小不会影响已添加的节点,所以需要手动更新。

等待渲染完成

在重新布局前等待浏览器渲染完成:

await graphInstance.sleep(100); // 等待节点大小属性的修改被浏览器渲染
await graphInstance.doLayout();

这确保布局计算使用正确的节点尺寸。

方向切换支持

支持水平(从左到右)和垂直(从上到下)两种布局方向:

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

切换方向会自动重新计算连接点和布局。

创意使用场景

数据流可视化

清晰显示数据在系统中的流动方向。例如,显示数据从传感器到处理单元再到存储系统的完整路径。

组织架构图

显示组织的汇报关系,包括向上汇报(下属到上级)和向下管理(上级到下属)两种关系。

决策树可视化

在决策树中显示决策流程,包括正向决策和逆向反馈回路,使整个决策过程清晰可见。

供应链网络

可视化供应链中的双向关系,包括供应商到制造商(正向)和零售商到分销商(逆向)的反馈。

神经网络架构

显示神经网络中神经元之间的连接,包括前向传播和反向传播路径。

项目依赖关系

在项目管理中显示任务之间的依赖关系,包括前置任务(prerequisites)和后续任务(dependencies)。

金融交易流程

显示金融交易的完整流程,包括资金流入、流出和中间处理步骤。

工作流和审批流程

可视化工作流系统中的审批流程,清晰显示申请的提交路径和审批的反馈路径。

能源流向图

在能源管理系统中显示能源的生产、传输和消耗,清晰显示双向能源流动。

消息传递系统

显示分布式系统或消息队列中的消息流向,包括请求和响应路径。