此文章是AntV G6从零到一(Vue)的下篇博客,本文主要分享实际案例,关于AntV G6的详细内容,请参考上篇文章。
需求
本次实现的案例如下图的结构:
分析
观察UI图发现:整体结构是流程图 ;节点与节点之间具有组合 的功能;节点总体是文本加图形的上下结构;边不是G6
默认边;右下角的加减号代表具有放大缩小功能。
所以接下来需要做的工作就比较清晰了:
- 实现自定义节点
- 实现自定义边
- 实现组合(Combo)
- 图布局配置
- 整体封装
实现
自定义节点
js
// 图片对象
const imgData = {oppositeE, oppositeR, fileE, fileR, taskE, taskR, programE, programR, entityE, entityR, kalfaE, kalfaR};
// 注册节点
G6.registerNode(
'lk-node-one',
{
options: {
style: {
cursor: 'pointer',
}
},
// 绘制完成以后的操作,用户可继承现有的节点或边,在 `afterDraw()` 方法中扩展图形或添加动画
// cfg 节点的配置项
// group 图形分组,节点中图形对象的容器
afterDraw(cfg, group) {
group.addShape('image', {
// 属性配置
attrs: {
x: -10,
y: -55,
fill: '#fff',
width: 40,
height: 40,
// 根据nodeType显示不同图片
img: imgData[cfg.nodeType],
cursor: 'pointer',
},
// // 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
name: 'image-shape',
});
},
// 调整锚点 anchorPoint,确定节点与边的相交的位置
getAnchorPoints() {
return [
[0, 0.5], // 左侧中间
[1, 0.5], // 右侧中间
];
},
},
'rect'
);
自定义边
js
G6.registerEdge('lk-line-one', {
/**
* 绘制节点
* @param {Object} cfg 节点的配置项
* @param {G.Group} group 图形分组,节点中图形对象的容器
* @return {G.Shape} 返回一个绘制的图形作为 keyShape
*/
draw(cfg, group) {
// 开始节点
const startPoint = cfg.startPoint;
// 结束节点
const endPoint = cfg.endPoint;
// 图形
const shape = group.addShape('path', {
// 属性
attrs: {
// 描边颜色
stroke: '#4e5568',
// path是svg里面的path,M是移动画笔,moveto的缩写,L是lineto的缩写,线移动
// 大写代表绝对定位,小写代表相对定位
path: [
['M', startPoint.x + 10, startPoint.y],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y], // 三分之一处
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y], // 三分之二处
['L', endPoint.x, endPoint.y],
],
// 描边宽度
lineWidth: 1,
// 开始箭头,画圆
startArrow: {
// path是svg里面的path,M是移动画笔,moveto的缩写,L是lineto的缩写,线移动,a是弧形
path: 'M 0,0 a 4 4,0,1,1, 4 4 a 4 4, 0,1,1, 4, -4',
},
// 结束箭头,画箭头
endArrow: {
// 自定义箭头指向(0, 0),尾部朝向 x 轴正方向的 path
path: 'M 0,0 l -8,6 l 0,0 l 8,-6 l -8,-6 l 0,0 l 8,6 Z',
},
},
// 在 G6 3.3 及之后的版本中,必须指定 name,可以是任意字符串,但需要在同一个自定义元素类型中保持唯一性
name: 'edge-shape',
});
return shape;
},
});
实现组合(Combo)
文档中关于Combo的章节在这里。其中的使用方式是渲染数据中的nodes
数据的comboId
字段和combos
数据中配置的id
相匹配。
js
export const graphData = {
nodes: [
{id: '0', nodeType: 'opposite', label: '统一DPI'},
{id: '1', nodeType: 'fileE', label: '4G XDR_S1MME', comboId: 'preNode'},
{id: '2', nodeType: 'entityR', label: 'fact_pscp_s1mme_front', comboId: 'preNode'},
{id: '3', nodeType: 'taskR', label: 'fact_pscp_s1mme_front_sync', comboId: 'coreNode'},
{id: '4', nodeType: 'entityR', label: 'lte_cm_projdata', comboId: 'coreNode'},
],
edges: [
{source: '0', target: '1'},
{source: '1', target: '2'},
{source: '2', target: '3'},
{source: '3', target: '4'},
],
combos: [
// 前置节点
{
id: 'preNode',
// 显示文本
label: '前置节点',
// 类型
type: 'rect',
size: 320,
padding: 30,
style: {
stroke: '#4761f0',
lineWidth: 1,
lineDash: 5,
fill: 0,
},
labelCfg: {
style: {
fill: '#4761f0',
fontSize: 14,
},
},
},
// 核心节点
{
id: 'coreNode',
label: '核心节点',
type: 'rect',
size: 320,
padding: 30,
style: {
stroke: '#4761f0',
lineWidth: 1,
lineDash: 5,
fill: 0,
},
labelCfg: {
style: {
fill: '#4761f0',
fontSize: 14,
},
},
},
],
};
图布局配置
js
new G6.Graph({
// 传入的渲染节点id
container: id,
// 传入的DOM ref
width: ref.clientWidth,
height: ref.clientHeight,
// 自适应画布
fitView: true,
// 自适应画布时四周留白像素值,fitView为true时生效
fitViewPadding: 40,
layout: {
// 布局类型
type: 'dagre',
// 从左至右布局
rankdir: 'LR',
// 对齐到右下角
align: 'DR',
// 是否保留布局连线的控制点
controlPoints: true,
// nodesep 节点竖直间距
nodesepFunc: () => 20,
// ranksep 节点水平方向层间距
ranksepFunc: () => 20,
},
// 交互管理,一个mode是多种行为Behavior的组合
modes: {
default: ['zoom-canvas', 'drag-canvas'],
},
renderer: 'svg', // 使用 Dom node 的时候需要使用 svg 的渲染形势
// 默认节点配置
defaultNode: {
type: 'lk-node-one',
size: [300, 50],
style: {
fill: '#ffffff',
radius: 2,
},
labelCfg: {
style: {
fill: '#333333',
fontSize: 18,
cursor: 'pointer',
},
},
},
defaultEdge: {
type: 'lk-line-one',
},
fitCenter: true,
});
整合封装
最后只需要将所有的配置封装到一个js文件中即可:
代码
以上代码不包含图片物料,如果需要完整案例,请访问Demo。如下所示:
总结
以上就是此次AntV G6
第二篇的案例分享,跟上篇文章不一样的是,此篇文章少了配置的讲解,直接展示思路和代码,总体处理步骤还是:节点、边、图布局、最后封装。
经过上一个案例《AntV G6从零到一(Vue)》的实践之后,这次的案例实践要轻松不少,也印证了熟能生巧的道理。
ok,就这样!下一篇文章再见!