本文根据 #嘉* 《基于G6 的转化数据可视化展示 Demo》 整理而成。
背景
在某些项目中,可能会需要以树形的可视化形式来展示链路的转换数据,如有一个餐馆,统计当天的营业额,会分为线上和线下两条链路来统计,而线上链路,又分为饿了么及其他外卖平台等等。类似这种需求,参考了 G6 官网上的 Demo,提供的树图不能满足需求,我们就基于 G6 实现了该可视化链路转换图。
效果
分析
从上面的效果图我们可以看得出来,该流量链路转换图,共涉及到 2 个不同类型的节点,2 种不同类型的边,且边上还需要有 label,用于表示转换的百分比。
节点类型:
- 主节点,会在第一行上面展示,可能会分为多个链路;
- 叶子节点:在第二行展示,不会在进行分流和转换的节点。
边类型:
- 直线,边上需要显示 label;
- 折线:在主节点和第一个子节点连线的中间处转折,边上同样需要显示 label。
方案
有了上面的分析,我们就可以针对不同节点和边,使用 G6 的自定义节点及自定义边的功能来实现。
自定义转换节点
在数据中,我们会通过指定字段来区分该节点是主节点还是叶子节点,比如在我们的测试数据中,我们通过 row
字段来区分是展示到第一行还是第二行上面。
G6.registerNode('operation', {
drawShape: function (cfg, group) {
var rect = group.addShape('rect', {
attrs: cfg.row === 1
? {
x: cfg.x,
y: cfg.content ? cfg.y - 10 : cfg.y,
width: 150,
height: cfg.content ? 48 : 28,
radius: cfg.content ? 4 : 12,
stroke: '#1890FF',
fill: '#E6F7FF',
fillOpacity: 0.4,
lineWidth: 2
} : {
x: cfg.x,
y: cfg.content ? cfg.y - 10 : cfg.y,
width: 150,
height: cfg.content ? 48 : 28,
radius: cfg.content ? 24 : 12,
stroke: '#13C2C2',
fill: '#E6FFFB',
fillOpacity: 0.4,
lineWidth: 2
}
});
return rect;
},
drawLabel(cfg: any, group) {
const label = group.addShape('text', {
position: 'center',
attrs: {
x: cfg.x + 75,
y: cfg.y + 14,
position: 'center',
text: cfg.content ? cfg.label + cfg.content : cfg.label,
textAlign: 'center',
textBaseline: 'middle',
fill: '#666',
stroke: '#FFF',
fontSize: 12,
}
});
return label;
},
}, 'single-node');
自定义折线
折线的实现主要通过控制 path
来实现,path 完全和 SVG 中 path 一样,不熟悉的同学可以参考这里。
G6.registerEdge('hvh', {
draw(cfg, group) {
return this.drawShape(cfg, group);
},
drawShape(cfg: EdgeConfig, group) {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const shape = group.addShape('path', {
attrs: {
stroke: '#13C2C2',
endArrow: {
path: 'M 0 0 L 0, -5 L -10, 0, L 0, 5 Z',
fill: '#13C2C2'
},
path: [
['M', startPoint.x, 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 - 10, endPoint.y]
]
}
});
return shape;
},
drawLabel: function (cfg: EdgeConfig, group) {
const endPoint = cfg.endPoint;
var label = group.addShape('text', {
position: 'right',
attrs: {
x: endPoint.x - 20,
y: endPoint.y,
position: 'right',
textAlign: 'right',
text: cfg.label,
textBaseline: 'middle',
fill: '#fff',
stroke: '#fff',
fontSize: 12,
}
});
return label;
},
});
直线的定义比上面这些的还要简单,即 path 部分只需要 M 和 一个 L 即可。
箭头
需要特别说明一下箭头的实现,在 G6 3.4.1 以上的版本中,渲染引擎底层重构了箭头机制,使用上和之前的版本有所不同,具体区别如下:
关于箭头更详细的内容,请参考 G6 自定义边部分。
总结
在实现过程中,连接线起止锚点的指定在文档中没有找到,通过在其他 Demo 中看到,可以通过 sourceAnchor 和 targetAnchor 分别指定起止节点作为连接起点的锚点。
连线上的说明文案的设置,起初通过 edge 传值作为 label 字段设置,但对自定义折线不生效,因此通过自定义的方式,设置终点处的普通带文本的矩形节点进行添加。
说明:在 G6 3.4.7 及以上版本中,给边上的 label 设置背景色就不用这么麻烦了,直接通过 background
属性即可设置,更详细的内容请参考节点或边上 label 的背景。