antv/G6是蚂蚁金服数据可视化团队出品的一个功能完备的图可视化引擎。
介于业务需要,最近在学习G6,特此记录下~~
简单展示:
功能点:
- 连接关系图表
- 鼠标控制缩放
- 节点拖动事件
- 画布拖动事件
- 边的状态切换
- 边动画
特性:
状态:G6中提供了状态管理,指的是节点或边的状态,包括交互状态和业务状态。
动画:动画是可视化中非常重要的内容,本例中涉及到边的动画效果
字体图标:本例中使用iconfont,具体实现参照G6官方文档,比较的详细
布局:G6提供了一些布局的方法,只需要在实例化G6时进行配置就好,但是本例没有使用布局,而是指定了节点额度坐标
话不多说,上代码,使用vue写的组件,代码写的比较low~~~
完整代码
<template>
<div class="main-content-box">
<div id="container"></div>
</div>
</template>
<script>
import G6 from '@antv/g6';
export default {
name: 'g6demo',
data () {
return {
data: {
randomColor: ''
}
}
},
mounted () {
setTimeout(() => {
this.getInit()
}, 100)
},
methods: {
getInit () {
const nodes = [];
const edges = [];
// 中心节点
const centerNode = {
id: 'center',
x: 500,
y: 300,
// type: 'center-node',
size: 86,
label: '网络运营商',
text: '\ue827', //对应iconfont.css 里面的content,注意加u
style: {
fill: 'red'
},
labelCfg: {
style: {
fill: "blue"
}
},
backgroundConfig: null // 自定义项,用于判读是否需要圆背景
};
nodes.push(centerNode);
// 左侧一级节点
const leftMoudelNode = {
id: 'node1',
x: 350,
y: 300,
label: '光纤',
text: '\ue78a',
style: {
fill: 'Coral'
},
backgroundConfig: null,
size: 45,
}
nodes.push(leftMoudelNode);
edges.push({ source: 'node1', target: 'center', type: 'can-running' });
let leftGzzNode = {
}
// 左侧添加 4 个节点
for (let i = 0; i < 4; i++) {
const id = 'left' + i;
nodes.push({
id,
x: 150,
y: (i + 1) * 100 + 50,
type: 'leaf-node',
text: '\ue60e',
label: (i + 1) + '号楼',
style: {
fill: '#5B8FF9'
},
backgroundConfig: null,
size: 45,
});
edges.push({ source: id, target: 'node1', type: 'can-running' });
}
for (let i = 0; i < 4; i++) {
const id = 'leftNodeGzz' + i;
nodes.push({
id,
x: 50,
y: (i + 1) * 100 + 50,
type: 'leaf-node',
text: '\ue627',
label: '黑网吧',
style: {
fill: '#c6E5F5'
},
backgroundConfig: null,
size: 45,
});
edges.push({ source: id, target: 'left' + i, type: 'can-running' });
}
// 右侧添加 5 个节点
for (let i = 0; i < 5; i++) {
const id = 'right' + i;
const edgesId = 'edgeRight' + i
nodes.push({
id,
x: 750,
y: i * 100 + 50,
type: 'leaf-node',
text: '\ue60e',
label: (i + 5) + '号楼',
relation: '以太网',
style: {
fill: '#5B8FF9'
},
backgroundConfig: null,
size: 45,
linebackgroundConfig: {
fill: 'Coral',
},
});
edges.push({
id: edgesId,
source: 'center',
target: id,
type: 'can-running',
label: id === 'right0' ? '高速宽带' : '以太网',
style: {
stroke: 'red'
},
labelCfg: {
style: {
fill: id === 'right0' ? 'Coral' : 'cyan'
}
}
});
}
for (let i = 0; i < 5; i++) {
const id = 'rightNodeGzz' + i;
nodes.push({
id,
x: 950,
y: (i + 1) * 100,
type: 'leaf-node',
text: '\ue64c',
label: '家庭用户',
style: {
fill: '#c6E5F5'
},
backgroundConfig: null,
size: 45,
});
edges.push({ source: 'right' + i, target: id, type: 'can-running' });
}
//
G6.registerNode(
'leaf-node',
{
draw (cfg, group) {
const { backgroundConfig: backgroundStyle, style, labelCfg: labelStyle } = cfg;
if (backgroundStyle) {
group.addShape('circle', {
attrs: {
x: 0,
y: 0,
r: cfg.size,
...backgroundStyle,
},
name: 'circle-shape',
});
}
group.addShape('circle', {
attrs: {
x: -120,
y: 0,
r: 30,
...backgroundStyle,
},
name: 'circle-shape',
});
const keyShape = group.addShape('text', {
attrs: {
x: 0,
y: 0,
fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont";
textAlign: 'center',
textBaseline: 'middle',
text: cfg.text,
fontSize: cfg.size,
...style,
},
name: 'text-shape1',
});
const labelY = backgroundStyle ? cfg.size * 2 : cfg.size;
group.addShape('text', {
attrs: {
x: 0,
y: labelY,
textAlign: 'center',
text: cfg.label,
...labelStyle.style,
},
// must be assigned in G6 3.3 and later versions. it can be any value you want
name: 'text-shape1',
});
return keyShape;
},
getAnchorPoints () {
return [
[0, 0.5],
[1, 0.5],
];
},
},
'circle',
);
//使用iconfont
G6.registerNode('iconfont', {
draw (cfg, group) {
const { backgroundConfig: backgroundStyle, style, labelCfg: labelStyle } = cfg;
if (backgroundStyle) {
group.addShape('circle', {
attrs: {
x: 0,
y: 0,
r: cfg.size,
...backgroundStyle,
},
// must be assigned in G6 3.3 and later versions. it can be any value you want
name: 'circle-shape',
});
}
group.addShape('circle', {
attrs: {
x: -12,
y: 0,
r: 30,
...backgroundStyle,
},
name: 'circle-shape',
});
const keyShape = group.addShape('text', {
attrs: {
x: 0,
y: 0,
fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont";
textAlign: 'center',
textBaseline: 'middle',
text: cfg.text,
fontSize: cfg.size,
...style,
},
// must be assigned in G6 3.3 and later versions. it can be any value you want
name: 'text-shape1',
});
const labelY = backgroundStyle ? cfg.size * 2 : cfg.size;
group.addShape('text', {
attrs: {
x: 0,
y: labelY,
textAlign: 'center',
text: cfg.label,
...labelStyle.style,
},
// must be assigned in G6 3.3 and later versions. it can be any value you want
name: 'text-shape1',
});
return keyShape;
},
});
// lineDash 的差值,可以在后面提供 util 方法自动计算
const dashArray = [
[0, 1],
[0, 2],
[1, 2],
[0, 1, 1, 2],
[0, 2, 1, 2],
[1, 2, 1, 2],
[2, 2, 1, 2],
[3, 2, 1, 2],
[4, 2, 1, 2],
];
const lineDash = [4, 2, 1, 2];
const interval = 9;
G6.registerEdge(
'can-running',
{
setState (name, value, item) {
const shape = item.get('keyShape');
if (name === 'running') {
if (value) {
const length = shape.getTotalLength(); // 后续 G 增加 totalLength 的接口
let totalArray = [];
for (let i = 0; i < length; i += interval) {
totalArray = totalArray.concat(lineDash);
}
let index = 0;
shape.animate(
() => {
const cfg = {
lineDash: dashArray[index].concat(totalArray),
};
index = (index + 1) % interval;
return cfg;
},
{
repeat: true,
duration: 3000,
},
);
} else {
shape.stopAnimate();
shape.attr('lineDash', null);
}
}
},
},
'cubic-horizontal',
);
let COLOR = '#40a9ff'
const width = document.getElementById('container').scrollWidth * 0.7;
const height = document.getElementById('container').scrollHeight || 600;
const graph = new G6.Graph({
container: 'container',
width,
height,
renderer: 'svg',
modes: {
default: [
'drag-canvas',
'drag-node',
'zoom-canvas'
]
},
defaultNode: {
backgroundConfig: {
backgroundType: 'circle',
fill: COLOR,
stroke: 'LightSkyBlue',
},
type: 'iconfont',
size: 12,
style: {
fill: '#DEE9FF',
stroke: '#5B8FF9',
},
labelCfg: {
style: {
fill: COLOR,
fontSize: 12,
},
},
},
defaultEdge: {
style: {
stroke: '#b5b5b5',
},
},
});
graph.data({ nodes, edges });
graph.render();
graph.fitView();
// 响应 hover 状态
graph.on('node:mouseenter', ev => {
const node = ev.item;
const edges = node.getEdges();
edges.forEach(edge => graph.setItemState(edge, 'running', true));
});
graph.on('node:mouseleave', ev => {
const node = ev.item;
const edges = node.getEdges();
edges.forEach(edge => graph.setItemState(edge, 'running', false));
});
let model = {
type: 'can-running',
text: '\ue60e',
style: {
stroke: 'yellow'
},
labelCfg: {
style: {
fill: 'cyan'
}
}
};
//增加edge的标识id字段后
const item = graph.findById('edgeRight0');
const item2 = graph.findById('edgeRight1');
const item3 = graph.findById('edgeRight2');
const item4 = graph.findById('edgeRight3');
const item5 = graph.findById('edgeRight4');
setInterval(() => {
model.labelCfg.style.fill = this.getRandomColor()
model.style.stroke = this.getRandomColor()
graph.updateItem(item, model);
graph.updateItem(item2, model);
graph.updateItem(item3, model);
graph.updateItem(item4, model);
graph.updateItem(item5, model);
}, 1000);
},
getRandomColor () {
var rand = Math.floor(Math.random() * 0xFFFFFF).toString(16);
if (rand.length == 6) {
return '#' + rand;
} else {
return this.getRandomColor();
}
}
}
}
</script>
<style scoped>
</style>
以上就是示例的完整代码,G6的版本为3.5.0,话说G6的团队真的是很勤奋,版本更新的也蛮快的,官方文档也是越来越完善。希望越做越好吧。
Tips:
如果本文章对您有帮助,欢迎评论告知!