G6 Fruchterman 力导向布局完全指南:参数配置、聚类模式与底层实现原理
2026/9/23 19:34:53 网站建设 项目流程
  • 数据可视化
  • 前端
  • 图表库

【免费下载链接】G6

♾ A Graph Visualization Framework in JavaScript.

项目地址:https://gitcode.com/gh_mirrors/g6/G6
点击查看免费下载

Fruchterman 布局是 G6(JavaScript 图可视化框架)内置的一种经典力导向布局,它通过模拟节点间的斥力与引力,让图自动收敛到能量最小化的稳定状态。本文以 FruchtermanLayout.en.md 文档为骨架,结合仓库内布局类型定义与运行时实现源码,系统讲解 Fruchterman 布局的全部配置参数、基本均匀分布与聚类两种使用模式,以及它在 G6 内部的迭代执行机制,帮助你按需调出清晰、美观的力导向图。

Fruchterman 布局概述

Fruchterman 布局是基于Graph Drawing by Force-directed Placement论文中力导向放置算法的实现。它的核心思想是:把图看作一个物理系统,节点之间存在相互斥力(防止重叠、保证均匀分布),边则像弹簧一样对两端节点施加吸引力(把关联节点拉近),同时所有节点还受到朝向画布中心的引力(gravity)。通过不断迭代计算这些合力并更新节点位置,系统最终达到能量最低的平衡状态,此时图结构清晰、节点分布均匀。

在 G6 中,Fruchterman 布局通过布局扩展注册表内置提供,无需额外引入。注册关系位于 packages/g6/src/registry/build-in.ts,其中fruchterman关键字被注册到FruchtermanLayout实现;该实现由 @antv/layout 中统一转发。从 packages/g6/src/layouts/types.ts 的类型定义可以看到,内置布局还同时支持'fruchterman''fruchterman-gpu'两种类型关键字(后者为 GPU 加速版本)。

它支持两种布局形态:

  • 基本均匀分布:节点受力均衡、间距近似均匀,适合网络拓扑、知识图谱等需要整体结构清晰、无局部堆叠的场景;
  • 聚类布局:在基础力导向之上叠加"簇内引力",让具有相同聚类字段的节点聚集成团,适合社区结构展示、关联群组分析等场景。

布局配置选项

在 G6 的Graph实例中,通过layout字段声明布局类型与参数:

