JavaScript is required

动态切换布局

自动布局切换 - 通过定时转换循环多个布局

自动布局切换动画

功能概述

本示例演示了通过定时转换在不同布局算法之间自动循环。图每 2 秒在中心、树形、圆形和力布局之间连续切换,创建动画展示不同算法如何排列相同的图数据。用户可以使用播放/停止控件启动和停止自动切换,使其成为演示布局功能或为数据集查找最佳布局的理想选择。

核心特性实现

布局循环配置

定义要循环的布局数组:

const exampleLayouts: { label: string, layoutOptions: RGLayoutOptions }[] = [
    {
        label: 'Center',
        layoutOptions: {
            layoutName: 'center'
        }
    },
    {
        label: 'Tree',
        layoutOptions: {
            layoutName: 'tree',
            from: 'left'
        }
    },
    {
        label: 'Circle',
        layoutOptions: {
            layoutName: 'circle'
        }
    },
    {
        label: 'Force',
        layoutOptions: {
            layoutName: 'force'
        }
    }
];

关键要点:

  • 标签字段:每种布局的人类可读名称
  • 布局选项:每种算法的完整配置对象
  • 易于扩展:通过添加到数组来添加更多布局

播放状态管理

使用状态和引用控制动画循环:

const [playing, setPlaying] = useState(false);
const currentLayoutIndexRef = useRef(0);
const playNextLayoutTimer = useRef();

关键要点:

  • UI 状态playing 状态控制按钮显示
  • 索引引用currentLayoutIndexRef 维护循环中的位置
  • 定时器引用:存储 setTimeout ID 以进行清理

布局切换逻辑

switchToNextLayout 函数执行实际的布局更改:

const switchToNextLayout = async () => {
    // 如果超过末尾则重置为开始
    if (currentLayoutIndexRef.current > exampleLayouts.length - 1) {
        currentLayoutIndexRef.current = 0;
    }

    // 更新布局选项
    graphInstance.updateOptions({
        layout: exampleLayouts[currentLayoutIndexRef.current].layoutOptions
    });

    // 重新计算位置
    await graphInstance.doLayout();

    // 调整视图
    graphInstance.moveToCenter();
    graphInstance.zoomToFit();

    // 安排下一次切换
    playNextLayoutTimer.current = setTimeout(() => {
        currentLayoutIndexRef.current++;
        switchToNextLayout();
    }, 2000); // 2 秒延迟
};

关键要点:

  • 索引包装:到达数组末尾时重置为 0
  • 选项更新:使用 updateOptions 更改布局算法
  • 重新布局:调用 doLayout 重新计算节点位置
  • 视图调整:每次布局后重新居中和缩放
  • 递归调度:setTimeout 用于下一次迭代

播放控制函数

简单的开始/停止控件:

const play = () => {
    switchToNextLayout();
};

const stop = () => {
    clearTimeout(playNextLayoutTimer.current);
};

基于效果的状态管理

处理播放状态更改和清理:

useEffect(() => {
    initializeGraph();
    return () => {
        stop(); // 卸载时清理
    };
}, []);

useEffect(() => {
    if (playing) {
        play();
    } else {
        stop();
    }
}, [playing]);

关键要点:

  • 初始化:挂载时加载图
  • 清理:组件卸载时清除定时器
  • 播放状态效果:当 playing 更改时启动/停止动画

带图标的 UI 控件

使用 Lucide 图标作为播放/停止按钮:

<RelationGraph options={graphOptions} />
<DraggableWindow>
    {!playing ? (
        <button
            className="border rounded-lg px-3 py-1 flex place-items-center justify-center gap-2 bg-white"
            onClick={() => setPlaying(true)}
        >
            <Play size={16} />
            <span>Play Auto Switch</span>
        </button>
    ) : (
        <button
            className="border rounded-lg px-3 py-1 flex place-items-center justify-center gap-2 bg-green-400"
            onClick={() => setPlaying(false)}
        >
            <Loader2Icon className="animate-spin" size={16} />
            <span>Stop Auto Switch</span>
        </button>
    )}
</DraggableWindow>

关键要点:

  • 视觉反馈:播放/停止状态的不同样式和图标
  • 加载指示器:播放时旋转的图标
  • 可拖动窗口:控件浮动在图上方

图数据

使用简单的树形结构数据集:

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' },
        // ... 更多连线
    ]
};

矩形节点形状

使用矩形节点进行清晰的层级可视化:

const graphOptions: RGOptions = {
    debug: false,
    defaultNodeShape: RGNodeShape.rect,
    layout: exampleLayouts[0].layoutOptions
};

创意使用场景

布局算法展示: 向利益相关者展示不同的图可视化算法。自动循环布局让观看者比较每种算法如何解释相同的数据。

数据集探索: 加载未知数据集并循环布局以快速识别哪种算法最好地揭示数据结构。在找到最信息丰富的排列时停止。

视觉基准测试: 在同一图上记录不同布局算法的性能。使用自动循环捕获截图或测量渲染时间。

交互式演示: 创建动态重新配置自己的引人入胜的演示。在教育设置中使用以展示布局算法如何工作。

环境数据可视化: 在公共空间显示带有自动布局更改的关系图。创建动态的、生动的可视化,吸引注意力并揭示不同的视角。

布局选择工具: 通过自动显示所有选项帮助用户为其数据选择最佳布局。用户可以在最适合其需求的布局上停止。