JavaScript is required

定时切换力学参数的力导向图

这个示例构建了一个全屏力导查看器:加载大型内联分支数据后先缩小视图,然后每 3 秒切换一次力学系数,让簇结构持续重组。它使用 relation-graph 内置力引擎以及 `setJsonData(...)`、`setZoom(30)`、`updateOptions(...)`,而非控制面板或自定义节点渲染。

全屏图谱中的定时驱动力布局振荡

这个示例构建了什么

这个示例构建了一个自动运行的全屏图谱查看器。画布展示了一张大型分叉网络:半透明白色圆节点通过半透明直线边相连,整体放置在绿色渐变背景上。

图谱在挂载时会自行初始化,立即缩放到 30,随后由于每三秒切换一次力布局系数而持续改变形态。这里没有自定义控制面板,也没有编辑工作流。这个示例的核心是演示如何在不重新加载数据的情况下,让一个运行中的 relation-graph 实例持续产生环境式动态效果。

数据是如何组织的

数据集以内联方式声明在 initializeGraph() 内部的一个 RGJsonData 对象中。它使用 rootId: 'a',包含 103 个节点和 102 条连线,并从一个根节点向四个大型分支(bcde)展开,每个分支下还有更深层的子节点组。

在调用 setJsonData(...) 之前,只有一个预处理步骤:为每条连线映射生成按顺序递增的 id,即 line_${index}。这个示例不会预先计算坐标,不会附加每节点样式,也不会从外部数据源拉取数据。其结构基本保持 relation-graph 默认的 nodeslines 模式。

在生产场景中,同样的结构可以表示服务依赖、组织集群、产品模块树,或仪表盘中的背景关系图。这里基于字母的示例 id 可以替换为任意业务标识,同时保持相同的分叉结构。

relation-graph 是如何使用的

index.tsx 使用 RGProvider 包裹整个示例,MyGraph.tsx 则通过 RGHooks.useGraphInstance() 作为控制入口。该实例负责加载图谱、设置初始缩放级别,并在运行时后续更新布局参数。

RelationGraph 组件本身基本保持内置行为。它使用内置的 force 布局,将 maxLayoutTimes 设为 30000,初始使用 force_node_repulsion: 1force_line_elastic: 1,以 60 x 60 的尺寸渲染圆形节点,使用 RGLineShape.StandardStraight,并把内置工具栏放在右下角的横向条带位置。

这里没有使用插槽、自定义节点渲染器、自定义连线渲染器或编辑控制器。视觉识别主要来自图谱选项以及一个 SCSS 覆盖:外层容器通过 height: 100vh 填满视口,.rg-map 使用从左到右的绿色渐变背景。

可复用的 relation-graph 模式在于运行时更新路径。首次调用 setJsonData(...) 之后,示例会通过定时器调用 graphInstance.updateOptions(...),在运行中的图谱上修改力布局系数。这意味着动态效果来自现有求解器在新参数下持续运行,而不是重新构建数据集。

关键交互

  • 图谱会在 useEffect(...) 中自动启动,因此用户无需手动触发加载步骤,就能直接看到准备好的网络。
  • 主要行为是每三秒执行一次的定时器,在 force_node_repulsionforce_line_elastic 上交替使用 [0.2, 2][1, 0.2]。这种重复切换会让图谱簇持续收紧、松开并重新成形。
  • 右下角会显示内置工具栏,但示例没有添加自己的调参控件、点击处理、编辑操作或分阶段重新布局按钮。它始终保持查看模式。

关键代码片段

这个 hook 与 effect 代码块表明,图谱会自动初始化,然后通过一个重复定时器持续运动。

const graphInstance = RGHooks.useGraphInstance();
const optIndex = useRef(0);

useEffect(() => {
    initializeGraph();
    const resizeTimer = setInterval(async () => {
        await updateLayoutorOptions();
    }, 3000);

    return () => {
        clearInterval(resizeTimer);
    };
}, []);

这段代码展示了数据集以内联方式定义,并且在加载数据之前即时生成连线 id。

