定时切换力学参数的力导向图
这个示例构建了一个全屏力导查看器:加载大型内联分支数据后先缩小视图,然后每 3 秒切换一次力学系数,让簇结构持续重组。它使用 relation-graph 内置力引擎以及 `setJsonData(...)`、`setZoom(30)`、`updateOptions(...)`,而非控制面板或自定义节点渲染。
全屏图谱中的定时驱动力布局振荡
这个示例构建了什么
这个示例构建了一个自动运行的全屏图谱查看器。画布展示了一张大型分叉网络:半透明白色圆节点通过半透明直线边相连,整体放置在绿色渐变背景上。
图谱在挂载时会自行初始化,立即缩放到 30,随后由于每三秒切换一次力布局系数而持续改变形态。这里没有自定义控制面板,也没有编辑工作流。这个示例的核心是演示如何在不重新加载数据的情况下,让一个运行中的 relation-graph 实例持续产生环境式动态效果。
数据是如何组织的
数据集以内联方式声明在 initializeGraph() 内部的一个 RGJsonData 对象中。它使用 rootId: 'a',包含 103 个节点和 102 条连线,并从一个根节点向四个大型分支(b、c、d 和 e)展开,每个分支下还有更深层的子节点组。
在调用 setJsonData(...) 之前,只有一个预处理步骤:为每条连线映射生成按顺序递增的 id,即 line_${index}。这个示例不会预先计算坐标,不会附加每节点样式,也不会从外部数据源拉取数据。其结构基本保持 relation-graph 默认的 nodes 加 lines 模式。
在生产场景中,同样的结构可以表示服务依赖、组织集群、产品模块树,或仪表盘中的背景关系图。这里基于字母的示例 id 可以替换为任意业务标识,同时保持相同的分叉结构。
relation-graph 是如何使用的
index.tsx 使用 RGProvider 包裹整个示例,MyGraph.tsx 则通过 RGHooks.useGraphInstance() 作为控制入口。该实例负责加载图谱、设置初始缩放级别,并在运行时后续更新布局参数。
RelationGraph 组件本身基本保持内置行为。它使用内置的 force 布局,将 maxLayoutTimes 设为 30000,初始使用 force_node_repulsion: 1 和 force_line_elastic: 1,以 60 x 60 的尺寸渲染圆形节点,使用 RGLineShape.StandardStraight,并把内置工具栏放在右下角的横向条带位置。
这里没有使用插槽、自定义节点渲染器、自定义连线渲染器或编辑控制器。视觉识别主要来自图谱选项以及一个 SCSS 覆盖:外层容器通过 height: 100vh 填满视口,.rg-map 使用从左到右的绿色渐变背景。
可复用的 relation-graph 模式在于运行时更新路径。首次调用 setJsonData(...) 之后,示例会通过定时器调用 graphInstance.updateOptions(...),在运行中的图谱上修改力布局系数。这意味着动态效果来自现有求解器在新参数下持续运行,而不是重新构建数据集。
关键交互
- 图谱会在
useEffect(...)中自动启动,因此用户无需手动触发加载步骤,就能直接看到准备好的网络。 - 主要行为是每三秒执行一次的定时器,在
force_node_repulsion和force_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-options、toys-clock 和 multi-group-3,但它的重点与三者都不同。相比 layout-force-options,它移除了调参面板,把运行时力参数更新变成一种被动的、自动持续运行的行为。用户不会去调整六个系数,也不会切换数据集,图谱只会自行持续运动。
相比 toys-clock,这里的动态效果并不是来自标记节点或时钟专用的播放逻辑。相比 multi-group-3,它不会分阶段执行从 center 到 force 的一次性过渡,也不会调用显式的重新布局流程。它的动态效果始终保留在力求解器内部,通过对同一张运行中图谱反复更新系数来实现。
罕见的组合正是它有价值的原因:一个大型内联分叉数据集、生成式连线 id、激进的 setZoom(30) 启动方式、全视口展示、半透明圆形默认样式,以及一个无需重新加载数据就交替切换斥力与弹性的定时器。当目标是实现无人值守的力布局动态效果,而不是图谱编辑、业务语义表达或自定义渲染时,这使它成为一个很强的参考示例。
这种模式还适用于哪里
这种模式非常适合信息亭屏幕、展会展台循环展示、落地页背景视觉,以及需要在无人操作时仍保持画面活跃的仪表盘界面。定时器可以在底层数据保持不变的情况下,让关系图谱表面持续保持生命感。
它也适用于依赖图或拓扑视图,在这些场景里,团队希望同一张图能根据不同运行模式持续自我平衡。在生产版本中,定时器可以替换为状态变化、模式切换或计划任务间隔,同时仍然保留同样的 updateOptions(...) 技术路径。
最后,这也是构建品牌化动态表面的一个实用起点。如果团队想要的是由布局驱动的动画,而不是定制的 SVG 艺术图,那么内置 force 布局、运行时选项更新、半透明默认样式以及轻量级画布样式覆盖的组合,就很容易改造成自己的版本。