什么是 AntV G6 ?
企业级应用开发往往需要使用流程图组件,AntV G6就是一款可以开箱即用的由蚂蚁金服提供的,全新一代数据可视化解决方案,是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画等图可视化的基础能力。旨在让关系变得透明,简单。让用户获得关系数据的 Insight
G6 可以做什么 ?
上面这些关系图都是它可以轻松搞定的,我们可以通过他快速创建出自己的图分析和编辑引用
如何快速使用G6呢
第一步: 使用命令行在项目目录下执行以下命令:
npm install --save @antv/g6
第二步:在需要的位置引用它
import G6 from '@antv/g6';
第三步:在引用页面制造容器
<div id="container" style="width:100%;height:500px;"></div>
第四步:在data数据中 ,创建适用的流程图数据
data: {
nodeExtraAttrs: {
begin: {
fill: 'rgba(24, 144, 255, 0.1)',
stroke: '#1890FF',
},
end: {
fill: 'rgba(242, 65, 48, 0.1)',
stroke: '#F24130',
},
ORIGINAL: {
fill: 'rgba(38, 191, 89, 0.1)',
stroke: '#26BF59',
},
},
nodes: [
{
id: 'node1',
label: 'node1',
text: null,
key: 'ORIGINAL',
},
{
id: 'node2',
label: 'node2',
text: null,
key: 'begin',
},
{
id: 'node3',
label: 'node3',
text: 'node3',
key: 'ORIGINAL',
},
{
id: 'node4',
label: 'node4',
text: 'node4',
key: 'begin',
},
{
id: 'node5',
label: 'node5',
text: 'node5',
key: 'ORIGINAL',
},
{
id: 'node6',
label: 'node6',
text: 'node6',
key: 'end',
},
{
id: 'node7',
label: 'node7',
text: 'node7',
key: 'end',
},
{
id: 'node8',
label: 'node8',
text: 'node8',
key: 'begin',
},
{
id: 'node9',
label: 'node9',
text: 'node9',
key: 'ORIGINAL',
},
{
id: 'node10',
label: 'node10',
text: 'node10',
key: 'begin',
},
],
edges: [
{
source: 'node1',
target: 'node2',
},
{
source: 'node2',
target: 'node3',
},
{
source: 'node3',
target: 'node4',
},
{
source: 'node4',
target: 'node5',
},
{
source: 'node5',
target: 'node6',
},
{
source: 'node6',
target: 'node7',
},
{
source: 'node6',
target: 'node8',
},
{
source: 'node7',
target: 'node9',
},
{
source: 'node8',
target: 'node9',
},
{
source: 'node9',
target: 'node10',
},
],
}
第五步:具体实现画流程图的方法
drawView() {
// 重写方法
const _extends =
Object.assign ||
function (target) {
for (let i = 1; i < arguments.length; i++) {
const source = arguments[i];
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
// 自定义节点 内置节点无法满足需求
// G6.registerNode(typeName: string, nodeDefinition: object, extendedTypeName?: string)
G6.registerNode(
// 该新节点类型名称
'node',
// 该新节点类型的定义
// 当有 extendedTypeName (第三个参数)时,没被复写的函数将会继承 extendedTypeName 的定义
{
// cfg 节点身上所有的配置:包括label,size,x,y坐标等
// 这个方法,每渲染一个节点,执行一次
drawShape: (cfg, group) => {
// if(cfg.key==="ORIGINAL") 圆形
//圆形
if(cfg.key==="ORIGINAL") {
// ctg上的id key label 都可以决定当前节点的类型
cfg.size = (cfg.label.length / 10) * 130;
let widthX = 2;
const rect = group.addShape('ellipse', {
attrs: _extends(
{
x: -widthX / 2,
y: 0,
rx: 60,
ry: 40,
fill: 'blue',
},
this.nodeExtraAttrs[cfg.key]
),
});
return rect;
}else{
// ctg上的id key label 都可以决定当前节点的类型
cfg.size = (cfg.label.length / 10) * 130;
let widthX = 0;
if (cfg.label.length / 10 < 1) {
widthX = 120;
} else {
widthX = cfg.size;
}
const rect = group.addShape('rect', {
attrs: _extends(
{
x: -widthX / 2,
y: -25,
width: widthX,
height: 50,
radius: 4,
fill: '#FFD591',
fillOpacity: 1,
},
// 相当于:
// ORIGINAL: {
// fill: 'rgba(38, 191, 89, 0.1)',
// stroke: '#26BF59',
// },
// 属性为fill 和 stroke的对象
this.nodeExtraAttrs[cfg.key]
),
});
return rect;
}
},
/**
* 获取锚点(相关边的连入点)
* @param {Object} cfg 节点的配置项
* @return {Array|null} 锚点(相关边的连入点)的数组,如果为 null,则没有控制点
*/
// 自定义锚点
getAnchorPoints: () => {
return [
[0, 0.5], // 左侧中间
[1, 0.5], // 右侧中间
];
},
},
// 被继承的节点类型,可以是内置节点类型名,也可以是其他自定义节点的类型名。
// extendedTypeName 未指定时代表不继承其他类型的节点;
// 例如基类 'single-node',或 'circle', 'rect' 等
'single-shape'
);
/**
* 自定义带箭头的贝塞尔曲线 edge
*/
G6.registerEdge('line-with-arrow', {
itemType: 'edge',
draw: (cfg, group) => {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const centerPoint = {
x: (startPoint.x + endPoint.x) / 2,
y: (startPoint.y + endPoint.y) / 2,
};
// 控制点坐标
const controlPoint = {
x: (startPoint.x + centerPoint.x) / 2,
y: startPoint.y,
};
// 为了更好的展示效果, 对称贝塞尔曲线需要连到箭头根部
const path = group.addShape('path', {
attrs: {
path: [
['M', startPoint.x, startPoint.y],
['Q', controlPoint.x, controlPoint.y, centerPoint.x, centerPoint.y],
['T', endPoint.x, endPoint.y],
['L', endPoint.x, endPoint.y],
],
stroke: '#ccc',
lineWidth: 1.6,
endArrow: {
path: 'M 4,0 L -4,-4 L -4,4 Z',
d: 4,
},
},
});
return path;
},
});
const graph = new G6.Graph({
// 常用配置项
// 类型:Boolean;默认:'false'。图是否自适应画布。
fitView: true,
// 类型:Number | Array;默认:0。图自适应画布时的四周留白像素值。fitView 为 true 时生效。
// fitViewPadding : 0
// 类型:Boolean;默认:'false'。是否平移图使其中心对齐到画布中心。v3.5.1 后支持。
fitCenter: true,
// bloodView:流程图容器id
container: 'container',
//modes 交互行为相关
// 配置多种交互模式及其包含的交互事件的。
modes: {
default: [
'drag-canvas',
// 'zoom-canvas', 缩放
{
type: 'tooltip',
formatText(model) {
const cfg = model.text;
const text = model.text;
// cfg.forEach((row) => {
// text.push(row.label + ':' + row.value + '<br>');
// });
return text;
},
offset: 30,
},
],
},
// 若数据中不存在节点位置,则默认为随机布局。配置布局类型及其参数。
layout: {
// 类型 总共三种:径向:radial 有向分层:dagre 力导:force
type: 'dagre',
// 'LR':从左至右布局;
rankdir: 'LR', // 可选可选值:'TB' | 'BT' | 'LR' | 'RL',默认为图的中心 TB
},
// defaultNode类型:Object。默认情况下全局节点的配置项,包括样式属性和其他属性
// G6 的内置节点包括
// circle圆形,rect长方形,ellipse椭圆,diamond菱形,triangle三角形,
// star五角星,image图片,modelRect卡片,donut圆形(v4.2.5 起支持)。
defaultNode: {
type: 'node', // 这里的type指向自定义节点
// size:300,
labelCfg: {
style: {
fill: '#595959',
fontSize: 14,
},
},
},
// defaultEdge 类型:Object。默认情况下全局边的配置项,包括样式属性和其他属性
defaultEdge: {
type: 'line-with-arrow',
style: {
endArrow: true,
lineWidth: 2,
stroke: '#ccc',
},
},
});
this.data.edges.forEach((item, index) => {
if (item.upstreamKey === 'WORK') {
item.labelCfg = {
autoRotate: true,
style: {
fill: '#262626', // 文字颜色
fontSize: 10,
cursor: 'pointer',
background: {
fill: 'rgba(38, 191, 89, 0.1)',
stroke: '#26BF59',
padding: [4.5, 16.5, 4.5, 16.5],
radius: 2,
},
},
};
} else if (item.upstreamKey === 'ORIGINAL') {
item.labelCfg = {
autoRotate: true,
style: {
fill: '#262626', // 文字颜色
fontSize: 10,
cursor: 'pointer',
background: {
fill: 'rgba(255, 167, 64, 0.1)',
stroke: '#FFA740',
padding: [4.5, 16.5, 4.5, 16.5],
radius: 2,
},
},
};
} else if (item.upstreamKey === 'FINAL') {
item.labelCfg = {
autoRotate: true,
style: {
fill: '#262626', // 文字颜色
fontSize: 10,
cursor: 'pointer',
background: {
fill: 'rgba(24, 144, 255, 0.1)',
stroke: '#1890FF',
padding: [4.5, 16.5, 4.5, 16.5],
radius: 2,
},
},
};
}
});
// 单击节点
graph.on('node:click', (e) => {
const nodeItem = e.item // 获取被点击的节点元素对象
console.log(nodeItem._cfg)
})
// 鼠标进入节点
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item // 获取鼠标进入的节点元素对象
console.log('鼠标移入', nodeItem._cfg)
})
// 双击节点
graph.on('node:dblclick', (e) => {
const nodeItem = e.item // 获取被点击的节点元素对象
console.log('双击', nodeItem._cfg)
})
graph.data(this.data);
// 渲染
graph.render();
},
第六步:在需要调用的地方进行引用
this.$nextTick(() => {
this.drawView()
});
第七步:完整代码如下
实现效果如下:
<template>
<div>
<div id="container" style="width:100%;height:500px;"></div>
</div>
</template>
<script>
import G6 from '@antv/g6';
export default {
components: {
},
props: {
// 是否显示
page: {
type: String,
default: null
}
},
setup() {
},
data() {
return {
url: null,
// 保存自定义节点的数据
// 一般实际开发中,流程图节点样式都是在自定义的
nodeExtraAttrs: {
begin: {
fill: 'rgba(24, 144, 255, 0.1)',
stroke: '#1890FF',
},
end: {
fill: 'rgba(242, 65, 48, 0.1)',
stroke: '#F24130',
},
ORIGINAL: {
fill: 'rgba(38, 191, 89, 0.1)',
stroke: '#26BF59',
},
},
data: {
nodes: [
{
id: 'node1',
label: 'node1',
text: null,
key: 'ORIGINAL',
},
{
id: 'node2',
label: 'node2',
text: null,
key: 'begin',
},
{
id: 'node3',
label: 'node3',
text: 'node3',
key: 'ORIGINAL',
},
{
id: 'node4',
label: 'node4',
text: 'node4',
key: 'begin',
},
{
id: 'node5',
label: 'node5',
text: 'node5',
key: 'ORIGINAL',
},
{
id: 'node6',
label: 'node6',
text: 'node6',
key: 'end',
},
{
id: 'node7',
label: 'node7',
text: 'node7',
key: 'end',
},
{
id: 'node8',
label: 'node8',
text: 'node8',
key: 'begin',
},
{
id: 'node9',
label: 'node9',
text: 'node9',
key: 'ORIGINAL',
},
{
id: 'node10',
label: 'node10',
text: 'node10',
key: 'begin',
},
],
edges: [
{
source: 'node1',
target: 'node2',
},
{
source: 'node2',
target: 'node3',
},
{
source: 'node3',
target: 'node4',
},
{
source: 'node4',
target: 'node5',
},
{
source: 'node5',
target: 'node6',
},
{
source: 'node6',
target: 'node7',
},
{
source: 'node6',
target: 'node8',
},
{
source: 'node7',
target: 'node9',
},
{
source: 'node8',
target: 'node9',
},
{
source: 'node9',
target: 'node10',
},
],
}
}
},
watch: {
page: {
handler(val, oldV) {
this.url = val
switch (val) {
case '物料工程':
this.url = '/diagram/wuliaogongcheng.html'
break
default :
console.log('step other')
}
},
immediate: true
}
},
created() {
},
mounted() {
this.$nextTick(() => {
this.drawView();
});
},
methods: {
drawView() {
// 重写方法
const _extends =
Object.assign ||
function (target) {
for (let i = 1; i < arguments.length; i++) {
const source = arguments[i];
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
// 自定义节点 内置节点无法满足需求
// G6.registerNode(typeName: string, nodeDefinition: object, extendedTypeName?: string)
G6.registerNode(
// 该新节点类型名称
'node',
// 该新节点类型的定义
// 当有 extendedTypeName (第三个参数)时,没被复写的函数将会继承 extendedTypeName 的定义
{
// cfg 节点身上所有的配置:包括label,size,x,y坐标等
// 这个方法,每渲染一个节点,执行一次
drawShape: (cfg, group) => {
// if(cfg.key==="ORIGINAL") 圆形
//圆形
if(cfg.key==="ORIGINAL") {
// ctg上的id key label 都可以决定当前节点的类型
cfg.size = (cfg.label.length / 10) * 130;
let widthX = 2;
const rect = group.addShape('ellipse', {
attrs: _extends(
{
x: -widthX / 2,
y: 0,
rx: 60,
ry: 40,
fill: 'blue',
},
this.nodeExtraAttrs[cfg.key]
),
});
return rect;
}else{
// ctg上的id key label 都可以决定当前节点的类型
cfg.size = (cfg.label.length / 10) * 130;
let widthX = 0;
if (cfg.label.length / 10 < 1) {
widthX = 120;
} else {
widthX = cfg.size;
}
const rect = group.addShape('rect', {
attrs: _extends(
{
x: -widthX / 2,
y: -25,
width: widthX,
height: 50,
radius: 4,
fill: '#FFD591',
fillOpacity: 1,
},
// 相当于:
// ORIGINAL: {
// fill: 'rgba(38, 191, 89, 0.1)',
// stroke: '#26BF59',
// },
// 属性为fill 和 stroke的对象
this.nodeExtraAttrs[cfg.key]
),
});
return rect;
}
},
/**
* 获取锚点(相关边的连入点)
* @param {Object} cfg 节点的配置项
* @return {Array|null} 锚点(相关边的连入点)的数组,如果为 null,则没有控制点
*/
// 自定义锚点
getAnchorPoints: () => {
return [
[0, 0.5], // 左侧中间
[1, 0.5], // 右侧中间
];
},
},
// 被继承的节点类型,可以是内置节点类型名,也可以是其他自定义节点的类型名。
// extendedTypeName 未指定时代表不继承其他类型的节点;
// 例如基类 'single-node',或 'circle', 'rect' 等
'single-shape'
);
/**
* 自定义带箭头的贝塞尔曲线 edge
*/
G6.registerEdge('line-with-arrow', {
itemType: 'edge',
draw: (cfg, group) => {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const centerPoint = {
x: (startPoint.x + endPoint.x) / 2,
y: (startPoint.y + endPoint.y) / 2,
};
// 控制点坐标
const controlPoint = {
x: (startPoint.x + centerPoint.x) / 2,
y: startPoint.y,
};
// 为了更好的展示效果, 对称贝塞尔曲线需要连到箭头根部
const path = group.addShape('path', {
attrs: {
path: [
['M', startPoint.x, startPoint.y],
['Q', controlPoint.x, controlPoint.y, centerPoint.x, centerPoint.y],
['T', endPoint.x, endPoint.y],
['L', endPoint.x, endPoint.y],
],
stroke: '#ccc',
lineWidth: 1.6,
endArrow: {
path: 'M 4,0 L -4,-4 L -4,4 Z',
d: 4,
},
},
});
return path;
},
});
const graph = new G6.Graph({
// 常用配置项
// 类型:Boolean;默认:'false'。图是否自适应画布。
fitView: true,
// 类型:Number | Array;默认:0。图自适应画布时的四周留白像素值。fitView 为 true 时生效。
// fitViewPadding : 0
// 类型:Boolean;默认:'false'。是否平移图使其中心对齐到画布中心。v3.5.1 后支持。
fitCenter: true,
// bloodView:流程图容器id
container: 'container',
//modes 交互行为相关
// 配置多种交互模式及其包含的交互事件的。
modes: {
default: [
'drag-canvas',
// 'zoom-canvas', 缩放
{
type: 'tooltip',
formatText(model) {
const cfg = model.text;
const text = model.text;
// cfg.forEach((row) => {
// text.push(row.label + ':' + row.value + '<br>');
// });
return text;
},
offset: 30,
},
],
},
// 若数据中不存在节点位置,则默认为随机布局。配置布局类型及其参数。
layout: {
// 类型 总共三种:径向:radial 有向分层:dagre 力导:force
type: 'dagre',
// 'LR':从左至右布局;
rankdir: 'LR', // 可选可选值:'TB' | 'BT' | 'LR' | 'RL',默认为图的中心 TB
},
// defaultNode类型:Object。默认情况下全局节点的配置项,包括样式属性和其他属性
// G6 的内置节点包括
// circle圆形,rect长方形,ellipse椭圆,diamond菱形,triangle三角形,
// star五角星,image图片,modelRect卡片,donut圆形(v4.2.5 起支持)。
defaultNode: {
type: 'node', // 这里的type指向自定义节点
// size:300,
labelCfg: {
style: {
fill: '#595959',
fontSize: 14,
},
},
},
// defaultEdge 类型:Object。默认情况下全局边的配置项,包括样式属性和其他属性
defaultEdge: {
type: 'line-with-arrow',
style: {
endArrow: true,
lineWidth: 2,
stroke: '#ccc',
},
},
});
this.data.edges.forEach((item, index) => {
if (item.upstreamKey === 'WORK') {
item.labelCfg = {
autoRotate: true,
style: {
fill: '#262626', // 文字颜色
fontSize: 10,
cursor: 'pointer',
background: {
fill: 'rgba(38, 191, 89, 0.1)',
stroke: '#26BF59',
padding: [4.5, 16.5, 4.5, 16.5],
radius: 2,
},
},
};
} else if (item.upstreamKey === 'ORIGINAL') {
item.labelCfg = {
autoRotate: true,
style: {
fill: '#262626', // 文字颜色
fontSize: 10,
cursor: 'pointer',
background: {
fill: 'rgba(255, 167, 64, 0.1)',
stroke: '#FFA740',
padding: [4.5, 16.5, 4.5, 16.5],
radius: 2,
},
},
};
} else if (item.upstreamKey === 'FINAL') {
item.labelCfg = {
autoRotate: true,
style: {
fill: '#262626', // 文字颜色
fontSize: 10,
cursor: 'pointer',
background: {
fill: 'rgba(24, 144, 255, 0.1)',
stroke: '#1890FF',
padding: [4.5, 16.5, 4.5, 16.5],
radius: 2,
},
},
};
}
});
// 单击节点
graph.on('node:click', (e) => {
const nodeItem = e.item // 获取被点击的节点元素对象
console.log(nodeItem._cfg)
})
// 鼠标进入节点
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item // 获取鼠标进入的节点元素对象
console.log('鼠标移入', nodeItem._cfg)
})
// 双击节点
graph.on('node:dblclick', (e) => {
const nodeItem = e.item // 获取被点击的节点元素对象
console.log('双击', nodeItem._cfg)
})
graph.data(this.data);
// 渲染
graph.render();
},
}
}
</script>