const graph = new Graph({ // ... layout: { type: 'fruchterman', // ...布局参数 }, });

Fruchterman 布局的核心参数如下表:

属性说明类型默认值是否必填
type布局类型'fruchterman'-
height布局区域高度number容器高度
width布局区域宽度number容器宽度
maxIteration最大迭代次数number500
minMovement收敛阈值number0.4
gravity中心引力,即把所有节点拉向中心的力,值越大布局越紧凑number10
speed每次迭代节点的移动速度,过大容易引起强烈震荡number5
onTick每次迭代的回调(data: LayoutMapping) => void-

各参数详解

type:必填的布局类型标识,取值为'fruchterman'。如希望启用 GPU 加速,可尝试'fruchterman-gpu'(见 packages/g6/src/layouts/types.ts)。

width / height:布局计算区域尺寸,默认取画布(容器)尺寸。从 packages/g6/src/runtime/layout.ts 的实现可以看到,运行时实际通过viewport.getCanvasSize()获取画布宽高,并以[width / 2, height / 2]作为力导向的引力中心。手动指定时布局会在该区域内分布节点。

maxIteration:迭代上限。力导向布局是渐进收敛的,迭代次数越多结果越接近稳定,但耗时也越长;如果图规模较大而迭代次数过少,布局可能未收敛就停止。当通过animation: true开启布局动画时,G6 会把这个值作为maxIteration传给底层布局并逐帧驱动(见下文"运行原理")。

minMovement:收敛阈值。当两次迭代之间节点的最大位移小于该值时,布局认为已经达到稳定状态并提前终止,避免无意义的后续计算。

gravity:中心引力大小,是所有节点被拉向画布中心的力量。值越大,节点越向中心聚拢、布局越紧凑;值越小,节点分布越松散。它与弹簧拉力、节点斥力共同决定最终密度,是调节整体观感最常用的参数之一。

speed:单次迭代节点的移动步长。适当增大可以加快收敛,但过大会使节点在平衡位置附近来回震荡、难以稳定;过小则收敛缓慢。

onTick:每完成一次迭代布局数据更新时触发的回调,接收当前的布局映射数据。G6 在布局动画模式下正是借助该回调逐帧更新元素位置(见 packages/g6/src/runtime/layout.ts),你可以用它实现自定义的逐帧渲染或调试收敛过程。

所有布局通用的附加选项

除上述专属参数外,BaseLayoutOptions(定义于 packages/g6/src/layouts/types.ts)还提供了一批对所有内置布局通用的选项,其中与 Fruchterman 布局相关的主要有:

属性说明默认值
nodeFilter指定哪些节点参与该布局,接收节点数据并返回布尔值-
comboFilter指定哪些 combo 参与该布局-
preLayout是否在初始化元素前预先计算布局(不适用于流水线布局)false
isLayoutInvisibleNodes不可见节点是否参与布局,仅在preLayouttrue时生效-
animation是否启用布局动画。对迭代型布局,会在两次迭代之间进行动画过渡false
enableWorker是否在 WebWorker 中运行布局,避免阻塞主线程false
iterations迭代型布局的迭代次数(非动画模式下运行时默认取 300,见 packages/g6/src/runtime/layout.ts)-

聚类布局参数

开启聚类模式后,Fruchterman 布局会在普通力导向计算之外,为同簇节点额外施加"簇内引力",使数据中具备相同聚类字段的节点自然聚成多个团块,同时簇与簇之间仍保持整体均匀分布。

属性说明类型默认值
clustering是否启用聚类布局booleanfalse
nodeClusterBy节点数据中用于聚类的字段名,clusteringtrue时生效string'cluster'
clusterGravity簇内引力,影响簇的紧凑程度,clusteringtrue时生效number10

使用要点:

  • clustering需显式设为true才会启用聚类计算;
  • nodeClusterBy指定从节点数据中读取哪个字段作为分组依据,默认读取顶层cluster字段;字段中取值相同的节点会被归入同一簇;
  • clusterGravity控制簇内聚合强度:值越大同一簇的节点贴得越紧、簇边界越清晰;值越小则簇内越松散,可与整体gravity配合调节簇与簇之间的间距。

示例:基本均匀分布布局

下面是一个完整的 Fruchterman 基本布局示例:11 个节点构成一个以0为中心的星型连接图,通过gravity: 5speed: 5控制布局的整体紧凑度与收敛速度,并开启drag-canvasdrag-element两个交互行为便于观察力导向的动态平衡效果。

import { Graph } from '@antv/g6'; const data = { nodes: [ { id: '0' }, { id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }, { id: '5' }, { id: '6' }, { id: '7' }, { id: '8' }, { id: '9' }, { id: '10' }, ], edges: [ { source: '0', target: '1' }, { source: '0', target: '2' }, { source: '0', target: '3' }, { source: '0', target: '4' }, { source: '0', target: '7' }, { source: '0', target: '8' }, { source: '0', target: '9' }, { source: '0', target: '10' }, { source: '2', target: '3' }, { source: '4', target: '5' }, { source: '4', target: '6' }, { source: '5', target: '6' }, { source: '9', target: '10' }, ], }; const graph = new Graph({ container: 'container', width: 500, height: 250, data, node: { style: { labelFill: '#fff', labelPlacement: 'center', labelText: (d) => d.id, }, }, layout: { type: 'fruchterman', gravity: 5, speed: 5, }, behaviors: ['drag-canvas', 'drag-element'], }); graph.render();

渲染后节点会在 500 × 250 的布局区域内受力展开,星型结构的外围节点彼此保持近似等距,整体呈现均匀的放射状分布。仓库中对应的可运行测试用例位于 packages/g6/tests/demos/layout-fruchterman-basic.ts,它加载cluster.json数据集并以相同的gravity: 5, speed: 5参数渲染,可作为实际运行效果的参照。

示例:聚类布局

下面的示例演示了聚类模式:节点数据通过data.cluster字段标记为abc三个分组,布局开启clustering: truenodeClusterBy: 'cluster',并设置较小的clusterGravity: 3保持簇内相对松散。节点样式同时使用palette.type: 'group'field: 'cluster'按簇着色,便于肉眼区分簇边界。

import { Graph } from '@antv/g6'; const data = { nodes: [ { id: '0', data: { cluster: 'a' } }, { id: '1', data: { cluster: 'a' } }, { id: '2', data: { cluster: 'a' } }, { id: '3', data: { cluster: 'a' } }, { id: '4', data: { cluster: 'a' } }, { id: '5', data: { cluster: 'b' } }, { id: '6', data: { cluster: 'b' } }, { id: '7', data: { cluster: 'b' } }, { id: '8', data: { cluster: 'c' } }, { id: '9', data: { cluster: 'c' } }, { id: '10', data: { cluster: 'c' } }, ], edges: [ { source: '0', target: '1' }, { source: '0', target: '2' }, { source: '0', target: '4' }, { source: '0', target: '6' }, { source: '2', target: '3' }, { source: '2', target: '4' }, { source: '3', target: '4' }, { source: '5', target: '6' }, { source: '6', target: '7' }, { source: '7', target: '8' }, { source: '8', target: '9' }, { source: '8', target: '10' }, ], }; const graph = new Graph({ container: 'container', width: 500, height: 250, data, node: { style: { labelFill: '#fff', labelPlacement: 'center', labelText: (d) => `${d.data.cluster}-${d.id}`, }, palette: { type: 'group', field: 'cluster', }, }, edge: { style: { endArrow: true, }, }, layout: { type: 'fruchterman', gravity: 6, speed: 5, // 聚类布局参数 clustering: true, nodeClusterBy: 'cluster', clusterGravity: 3, }, behaviors: ['drag-canvas', 'drag-element'], }); graph.render();

渲染后,abc三组节点会在簇内引力的作用下分别聚拢为三个团块,且簇间仍保持清晰的间距;边末端的箭头能帮助观察跨簇连接的走向。仓库中对应的聚类测试用例见 packages/g6/tests/demos/layout-fruchterman-cluster.ts,它把cluster.jsondata.cluster字段提升到节点顶层后作为nodeClusterBy的分组依据,展示了字段路径的处理方式。

底层运行原理:G6 如何执行 Fruchterman 布局

理解布局在 G6 内部的执行流程,有助于更好地解释上文参数的实际作用。布局执行入口位于 packages/g6/src/runtime/layout.ts 的graphLayout方法:

  1. 创建布局实例initGraphLayout(packages/g6/src/runtime/layout.ts)通过getExtension('layout', type)从注册表中取出'fruchterman'对应的构造器;由于 Fruchterman 来自@antv/layout,会经过layoutAdapter适配为标准布局实例。同时,运行时自动注入nodeSize(从元素计算尺寸)、widthheight(默认画布尺寸)与center(画布中心点)等配置。
  2. 动画模式:当animation: true时,布局以maxIteration: iterations启动迭代,并通过onTick回调把每次迭代的中间位置数据交给updateElementPosition逐帧更新到画布,从而呈现"力导向逐渐稳定"的动态效果(packages/g6/src/runtime/layout.ts)。
  3. 非动画模式:先layout.execute(data)启动计算,随后layout.stop()停止,最后调用layout.tick(iterations)一次性取出最终位置结果返回(packages/g6/src/runtime/layout.ts),iterations的默认值为 300。

可见maxIterationonTickanimationiterations是同一套迭代机制的不同入口:前者由布局参数直接指定,后两者由 G6 运行时在调用底层时传入。另外,BaseLayout基类(packages/g6/src/layouts/base-layout.ts)统一暴露了executetick与可选的stop方法,这是所有布局与运行时协作的通用契约。

更多可运行示例

仓库的测试 demos 目录中还提供了 Fruchterman 布局的其他变体用例,可作为进阶参考:

  • packages/g6/tests/demos/layout-fruchterman-basic.ts:基本分布布局;
  • packages/g6/tests/demos/layout-fruchterman-cluster.ts:聚类布局;
  • packages/g6/tests/demos/layout-fruchterman-fix.ts:固定部分节点位置的用法;
  • packages/g6/tests/demos/layout-fruchterman-gpu.ts 与 packages/g6/tests/demos/layout-fruchterman-wasm.ts:GPU / WASM 加速场景。

这些用例共同展示了 Fruchterman 布局在不同数据集与参数组合下的表现。实际使用中,建议先用默认参数渲染观察整体形态,再按"先调gravity定紧凑度、再调speed稳收敛、最后用clusterGravity修簇内聚合"的顺序逐步微调,即可获得理想的可视化效果。

  • 数据可视化
  • 前端
  • 图表库

【免费下载链接】G6

♾ A Graph Visualization Framework in JavaScript.

项目地址:https://gitcode.com/gh_mirrors/g6/G6
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询