本文根据 #嘉* 《基于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 的背景。