const myJsonData: RGJsonData = {
    rootId: 'a',
    nodes: [
        { id: 'a', text: 'a' }, { id: 'b', text: 'b' },
        // ...more branching nodes...
        { id: 'e2-9', text: 'e2-9' }
    ],
    lines: [
        { from: 'a', to: 'b' }, { from: 'b', to: 'b1' },
        // ...more branching links...
        { from: 'e2', to: 'e2-9' }
    ].map((line, index) => ({ ...line, id: `line_${index}` }))
};

这些调用展示了一次性的启动顺序:先加载数据,再强制设置一个较宽的初始视角。

const initializeGraph = async () => {
    // ...inline RGJsonData definition...
    await graphInstance.setJsonData(myJsonData);
    graphInstance.setZoom(30);
};

这个更新函数是可复用的核心模式:在运行中的图谱上直接修改实时力系数,而不是重新加载图谱数据。

const opts = [[0.2, 2], [1, 0.2]];
const opt = opts[optIndex.current++];
if (optIndex.current >= opts.length) {
    optIndex.current = 0;
}

graphInstance.updateOptions({
    layout: {
        layoutName: 'force',
        force_node_repulsion: opt[0],
        force_line_elastic: opt[1]
    }
});

这段选项配置表明,这个示例在外观和布局行为上主要依赖 relation-graph 的内置默认能力。

const graphOptions: RGOptions = {
    defaultLineColor: 'rgba(255, 255, 255, 0.6)',
    defaultNodeColor: 'rgba(255, 255, 255, 0.6)',
    defaultNodeBorderColor: 'rgba(255, 255, 255, 0.3)',
    defaultNodeShape: RGNodeShape.circle,
    defaultNodeWidth: 60,
    defaultNodeHeight: 60,
    toolBarDirection: 'h',
    toolBarPositionH: 'right',
    toolBarPositionV: 'bottom',
    defaultLineShape: RGLineShape.StandardStraight,

这段样式片段展示了唯一一个决定性视觉覆盖,它把图谱变成了一个具有环境感的全屏表面。

.my-graph {
    .relation-graph {
        .rg-map {
            background: linear-gradient(to right, rgb(16, 185, 129), rgb(101, 163, 13));
        }
    }
}

这个示例的独特之处

对比数据表明,这个示例接近 layout-force-optionstoys-clockmulti-group-3,但它的重点与三者都不同。相比 layout-force-options,它移除了调参面板,把运行时力参数更新变成一种被动的、自动持续运行的行为。用户不会去调整六个系数,也不会切换数据集,图谱只会自行持续运动。

相比 toys-clock,这里的动态效果并不是来自标记节点或时钟专用的播放逻辑。相比 multi-group-3,它不会分阶段执行从 centerforce 的一次性过渡,也不会调用显式的重新布局流程。它的动态效果始终保留在力求解器内部,通过对同一张运行中图谱反复更新系数来实现。

罕见的组合正是它有价值的原因:一个大型内联分叉数据集、生成式连线 id、激进的 setZoom(30) 启动方式、全视口展示、半透明圆形默认样式,以及一个无需重新加载数据就交替切换斥力与弹性的定时器。当目标是实现无人值守的力布局动态效果,而不是图谱编辑、业务语义表达或自定义渲染时,这使它成为一个很强的参考示例。

这种模式还适用于哪里

这种模式非常适合信息亭屏幕、展会展台循环展示、落地页背景视觉,以及需要在无人操作时仍保持画面活跃的仪表盘界面。定时器可以在底层数据保持不变的情况下,让关系图谱表面持续保持生命感。

它也适用于依赖图或拓扑视图,在这些场景里,团队希望同一张图能根据不同运行模式持续自我平衡。在生产版本中,定时器可以替换为状态变化、模式切换或计划任务间隔,同时仍然保留同样的 updateOptions(...) 技术路径。

最后,这也是构建品牌化动态表面的一个实用起点。如果团队想要的是由布局驱动的动画,而不是定制的 SVG 艺术图,那么内置 force 布局、运行时选项更新、半透明默认样式以及轻量级画布样式覆盖的组合,就很容易改造成自己的版本。