图
// 创建 G6 图实例
const graph = new G6.Graph({
container: 'mountNode', // 指定图画布的容器 id,与第 9 行的容器对应
// 画布宽高
width: 800,
height: 500,
});
// 读取数据
graph.data(data);
// 渲染图
graph.render();
//监听
graph.on()
Graph 对象的生命周期为:初始化 —> 加载数据 —> 渲染 —> 更新 —> 销毁。
必要配置项
上面代码中实例化 Graph 的部分使用了三个必要的配置项:
container
width
、height
常用配置项
使用 canvas 或 svg 渲染
renderer
自适应画布
fitView
fitViewPadding
fitCenter
全局元素配置
defaultNode
defaultEdge
nodeStateStyles
edgeStateStyles
布局相关
layout
交互行为相关
modes
动画相关
animate
animateCfg
插件
plugins
图形
每个图元素由图形(Shape) 组成,且都会有自己的唯一关键图形(keyShape)。
图形 Shape
各图形 Shape 的通用方法
attr(name)
获取实例的属性值。
attr(name, value)
更新实例的单个绘图属性。
attr({...})
批量更新实例绘图属性。
KeyShape
代表元素的图形
group
- addGroup(cfgs)
- addShape(type, cfgs)
变换
- 获取当前矩阵:getMatrix();
- 设置矩阵:setMatrix(matrix) 或 attr('matrix', matrix);
- 重置矩阵:resetMatrix()。
图元素
图的元素(Item)包含图上的节点 Node 、边 Edge 和 Combo 三大类。
- 样式属性,通过
style
字段对象进行配置,和元素的关键图形相关,例如fill
,stroke
。 - 其他属性,例如
id
、type
,不能在元素状态改变是进行改变,可通过 graph.updateItem 进行手动更新。
节点
G6 的内置节点包括 circle,rect,ellipse,diamond,triangle,star,image,modelRect。这些内置节点的默认样式分别如下图所示。
定义方式
// 1
defaultNode: {
type: 'circle',
// 其他配置
}
//2
graph.node((node) => {
return {
id: node.id,
type: 'rect',
style: {
fill: 'blue',
},
};
});
graph.data(data);
graph.render();
//3
const data = {
nodes: [
{
id: 'node_circle',
x: 100,
y: 100,
type: 'circle',
label: 'circle',
},]
}
自定义
G6.registerNode(
'nodeName',
{
options: {
style: {},
stateStyles: {
hover: {},
selected: {},
},
},
/**
* 绘制节点,包含文本
* @param {Object} cfg 节点的配置项
* @param {G.Group} group 图形分组,节点中图形对象的容器
* @return {G.Shape} 返回一个绘制的图形作为 keyShape,通过 node.get('keyShape') 可以获取。
* 关于 keyShape 可参考文档 核心概念-节点/边/Combo-图形 Shape 与 keyShape
*/
draw(cfg, group) {},
/**
* 绘制后的附加操作,默认没有任何操作
* @param {Object} cfg 节点的配置项
* @param {G.Group} group 图形分组,节点中图形对象的容器
*/
afterDraw(cfg, group) {},
/**
* 更新节点,包含文本
* @override
* @param {Object} cfg 节点的配置项
* @param {Node} node 节点
*/
update(cfg, node) {},
/**
* 更新节点后的操作,一般同 afterDraw 配合使用
* @override
* @param {Object} cfg 节点的配置项
* @param {Node} node 节点
*/
afterUpdate(cfg, node) {},
/**
* 响应节点的状态变化。
* 在需要使用动画来响应状态变化时需要被复写,其他样式的响应参见下文提及的 [配置状态样式] 文档
* @param {String} name 状态名称
* @param {Object} value 状态值
* @param {Node} node 节点
*/
setState(name, value, node) {},
/**
* 获取锚点(相关边的连入点)
* @param {Object} cfg 节点的配置项
* @return {Array|null} 锚点(相关边的连入点)的数组,如果为 null,则没有控制点
*/
getAnchorPoints(cfg) {},
},
// 继承内置节点类型的名字,例如基类 'single-node',或 'circle', 'rect' 等
// 当不指定该参数则代表不继承任何内置节点类型
extendedNodeName,
);
连接方式
// 接入点
anchorPoints: [
[0, 1],
[0.5, 1],
],
jsx写法
<[group|shape] [key]="value" style={{ [key]: value }}>
<[more tag] /> ...
value
边
- line:直线,不支持控制点;
- polyline:折线,支持多个控制点;
- arc:圆弧线;
- quadratic:二阶贝塞尔曲线;
- cubic:三阶贝塞尔曲线;
- cubic-vertical:垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
- cubic-horizontal:水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点;
- loop:自环。
定义方式: 与节点类似
箭头:
//默认
style: {
endArrow: true,
startArrow: true
}
//内置 6种
endArrow: {
// 使用内置箭头路径函数,参数为箭头的 宽度、长度、偏移量(默认为 0,与 d 对应)
path: G6.Arrow.triangle(10, 20, 25),
d: 25
}
// 自定义箭头
// 只有内置箭头和自定义箭头可以配置样式
style: {
endArrow: {
path: 'M 0,0 L 20,10 L 20,-10 Z',
d: 5,
fill: '#f00',
stroke: '#0f0',
opacity: 0.5,
lineWidth: 3,
// ...
},
}
自定义:同节点
combo
G6 的内置 Combo 包括 circle 和 rect 两种类型
对于熟悉图可视化类库的用户来说,节点分组是非常实用的一个功能
G6 已经存在一个节点分组 Node Group 功能,但它的机制无法支持一些较复杂的功能,例如:带有节点分组的图布局、自定义 Combo、嵌套节点分组的均匀 padding、节点与分组的边、分组与分组的边、空的节点分组等
{
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'
},
// ...
]
}
其他内容:类似与节点
高级样式
背景
defaultNode: {
position: 'left',
style: {
background: {
fill: '#ffffff',
stroke: 'green',
padding: [3, 2, 3, 2],
radius: 2,
lineWidth: 3,
},
},
三种方式更新文本样式
// 1. 实例化默认
defaultNode: {
type: 'node',
labelCfg: {
style: {
fill: '#fff',
fontSize: 14,
},
},
},
// 2.数据指定
const data = {
nodes: [
{
id: 'node1',
label: 'node1',
labelCfg: {
style: {
fill: '#fff',
fontSize: 12,
},
},
},
],
};
// 3.update/updateItem
graph.updateItem(node, {
// 节点的样式
style: {
stroke: 'blue',
},
// 节点上文本的样式
labelCfg: {
style: {
fill: '#fff',
fontSize: 12,
},
},
});
渐变色/纹理
操作
更新样式
更新节点边: 三种方式
层级
所有节点会绘制在所有边的上层
先绘制图形在后绘制图形后边
toFront()
与 toBack()
显示/隐藏
show()/hide()
多条边
自定义边 edgeType
锁定/解锁
lock()
、unlock()
和 hasLocked()
不可拖动
不可缩放
图布局
一般布局
- Random Layout:随机布局;
- Force Layout:G6 4.0 支持的经典力导向布局,支持 GPU 并行计算;
- Force Layout:引用 d3 的经典力导向布局;
- Fruchterman Layout:Fruchterman 布局,一种力导布局;
- Circular Layout:环形布局;
- Radial Layout:辐射状布局;
- MDS Layout:高维数据降维算法布局;
- Dagre Layout:层次布局;
- Concentric Layout:同心圆布局;
- Grid Layout:网格布局;
- Combo Force Layout:_V3.5 新增。_适用于带有 combo 图的力导向布局,推荐有 combo 的图使用该布局。
树图
- CompactBox Layout:紧凑树布局;
- Dendrogram Layout:树状布局(叶子节点布局对齐到同一层);
- Indented Layout:缩进布局;
- Mindmap Layout:脑图布局。
布局切换
updateLayout(params)
:布局方法或参数的切换;
graph.updateLayout({
type: 'force', // 布局名称
preventOverlap: true, // 布局参数,是否允许重叠
nodeSize: 40, // 布局参数,节点大小,用于判断节点是否重叠
linkDistance: 100, // 布局参数,边长
});
* `changeData()`:数据的切换。
graph.changeData(data2);
子图
子图布局独立与全局布局的思路,与 graph 不挂钩,直接使用实例化布局方法的方式,灌入子图数据,通过布局将位置写到相应数据中。这种机制还可供外部的全局布局使用,即使不用 G6 渲染,也可以计算节点布局后的位置
// 实例化布局
const subgraphLayout = new G6.Layout['force']({
center: [500, 450],
});
// 初始化布局,灌入子图数据
subgraphLayout.init({
nodes: subGraphNodes,
edges: subGraphEdges,
});
// 执行布局
subgraphLayout.execute();
// 图实例根据数据更新节点位置
graph.positionsAnimate();
webworker
在大规模图可视化中,布局算法往往需要较大的计算量。
workerEnabled: true, // 开启 Web-Worker
- 树图不支持 Web-Worker 机制;
- 子图布局机制暂不支持 Web-Worker 机制。
- 使用会造成交互延时需要注意
自定义布局
getDefaultCfg() {
return {};
},
/**
* 初始化
* @param {object} data 数据
*/
init(data) {},
/**
* 执行布局
*/
execute() {},
/**
* 根据传入的数据进行布局
* @param {object} data 数据
*/
layout(data) {},
/**
* 更新布局配置,但不执行布局
* @param {object} cfg 需要更新的配置项
*/
updateCfg(cfg) {},
/**
* 销毁
*/
destroy() {},
});
布局预测
import { GraphLayoutPredict } from '@antv/vis-predict-engine'
const { predictLayout, confidence } = await GraphLayoutPredict.predict(data);
const graph = new G6.Graph({
// 省略其他配置
layout: {
type: predictLayout
}
})
交互与事件
监听/绑定
- 画布、图形层次的事件,
mousedown
,mouseup
,click
,mouseenter
,mouseleave
等; - 节点/边 上的事件,
node:mousedown
,edge:click
等,以type:eventName
为事件名称; -
时机事件:
- 节点/边增删改时的事件, 例如:
beforeadditem
,afteradditem
等; - 节点/边状态改变时的事件:
beforerefreshitem
与afterrefreshitem
; - 布局时机:
beforelayout
与afterlayout
。
- 节点/边增删改时的事件, 例如:
graph.on('click', (ev) => {
const shape = ev.target;
const item = ev.item;
if (item) {
const type = item.getType();
}
});
graph.on('node:click', (ev) => {
const shape = ev.target;
const node = ev.item;
});
内置 behavior
ehavior 是 G6 提供的定义图上交互事件的机制。
G6 目前共提供了以下 14 个内置的 Behavior。
drag-combo
collapse-expand-combo
drag-canvas
zoom-canvas
drag-node
click-select
tooltip
edge-tooltip
activate-relations
brush-select
lasso-select
collapse-expand
create-edge
shortcuts-call
自定义交互 Behavior
在交互行为上, G6 主要考虑了三个场景:
- 展示关系数据;
- 可视化建模;
- 图分析。
在这些场景中只要用户可能无法一眼看清楚所有需要的信息,都需要进行交互,例如:
- 图太大,需要缩放;
- 单个节点上展示的信息太少,需要通过 tooltip 显示详情;
- 对节点进行增删改查。
交互模式 Mode
- default 模式中包含点击选中节点行为和拖拽画布行为;
- edit 模式中包含点击节点弹出编辑框行为和拖拽节点行为。
modes: {
// 支持的 behavior
default: ['drag-canvas', 'zoom-canvas'],
edit: ['click-select'],
},
// 解绑目前图模式的所有事件监听;
// 生成新的 Behavior ,进行事件初始化;
// 绑定新的行为对应的事件监听。
graph.setMode('edit');
graph.addBehaviors
graph.removeBehaviors
状态State
判断是否该使用 state 的原则很简单,从交互和业务两个层面来看:
- 某个交互动作要改变节点或边的样式及属性;
- 呈现给用户的内容会根据数据改变(如 1 代表成功,0 代表失败)。
满足上述条件其一,则应该使用 state。
在 G6 中,有两种方式配置不同状态的样式:
- 在实例化 Graph 时,通过
nodeStateStyles
和edgeStateStyles
对象定义; - 在节点/边数据中,在
stateStyles
对象中定义状态; - 设置状态:
setItemState
- 取消状态:
clearItemStates
- 更新状态:
updateItem
graph.setItemState(item, stateName, stateValue)
graph.clearItemStates(item, 'selected');
// 实例化
nodeStateStyles: {
},
//数据
stateStyles: {
},
//updataItem
stateStyles: {
// 修改 hover 状态下的样式
hover: {
opacity: 0.1,
// 修改 name 为 'node-label' 的子图形 hover 状态下的样式
'node-text': {
stroke: 'blue',
},
},
},
//优先级
item.hasState('active');
插件**
// 实例化 Image Minimap 插件
const imageMinimap = new G6.ImageMinimap({
width: 200,
graphImg: 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eD7nT6tmYgAAAAAAAAAAAABkARQnAQ'
});
const graph = new G6.Graph({
//... 其他配置项
plugins: [imageMinimap], // 配置 imageMinimap 插件
});
图算法
计算nodes,edges x/y
动画
全局
//全局
animate: true, // Boolean,切换布局时是否使用动画过度,默认为 false
graph.updateLayout(cfg) 布局的变化
graph.changeData() 数据的变化
元素
- 节点上图形的动画
- 增加带有动画的背景图形
- 节点上部分图形的旋转动画
- 圆点在沿着线运动
- 虚线运动的效果
- 线从无到有的效果
//开始
shape.animate(
(ratio) => {
// 每一帧的操作,入参 ratio:这一帧的比例值(Number)。返回值:这一帧需要变化的参数集(Object)。
// 先变大、再变小
const diff = ratio <= 0.5 ? ratio * 10 : (1 - ratio) * 10;
let radius = cfg.size;
if (isNaN(radius)) radius = radius[0];
// 返回这一帧需要变化的参数集,这里只包含了半径
return {
r: radius / 2 + diff,
};
},
{
// 动画重复
repeat: true,
duration: 3000,
easing: 'easeCubic',
},
); // 一次动画持续的时长为 3000,动画效果为 'easeCubic'
//结束
shape.stopAnimate();
转载:https://www.it610.com/article/1345031839403814912.htm