G6 布局通用配置项完全指南:LayoutOptions 核心字段与运行机制
2026/9/24 2:30:51 网站建设 项目流程
  • 数据可视化
  • 前端
  • 图表库

【免费下载链接】G6

♾ A Graph Visualization Framework in JavaScript.

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

本文围绕 AntV G6 布局系统的通用配置项展开,系统讲解Graphlayout配置中所有通用字段(typepreLayoutnodeFilteriterationsanimation等)的语义、默认值与适用场景,并结合仓库源码剖析 G6 布局控制器(LayoutController)的前/后布局管线与过滤逻辑。读完本文,你将能够独立配置任何内置或自定义布局的通用参数,理解布局动画与迭代布局的执行差异,并掌握多布局流水线(pipeline)的用法。

布局配置的入口:Graph 的layout选项

在 G6 中,布局通过Graph构造时的layout字段声明。layout的完整类型定义是LayoutOptions = SingleLayoutOptions | SingleLayoutOptions[](见 spec/layout.ts),即既可以是一个单布局配置对象,也可以是多个布局配置组成的数组,后者会按顺序依次执行,形成"布局流水线"(pipeline)。

const graph = new Graph({ container: 'container', data, layout: { type: 'antv-dagre', // 布局类型,通用配置中最核心的字段 // ...其他通用配置与布局私有配置 }, });

除了初始化配置,G6 还在运行时提供了四个与布局相关的 API(实现于 runtime/graph.ts):

  • setLayout(layout | (prev) => next):动态修改布局配置,传入函数时可根据旧配置计算新配置;
  • getLayout():读取当前布局配置;
  • layout(layoutOptions?):手动触发一次布局计算,等价于执行布局管线的postLayout(graph.ts);
  • stopLayout():停止迭代型布局(如force)的迭代动画,常用于迭代时间过长时在点击画布/节点事件里手动终止(graph.ts)。

通用配置项全解

下表即本文的核心,也是所有布局(内置与自定义)共用的配置字段,定义于 layouts/types.ts 的BaseLayoutOptions

属性描述类型默认值必选
type布局类型,内置布局或自定义布局的名称Type-
isLayoutInvisibleNodes不可见节点是否参与布局(当 preLayout 为 true 时生效)booleanfalse
nodeFilter参与该布局的节点(node: NodeData) => boolean() => true
comboFilter参与该布局的 combo 元素(combo: ComboData) => boolean() => true
preLayout使用前布局,在初始化元素前计算布局booleanfalse
enableWorker是否在 WebWorker 中运行布局boolean-
iterations迭代布局的迭代次数number-
animation是否启用布局动画booleanfalse
width布局区域宽度,默认使用当前容器宽度number-
height布局区域高度,默认使用当前容器高度number-
center布局中心点[number, number] \| [number, number, number]-
node节点字段映射,用于把业务字段映射为布局字段(datum) => ({ id?, x?, y?, z?, parentId?, isCombo? })-
edge边字段映射,用于把业务字段映射为布局字段(datum) => ({ id?, source?, target? })-

补充说明:

  • width/height/center@antv/layout统一支持的通用布局字段;
  • node/edge用于适配非标准id/source/target业务数据;
  • iterations是 G6 运行时用于驱动迭代布局的步数,不等同于某些布局内部自己的算法参数。

type:布局类型的名称

type必选,指定使用哪个内置布局或自定义布局。布局实例通过扩展注册表(registry)按名称获取:getExtension('layout', type)(见 runtime/layout.ts)。若名称未注册,控制台会打印警告The layout of ${type} is not registered.且跳过该布局。

const graph = new Graph({ // 其他配置... layout: { type: 'antv-dagre', }, });

内置type的可选值及对应文档如下:

type说明对应文档
antv-dagre基于 dagre 定制的布局AntvDagreLayout.zh.md
circular环形布局CircularLayout.zh.md
combo-combined适用于存在组合的布局ComboCombinedLayout.zh.md
concentric同心圆布局ConcentricLayout.zh.md
d3-force基于 D3 的力导向布局D3ForceLayout.zh.md
d3-force-3d3D 力导向布局D3Force3DLayout.zh.md
dagredagre 布局DagreLayout.zh.md
fishbone鱼骨布局Fishbone.zh.md
force力导向布局ForceLayout.zh.md
force-atlas2ForceAtlas2 布局ForceAtlas2Layout.zh.md
fruchtermanFruchterman 布局FruchtermanLayout.zh.md
grid网格布局GridLayout.zh.md
mds高维数据降维算法布局MdsLayout.zh.md
radial径向布局RadialLayout.zh.md
random随机布局RandomLayout.zh.md
snake蛇形布局Snake.zh.md
compact-box紧凑树布局CompactBoxLayout.zh.md
dendrogram树状布局DendrogramLayout.zh.md
mindmap思维导图布局MindmapLayout.zh.md
indented缩进树布局IndentedLayout.zh.md

这些内置类型的名称声明可以在 layouts/types.ts 的BuiltInLayoutOptions联合类型中逐一定义,例如force布局的类型为'force' | 'gforce'fruchterman'fruchterman' | 'fruchterman-gpu'd3-force-3d的注册名称为'd3-force3d',配置时请以对应文档与类型声明为准。除内置布局外,type也可以填写通过register('layout', ...)注册的自定义布局名称,参见 custom-layout.zh.md。

preLayoutisLayoutInvisibleNodes:控制布局执行时机与节点范围

preLayout(前布局)表示在元素初始化之前就计算布局,适合需要提前确定节点位置的场景(如某些布局依赖画布尺寸)。从源码看,G6 渲染流程中会先判断是否为前布局再决定执行顺序(runtime/graph.ts):

if (!this.options.layout) { // 无布局:直接绘制 } else if (!this.rendered && isPreLayout(this.options.layout)) { // 前布局:先计算位置,再初始化元素 await this.context.layout!.preLayout(drawData); ... } else { // 后布局:先绘制,再执行布局 await Promise.all([animation?.finished, this.context.layout!.postLayout()]); }

判断逻辑在 utils/layout.ts:isPreLayout要求layout不是数组且配置了preLayout: true。也就是说,前布局不适用于流水线布局(多布局数组),这一点在BaseLayoutOptions.preLayout的源码注释中也有明确说明(layouts/types.ts)。

isLayoutInvisibleNodes只在preLayout为 true 时生效(layouts/types.ts)。在前布局模式下,默认情况下以下节点会被排除在布局之外:

  • style.visibility === 'hidden'的节点;
  • 祖先(树结构TREE_KEY或 combo 结构COMBO_KEY)处于折叠状态的节点;

对应逻辑见 runtime/layout.ts 的filterFn。当isLayoutInvisibleNodes: true时,这些不可见节点也会参与布局计算。

nodeFiltercomboFilter:按业务条件筛选参与布局的元素

两个过滤函数分别控制节点与 combo 是否参与该布局,默认均为() => true。布局控制器在getLayoutData中会基于这两个函数筛选出待布局数据,并且只保留两端节点都在布局集合内的边(runtime/layout.ts)。

需要注意:非前布局(后布局)模式下,节点的元素必须已经存在且未被销毁才会参与布局(runtime/layout.ts),这保证了布局不会作用于尚未渲染的元素。典型用法是只对某一类节点布局:

const graph = new Graph({ layout: { type: 'force', nodeFilter: (node) => node.data.category !== 'fixed', // 固定节点不参与力导向计算 comboFilter: (combo) => combo.style.visible !== false, }, });

enableWorkeriterations:迭代布局的执行控制

enableWorker声明是否在 WebWorker 中运行布局,类型声明见WebWorkerLayoutOptions(layouts/types.ts);其实际可用性取决于所选用布局对 worker 的支持情况,配置前建议查阅具体布局文档。

iterations是 G6 运行时驱动迭代布局(iterative layout,如forcefruchterman)的总迭代步数,它不等同于某些布局内部自带的算法参数。在graphLayout中可以看到它的实际消费方式(runtime/layout.ts):

const { animation, iterations = 300 } = options; // 默认 300 步 if (isLayoutWithIterations(layout)) { if (animation) { // 有动画:基于 tick 逐帧更新位置 return await layout.execute(data, { animate: true, maxIteration: iterations, onTick: ... }); } // 无动画:直接执行到终态 layout.execute(data); layout.stop(); return layout.tick(iterations); }

即:未显式配置时迭代步数默认为 300;开启animation后,每次迭代都会通过onTick回调驱动元素位置更新,形成逐步趋稳的动画效果。

animation:是否启用布局动画

默认false。开启后:

  • 对迭代布局(isLayoutWithIterations为 true 的布局),会在两次迭代之间进行动画过渡;
  • 对非迭代布局,会在终态位置计算完成后做一次从当前位置到目标位置的补间动画(runtime/layout.ts)。

另外,G6 会把全局动画配置注入布局选项:LayoutController.presetOptions会在全局动画开启时默认置animation: true(runtime/layout.ts),因此布局动画的最终生效是"全局动画配置 && 布局配置"共同作用的结果。

width/height/center:布局区域的几何约束

这三个字段由@antv/layout统一支持。不配置时,G6 在initGraphLayout中会自动取画布尺寸并计算中心点(runtime/layout.ts):

const [width, height] = viewport!.getCanvasSize(); const center = [width / 2, height / 2];

d3-force/d3-force-3d这类三维坐标布局,中心点会被特殊处理为{ x, y, z }对象形式(runtime/layout.ts)。此外,布局所需的nodeSize也会被自动推导:优先取配置值,否则从元素的实际尺寸(element.attributes.size)或节点样式计算得出(runtime/layout.ts),这也是布局区域计算的重要输入。

node/edge:业务字段到布局字段的映射

当业务数据的节点、边没有使用标准的id/source/target字段(或需要自定义parentIdisCombo等派生字段)时,可以通过这两个函数将业务数据映射为布局所需的结构。源码中的默认实现展示了标准的映射形态(utils/layout.ts):

const defaultNode = (datum) => ({ id, ...(style?.x != null ? { x: style.x } : {}), ...(style?.y != null ? { y: style.y } : {}), ...(style?.z != null ? { z: style.z } : {}), parentId, // 取自 datum.combo ...(isCombo ? { isCombo: true } : {}), }); const defaultEdge = (datum) => ({ id, source: datum.source, target: datum.target });

自定义映射示例:

const graph = new Graph({ data: { nodes: [{ id: 'n1', data: { bizId: 'a', pos: [10, 20] } }] }, layout: { type: 'grid', node: (datum) => ({ id: datum.data.bizId, x: datum.data.pos[0], y: datum.data.pos[1] }), edge: (datum) => ({ id: datum.id, source: datum.source, target: datum.target }), }, });

布局执行管线的底层机制

所有通用配置最终都会汇入LayoutController(runtime/layout.ts),它负责前布局、后布局、模拟布局的调度。理解这条管线有助于判断各配置项何时生效:

  1. 数据获取getLayoutDatanodeFilter/comboFilter/preLayout/isLayoutInvisibleNodes筛选节点与 combo,并同步过滤掉不在集合内的边;
  2. 布局分流stepLayout依据isTreeLayoutcompact-boxmindmapdendrogramindented四类,见 utils/layout.ts)分流到树布局管线或图布局管线;
  3. 实例创建initGraphLayout从扩展注册表取出布局类,通过适配器(layoutAdapter/legacyLayoutAdapter,utils/layout.ts)将@antv/layout的布局统一包装为继承自 BaseLayout 的标准实例,并合并width/height/center/nodeSize等默认几何配置;
  4. 执行与回写:迭代布局按iterations步进(可配合animation的 tick 动画),非迭代布局一次性算出终态,结果通过model.updateDataelement.draw回写元素位置(runtime/layout.ts);
  5. 后处理:布局结束后触发BEFORE_LAYOUT/AFTER_LAYOUT等生命周期事件,并调用各 transform 的afterLayout钩子。

@antv/layout提供的布局外,G6 仓库内还内置了两个自研布局fishbonesnake(导出于 layouts/index.ts),它们直接继承BaseLayout并实现了各自的算法,可作为理解"自定义布局需要实现什么"的参考范例(fishbone.ts、snake.ts)。

实践建议与注意事项

  • 先 type 后参数:任何布局配置都必须先确定type,通用配置是所有布局的公共底座,私有参数请在对应布局文档中查阅;
  • 流水线场景慎用 preLayoutpreLayout不支持数组形式的流水线布局,需要多布局串联时请使用后布局(默认行为);
  • 区分 iterations 与算法内部参数iterations只驱动 G6 运行时的迭代步进,若要调整布局算法自身的收敛系数,应使用对应布局的私有字段;
  • 不可见节点的处理:默认前布局会跳过隐藏/折叠节点;如需让它们参与计算,显式设置isLayoutInvisibleNodes: true
  • 字段映射保持简单node/edge映射返回的字段只需包含布局实际读取的部分,未提供的字段(如id?)会退回默认逻辑。

更完整的布局总览与自定义布局教程,可继续阅读 overview.zh.md 与 custom-layout.zh.md。

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

【免费下载链接】G6

♾ A Graph Visualization Framework in JavaScript.

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

相关推荐

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

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

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

立即咨询