- 数据可视化
- 前端
- 图表库
【免费下载链接】G6
♾ A Graph Visualization Framework in JavaScript.
导读
Grid(网格)布局是 G6(AntV G6,一个 JavaScript 图可视化框架)内置的一种非迭代布局,它将所有节点按行、列整齐地排布成网格状,特别适合矩阵/表格型数据可视化、仪表盘、数据字典等需要"规整有序"呈现的场景。本文以官方文档 GridLayout.en.md 为主线,结合仓库中的注册表、运行时与测试代码,系统讲解 Grid 布局的配置项、默认值、防重叠机制、排序策略以及动态更新布局的完整实战方案。
Grid 布局概述与适用场景
Grid 布局的核心能力是把节点放入一个规则的行列网格中,与力导向、圆形等强调拓扑关系的布局不同,Grid 布局不追求"还原关系",而是追求"排布整齐":
- 支持根据节点数量、布局区域尺寸自动计算行数/列数,也可以手动指定
rows/cols; - 支持通过
nodeSize/nodeSpacing进行碰撞检测,避免节点相互重叠; - 支持按节点属性排序,让数值更大的节点更靠近中心;
- 支持通过
position手动指定特定节点所在的单元格。
从仓库源码看,Grid 布局在 G6 中属于注册在案的内置布局(packages/g6/src/registry/build-in.ts#L166),其类型定义继承自BaseLayoutOptions并标注type: 'grid'(packages/g6/src/layouts/types.ts#L108-L110),实际算法由@antv/layout提供。典型适用场景:
- 矩阵、表格形式的数据可视化,例如班级座位表、机房机柜、仓库货位;
- 需要把一组"互不关联"或"关系较弱"的节点进行规整陈列的场景;
- 作为组合布局的兜底排版,或配合
sortBy做集群分组展示。
快速上手:最小可用配置
最简单的 Grid 布局只需声明type: 'grid'并指定行列数即可。以下配置会生成 25 个节点(5×5 网格)与 20 条随机连线:
const graph = new Graph({ layout: { type: 'grid', cols: 5, rows: 5, }, data: { nodes: Array.from({ length: 25 }, (_, i) => ({ id: `node-${i}`, data: { value: Math.random() * 100, }, })), edges: Array.from({ length: 20 }, (_, i) => ({ id: `edge-${i}`, source: `node-${Math.floor(Math.random() * 25)}`, target: `node-${Math.floor(Math.random() * 25)}`, })), }, });一个可运行的完整示例(带容器与渲染调用):
import { Graph } from '@antv/g6'; const graph = new Graph({ container: 'container', width: 600, height: 400, layout: { type: 'grid', cols: 5, rows: 5, }, data: { nodes: Array.from({ length: 25 }, (_, i) => ({ id: `node-${i}`, data: { value: Math.random() * 100 }, })), edges: Array.from({ length: 20 }, (_, i) => ({ id: `edge-${i}`, source: `node-${Math.floor(Math.random() * 25)}`, target: `node-${Math.floor(Math.random() * 25)}`, })), }, node: { style: { size: 20, label: true, labelText: (datum) => datum.id, labelBackground: true, }, }, edge: { style: { stroke: '#bfbfbf', }, }, }); graph.render();说明:节点数据里塞入
data.value等自定义字段,可以为后续的sortBy排序、palette分组着色等能力做准备。
配置项详解:每个参数的行为与默认值
Grid 布局的完整配置在 GridLayout.en.md 中以表格形式给出,下面逐项展开说明。
标准配置写法
const graph = new Graph({ layout: { type: 'grid', begin: [0, 0], cols: 5, rows: 5, width: 300, height: 300, preventOverlap: true, nodeSize: 30, condense: false, }, });参数总表
| Property | Description | Type | Default | Required |
|---|---|---|---|---|
| type | 布局类型 | grid | - | ✓ |
| begin | 网格起始位置(左上角坐标),默认[0, 0] | [number, number] | [0, 0] | |
| cols | 列数。若未定义,算法会根据节点数量、布局空间及 rows(若设置)自动计算 | number | undefined | |
| rows | 行数。若未定义,算法会根据节点数量、布局空间及 cols(若设置)自动计算 | number | 10 | |
| width | 布局区域宽度。在 G6 中默认使用容器宽度 | number | 300 | |
| height | 布局区域高度。在 G6 中默认使用容器高度 | number | 300 | |
| condense | false 时使用全部可用画布空间;true 时使用最小画布空间 | boolean | false | |
| nodeSize | 节点尺寸(直径),用于防重叠时的碰撞检测 | Size | ((nodeData: Node) => Size) | - | |
| nodeSpacing | 节点间距,用于调整节点之间的空隙 | ((node?: Node) => number) | number | - | |
| position | 为每个节点指定所在行列 | (node?: Node) => { row?: number; col?: number; } | undefined | |
| preventOverlap | 是否防止节点重叠。需要节点数据中存在 nodeSize 或 size 属性 | boolean | false | |
| preventOverlapPadding | 防重叠时的内边距。仅在 preventOverlap 为 true 时生效 | number | 10 | |
| sortBy | 排序依据(节点属性名)。数值越大的节点越靠近中心。若未定义则按度(degree)排序 | string | undefined |
核心参数深度解读
cols 与 rows(行列数)
两者互为补足关系:只给cols时,行数由节点总数自动推导;只给rows时,列数自动推导;都未设置时按行数为 10 的默认逻辑计算。手动指定时需确保cols * rows >= 节点数,否则多余节点会被截断到网格范围之外。官方在线 Demo 提供了 2~10 的调节范围(GridLayout.en.md)。
width 与 height(布局区域)
决定网格可铺陈的空间。需要注意:官方文档特别注明,在 G6 中布局宽度默认使用容器宽度;而当 Grid 布局单独使用(未接容器)时默认值为 300。从源码看,width/height同样被声明在BaseLayoutOptions中,默认取画布尺寸(packages/g6/src/layouts/types.ts#L86-L96)。
condense(紧凑模式)
false(默认):网格占满整个可用布局空间,节点之间的间距会被均匀拉大,视觉上更松散;true:按最小必要空间排布,节点紧凑靠拢,适合节点数量多、画布有限的情况。
nodeSize 与 nodeSpacing(尺寸与间距)
nodeSize既可以是固定数字,也可以是接收节点数据、返回尺寸的函数(Size | ((nodeData) => Size));nodeSpacing同样支持函数或数字两种形式,用于在防重叠时额外拉开间隙;- 两者共同参与防重叠算法中的碰撞检测与位置微调。
preventOverlap 与 preventOverlapPadding(防重叠)
官方文档明确:必须配合nodeSize或节点数据中的size属性一起使用,只有数据中存在data.size或布局中设置了nodeSize,才能执行节点重叠的碰撞检测。防重叠开启后,preventOverlapPadding(默认 10)控制节点之间的内边距大小。
sortBy(排序)
指定节点属性名作为排序依据,数值越大越靠近网格中心;若未定义,则使用节点的**度(degree,即连接的边数)**作为排序依据。仓库 utils 中的注释还提到一个兼容性细节:Grid 布局会直接读取data[sortBy],因此需要避免在数据中使用data、style等容易与内部字段冲突的属性名(packages/g6/src/utils/layout.ts#L287-L288)。
补充:Grid 布局同其他布局一样,继承了
BaseLayoutOptions的通用能力,例如nodeFilter(过滤参与布局的节点)、enableWorker(是否在 Web Worker 中执行)、animation(布局动画)等,详见 packages/g6/src/layouts/types.ts#L42-L98。
进阶用法一:自定义网格与排序着色
在官方文档的 Custom Configuration 示例中,可以通过组合begin、cols、rows、width、height、condense、sortBy精细控制网格形态,并配合节点palette做分组着色:
const graph = new Graph({ layout: { type: 'grid', begin: [50, 50], // 从 [50, 50] 开始排布 cols: 4, // 4 列 rows: 6, // 6 行 width: 400, // 布局区域宽度 height: 600, // 布局区域高度 preventOverlap: true, // 防止节点重叠 nodeSize: 30, // 节点尺寸 condense: true, // 使用最小空间 sortBy: 'value', // 按 value 属性排序 }, data: { nodes: Array.from({ length: 24 }, (_, i) => ({ id: `node-${i}`, data: { value: Math.random() * 100, // 排序依据属性 }, })), edges: Array.from({ length: 20 }, (_, i) => ({ id: `edge-${i}`, source: `node-${Math.floor(Math.random() * 24)}`, target: `node-${Math.floor(Math.random() * 24)}`, })), }, node: { style: { size: 20, label: true, labelText: (datum) => datum.id, labelBackground: true, }, palette: { type: 'group', field: (datum) => datum.data.value, color: ['#1783FF', '#00C9C9', '#F08F56', '#D580FF'], }, }, edge: { style: { stroke: '#bfbfbf', }, }, });要点解析:
begin: [50, 50]让网格整体向右下偏移,避免与画布边缘贴死;sortBy: 'value'使value更大的节点落在更靠近中心的单元格;palette的field按data.value分组着色,与排序协同,形成"中心高亮、外围渐变"的视觉层次;condense: true在 4×6 网格中会压缩空白,使节点更紧凑。
进阶用法二:为特定节点指定行列位置
当需要"锁定"某些关键节点到固定单元格(例如四角、关键路径节点)时,使用position回调。它对返回{ row, col }的节点强制放置,返回undefined的节点则继续走自动排布:
const graph = new Graph({ layout: { type: 'grid', cols: 5, rows: 5, position: (node) => { // 为特定节点指定位置 if (node.id === 'node-0') return { row: 0, col: 0 }; // 左上角 if (node.id === 'node-1') return { row: 0, col: 4 }; // 右上角 if (node.id === 'node-2') return { row: 4, col: 0 }; // 左下角 if (node.id === 'node-3') return { row: 4, col: 4 }; // 右下角 return undefined; // 其余节点自动排布 }, }, data: { nodes: Array.from({ length: 25 }, (_, i) => ({ id: `node-${i}`, })), edges: Array.from({ length: 20 }, (_, i) => ({ id: `edge-${i}`, source: `node-${Math.floor(Math.random() * 25)}`, target: `node-${Math.floor(Math.random() * 25)}`, })), }, node: { style: { size: 20, label: true, labelText: (datum) => datum.id, labelBackground: true, }, }, edge: { style: { stroke: '#bfbfbf', }, }, }); graph.render();注意事项:
row/col均从 0 开始计数;- 已被
position占用的单元格,自动排布会跳过,不会产生节点覆盖; - 建议只在少量关键节点上使用,全部节点手工指定会丧失 Grid 自动布局的意义。
进阶用法三:运行时动态更新布局参数
Grid 布局并不是"一次性"的——你可以通过graph.setLayout()+graph.layout()在运行时动态调整行列数、防重叠、排序等参数并重新布局。官方在线 Demo 的交互面板即采用此模式:
const options = { type: 'grid', cols: 5, rows: 5, width: 400, height: 400, preventOverlap: true, nodeSize: 30, condense: false, }; // 修改任意参数后重新执行布局 optionFolder.onChange(({ property, value }) => { graph.setLayout({ type: 'grid', [property]: value, }); graph.layout(); });从源码看,setLayout更新的是图实例的布局配置,layout()触发实际计算并调用model.updateData()把结果写回节点坐标(packages/g6/src/runtime/layout.ts)。这一能力让"用户拖拽调节滑块、图实时重排"成为可能,非常适合配置面板、可视化编辑器类产品。
仓库中的实证:Demo 与单元测试
仓库内置了 Grid 布局的完整示例与测试,可直接作为参考或运行验证:
- 交互示例:layout-grid.ts 使用
cluster.json数据集,演示了默认sortBy按度排序,以及通过面板在id、degree、cluster三种排序策略间切换:
export const layoutGrid: TestCase = async (context) => { const graph = new Graph({ ...context, data, node: { style: { labelText: (d) => d.id } }, layout: { type: 'grid', sortBy: (d) => d.data.cluster, }, behaviors: ['zoom-canvas', 'drag-canvas', 'drag-element', 'click-select'], }); await graph.render(); // ... };- 单元测试:grid.spec.ts 覆盖了
sortBy默认行为与sortBy: 'id'两种场景的 SVG 快照断言:
describe('grid', () => { it('sortBy default', async () => { await expect(graph).toMatchSnapshot(__filename, 'sortby-default'); }); it('sortBy id', async () => { graph.setLayout({ type: 'grid', sortBy: 'id' }); await graph.layout(); await expect(graph).toMatchSnapshot(__filename, 'sortby-id'); }); });多布局流水线:pipeline.spec.ts 中还验证了 Grid 可作为
layout: [...]数组流水线中的一环,说明它能与 dagre 等其他布局串联使用。真实用例:官方示例站点的 Grid Layout 基础示例 提供了开箱即用的演示代码。
常见问题与最佳实践
Q1:节点重叠了怎么办?
确保两件事同时满足:布局中设置nodeSize(或节点数据带size),并开启preventOverlap: true。还可配合preventOverlapPadding增加间隙、nodeSpacing拉开间距。
Q2:行列数怎么选?
规则明确:cols * rows >= 节点数即可铺满。若节点数动态变化,建议只给cols(或只给rows),让算法自动推导另一维,避免出现空行空列。
Q3:想让重点节点居中?
用sortBy指定数值型属性,数值越大越靠中心;无属性时默认按节点度排序,即"连接越多的节点越居中"。
Q4:与力导向等布局混用?
Grid 是非迭代布局,一次计算完成。在多布局流水线(layout: [grid, force])中通常放在靠前阶段做初排,后续布局再做精排。
最佳实践小结:
- 纯表格陈列用
condense: true压缩空间;需要呼吸感用condense: false; - 节点尺寸不统一时,
nodeSize传函数按节点返回尺寸,防重叠更准确; - 排序字段避免与内部保留字段(
data、style等)重名; - 交互式调参场景使用
setLayout + layout()组合,实时反馈。
总结
Grid 布局是 G6 中"秩序感"最强的布局方案:通过cols/rows控制网格密度,begin/width/height控制铺陈区域,preventOverlap/nodeSize/nodeSpacing保证不重叠,sortBy实现数值中心化排序,position实现定点放置,再配合setLayout()动态重排,可以胜任从静态矩阵表到交互式配置面板的各类规整排版需求。官方文档详见 GridLayout.en.md,源码入口见 packages/g6/src/layouts/types.ts 与 packages/g6/src/registry/build-in.ts#L166。
- 数据可视化
- 前端
- 图表库
【免费下载链接】G6
♾ A Graph Visualization Framework in JavaScript.
相关推荐
notebooklm-py 的事件循环亲和性契约:NotebookLMClient 的 Loop-Affinity 设计与实现
notebooklm py 的事件循环亲和性契约:NotebookLMClient 的 Loop Affinity 设计与实现 导读 NotebookLMCli
数据可视化前端图表库G6 径向布局(Radial Layout)完全指南:从基础配置到动态调参实战
G6 径向布局(Radial Layout)完全指南:从基础配置到动态调参实战 导读 径向布局(Radial Layout)是 G6 中一类以 根节点为中心、按
数据可视化前端图表库MaaAssistantArknights 开发指南:从环境搭建、PR 流程到代码格式化规范
MaaAssistantArknights 开发指南:从环境搭建、PR 流程到代码格式化规范 本指南以《明日方舟》小助手 MAA(MaaAssistantArk
数据可视化前端图表库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考