- 数据可视化
- 前端
- 图表库
【免费下载链接】G6
♾ A Graph Visualization Framework in JavaScript.
本文围绕 AntV G6 布局系统的通用配置项展开,系统讲解Graph的layout配置中所有通用字段(type、preLayout、nodeFilter、iterations、animation等)的语义、默认值与适用场景,并结合仓库源码剖析 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 时生效) | boolean | false | |
| nodeFilter | 参与该布局的节点 | (node: NodeData) => boolean | () => true | |
| comboFilter | 参与该布局的 combo 元素 | (combo: ComboData) => boolean | () => true | |
| preLayout | 使用前布局,在初始化元素前计算布局 | boolean | false | |
| enableWorker | 是否在 WebWorker 中运行布局 | boolean | - | |
| iterations | 迭代布局的迭代次数 | number | - | |
| animation | 是否启用布局动画 | boolean | false | |
| 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-3d | 3D 力导向布局 | D3Force3DLayout.zh.md |
dagre | dagre 布局 | DagreLayout.zh.md |
fishbone | 鱼骨布局 | Fishbone.zh.md |
force | 力导向布局 | ForceLayout.zh.md |
force-atlas2 | ForceAtlas2 布局 | ForceAtlas2Layout.zh.md |
fruchterman | Fruchterman 布局 | 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。
preLayout与isLayoutInvisibleNodes:控制布局执行时机与节点范围
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时,这些不可见节点也会参与布局计算。
nodeFilter与comboFilter:按业务条件筛选参与布局的元素
两个过滤函数分别控制节点与 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, }, });enableWorker与iterations:迭代布局的执行控制
enableWorker声明是否在 WebWorker 中运行布局,类型声明见WebWorkerLayoutOptions(layouts/types.ts);其实际可用性取决于所选用布局对 worker 的支持情况,配置前建议查阅具体布局文档。
iterations是 G6 运行时驱动迭代布局(iterative layout,如force、fruchterman)的总迭代步数,它不等同于某些布局内部自带的算法参数。在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字段(或需要自定义parentId、isCombo等派生字段)时,可以通过这两个函数将业务数据映射为布局所需的结构。源码中的默认实现展示了标准的映射形态(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),它负责前布局、后布局、模拟布局的调度。理解这条管线有助于判断各配置项何时生效:
- 数据获取:
getLayoutData按nodeFilter/comboFilter/preLayout/isLayoutInvisibleNodes筛选节点与 combo,并同步过滤掉不在集合内的边; - 布局分流:
stepLayout依据isTreeLayout(compact-box、mindmap、dendrogram、indented四类,见 utils/layout.ts)分流到树布局管线或图布局管线; - 实例创建:
initGraphLayout从扩展注册表取出布局类,通过适配器(layoutAdapter/legacyLayoutAdapter,utils/layout.ts)将@antv/layout的布局统一包装为继承自 BaseLayout 的标准实例,并合并width/height/center/nodeSize等默认几何配置; - 执行与回写:迭代布局按
iterations步进(可配合animation的 tick 动画),非迭代布局一次性算出终态,结果通过model.updateData与element.draw回写元素位置(runtime/layout.ts); - 后处理:布局结束后触发
BEFORE_LAYOUT/AFTER_LAYOUT等生命周期事件,并调用各 transform 的afterLayout钩子。
除@antv/layout提供的布局外,G6 仓库内还内置了两个自研布局fishbone与snake(导出于 layouts/index.ts),它们直接继承BaseLayout并实现了各自的算法,可作为理解"自定义布局需要实现什么"的参考范例(fishbone.ts、snake.ts)。
实践建议与注意事项
- 先 type 后参数:任何布局配置都必须先确定
type,通用配置是所有布局的公共底座,私有参数请在对应布局文档中查阅; - 流水线场景慎用 preLayout:
preLayout不支持数组形式的流水线布局,需要多布局串联时请使用后布局(默认行为); - 区分 iterations 与算法内部参数:
iterations只驱动 G6 运行时的迭代步进,若要调整布局算法自身的收敛系数,应使用对应布局的私有字段; - 不可见节点的处理:默认前布局会跳过隐藏/折叠节点;如需让它们参与计算,显式设置
isLayoutInvisibleNodes: true; - 字段映射保持简单:
node/edge映射返回的字段只需包含布局实际读取的部分,未提供的字段(如id?)会退回默认逻辑。
更完整的布局总览与自定义布局教程,可继续阅读 overview.zh.md 与 custom-layout.zh.md。
- 数据可视化
- 前端
- 图表库
【免费下载链接】G6
♾ A Graph Visualization Framework in JavaScript.
相关推荐
G6 布局通用配置完全指南:BaseLayout 公共参数与内置布局体系解析
G6 布局通用配置完全指南:BaseLayout 公共参数与内置布局体系解析 本文围绕 G6( @antv/g6 )中所有内置布局共同支持的通用配置项展开,系统
数据可视化前端图表库G6 布局 API 完全指南:setLayout / getLayout / layout / stopLayout 与布局配置实战
G6 布局 API 完全指南:setLayout / getLayout / layout / stopLayout 与布局配置实战 G6( @antv/g6
数据可视化前端图表库G6 随机布局(Random Layout)完全指南:用法、配置与源码级原理解析
G6 随机布局(Random Layout)完全指南:用法、配置与源码级原理解析 导读 随机布局(Random Layout)是 G6 内置布局中最轻量的一种,
数据可视化前端图表库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考