title: 节点分组 Combo
order: 8
V3.5 后支持的全新节点分组 Combo 机制。原节点分组仍可使用。
对于熟悉图可视化类库的用户来说,节点分组是非常实用的一个功能。此前,G6 已经存在一个节点分组 Node Group 功能,但它的机制无法支持一些较复杂的功能,例如:带有节点分组的图布局、自定义 Combo、嵌套节点分组的均匀 padding、节点与分组的边、分组与分组的边、空的节点分组等。V3.5 推出了全新的节点分组 Combo 机制,能够支持所有常用功能,参考 Demo。
数据结构
为保持 G6 源数据数据结构的稳定性,我们在原来的数据结构上做了如下修改:
- 新增
combos
数组,用于定义图上所有的 Combo 及其配置。combos
数组中的一个数据项有如下属性:
属性名 | 类型 | 是否必须 | 示例 | 解释 |
---|---|---|---|---|
id | string | true | ‘comboA’ | 一个 Combo 的唯一标识,必须是 string 类型,必须唯一 |
parentId | string | false | ‘comboB’ | 该 Combo 的父 Combo 的 ID |
padding | Number / Number[] | false | 10 或 [ 10, 20, 10, 20 ] | 该 Combo 内边距 |
label | string | false | ‘combo A’ | 该 Combo 的文本标签 |
style | Object | false | 该 Combo 的样式配置项,详见内置 Combo 配置文档及各类型 Combo 的文档 | |
labelCfg | Object | false | 该 Combo 的文本标签样式配置项,详见内置 Combo 配置文档及各类型 Combo 的文档 |
combos
数组中一个数据项的示例:
{
id: 'comboA',
label: 'A',
parentId: 'comboC'
},
- 在 nodes 数组中的数据项内加入
comboId
属性,表示该节点与某个 Combo 的从属关系。
{
nodes: [
{
id: 'node1',
comboId: 'comboA' // node1 属于 comboA
},
{
id: 'node2',
comboId: 'comboB' // node2 属于 comboB
},
{
id: 'node3' // node3 不属于任何 combo
},
// ...
],
edges: [
// ...
],
combos: [
{ // 定义 comboA
id: 'comboA',
label: 'A',
parentId: 'comboC'
},
{ // 定义 comboB
id: 'comboB',
parentId: 'comboB'
},
{ // 定义 comboC,这是一个空的 combo
id: 'comboC'
},
// ...
]
}
渲染 Combo
- 当存在
combos
数组、nodes
数组中的节点数据项中存在comboId
时,G6 将根据数据及parentId
或comboId
判断各 Combo 及节点之间的层级关系,并渲染出嵌套的 Combo; - 当没有使用任何布局时,需要在
nodes
数组中指定各个节点的坐标信息,即节点的x
和y
属性值,否则会使用随机的位置; - 空的 combo 将使用随机位置。
⚠️ 注意: 必须在示例化图时配置 groupByTypes
设置为 false
,带有 combo 的图中元素的视觉层级才能合理。
const data = {
nodes: [{
id: 'node6', comboId: 'comboC', label: 'rect',
x: 383, y: 240
}, {
id: 'node1', label: 'node1', comboId: 'comboA',
x: 316, y: 136
}, {
id: 'node9', label: 'node9', comboId: 'comboB',
x: 523,
y: 70
}, {
id: 'node2', label: 'node2', comboId: 'comboA',
x: 278, y: 121
}, {
id: 'node3', label: 'node3', comboId: 'comboA',
x: 308, y: 78
}, {
id: 'node7', comboId: 'comboB', label: 'node7',
x: 512, y: 125
}, {
id: 'node10', label: 'node10', comboId: 'comboC',
x: 469, y: 211
}],
edges: [{
source: 'node1', target: 'node2'
}, {
source: 'node2', target: 'node3'
}],
combos: [{
id: 'comboA', label: 'combo A', parentId: 'comboC'
}, {
id: 'comboB', label: 'combo B', parentId: 'comboC'
}, {
id: 'comboC', label: 'combo C'
}, {
id: 'comboD', label: 'combo D'
}]
}
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
// 必须将 groupByTypes 设置为 false,带有 combo 的图中元素的视觉层级才能合理
groupByTypes: false,
});
graph.data(data);
graph.render();
此时,还未使用布局算法,combo 范围及位置是根据子节点数据中位置信息(x
,y
)确定的。需要自动布局配置专为 combo 设计的布局算法 'comboForce'
,详见Combo Force 教程。
上面例子演示了最简单的默认 Circle Combo,G6 还内置了 Rect Combo。可在各自文档中查看如何配置样式。如果这两种类型的 Combo 还不能满足要求,可以使用 自定义 Combo 机制,自定义 Combo Demo。
此时,不能对分组中的节点及 Combo 进行任何操作,接下来,我们介绍可以对 Combo 进行的各种操作。
Combo 交互
只是简单地将 Combo 渲染出来,并没有多大的实用价值,只有支持一系列的交互操作后,才能最大程度地体现 Combo 的价值。
在 G6 中,我们内置了 drag-combo
、collapse-expand-combo
、drag-node
三个 Behavior。
drag-combo
drag-combo
Behavior,支持拖动 Combo ,拖动 Combo 过程中,会动态改变 Combo 中节点和边的位置,在拖拽完成以后,保持 Combo 和节点的相对位置不变。还可以通过拖拽改变 Combo 的从属关系。
collapse-expand-combo
collapse-expand-combo
Behavior,支持双击 Combo 收起和展开 Combo ,收起 Combo 以后,隐藏 Combo 中的所有节点,外部节点和 Combo 中节点有连线的情况下,所有连接会连接到 Combo 上面。若图配置有布局且该 behavior 的 relayout
配置项为 true
(默认为 true
),则该 behavior 被触发后会触发图的重新布局。若希望避免重新布局,可以配置 relayout
为 false
,或通过监听 combo 点击事件和 graph.collapseExpandCombo API 控制收缩展开逻辑。
drag-node
拖拽节点过程中,动态改变节点与父 Combo 的从属关系。
配置交互
通过下面代码在实例化图时将三个 behavior 配置到图上即可使用上述交互:
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
// 必须将 groupByTypes 设置为 false,带有 combo 的图中元素的视觉层级才能合理
groupByTypes: false,
modes: {
default: ['drag-combo', 'collapse-expand-combo', 'drag-node'],
}
});
适用场景
- 风控、反洗钱、保险骗保、网络诈骗、信用卡诈骗等场景下团伙分析;
- 特征分析:同一个分组中的节点在某些特征上面比较相似;
- 整理节点:当类似的节点放到一个分组中,只渲染分组,不渲染节点,减少干扰元素。