1、初见antv X6
工作中总会遇到图可视化的需求,比如监控大屏展示。以往的需求比较简单,柱状图、折线图可以使用Echarts、antv G2快速实现。这次遇到的需求是实现拓扑图,数据关系层级比较复杂,找到了几种常见的图可视化库,如Echarts/G3/Antv,比较了下发现antv系列现在做的是越来越好了,而且维护频率很高,最终选用了antv X6(v1.34.6)。
2、需求梳理
官网说明:X6 是 AntV 旗下的图编辑引擎,提供了一系列开箱即用的交互组件和简单易用的节点定制能力,方便我们快速搭建 DAG 图、ER 图、流程图等应用。 x6可以实现图编辑,比如图元素的生成,通过拖拽绘制图形。
公司的需求不需要绘制能力,产品经理和设计想实现类似下面的关系图:
这是一个基于elkjs展示的关系图,所以本文只着重介绍ELK图和x6混合的开发。
3、什么是elkjs
elkjs是一个开源的自动布局算法,elk全称 Eclipse Layout Kernel。Eclipse相信大家很都听过,其实elkjs就是基于Eclipse内核布局的算法,并可以应用于javaScript世界。 通过阅读文档,可以看到elkjs的用法和配置。下面讲解一下我使用的历程。
4、elkjs配置使用
安装:
npm install elkjs
这里我安装的是 "elkjs": "^0.8.2" 对了还要安装web-worker, 我安装的是 "web-worker": "^1.2.0"
使用
const ELK = require('elkjs')
const elk = new ELK()
const graph = {
id: "root",
layoutOptions: { 'elk.algorithm': 'layered' },
children: [
{ id: "n1", width: 30, height: 30 },
{ id: "n2", width: 30, height: 30 },
{ id: "n3", width: 30, height: 30 }
],
edges: [
{ id: "e1", sources: [ "n1" ], targets: [ "n2" ] },
{ id: "e2", sources: [ "n1" ], targets: [ "n3" ] }
]
}
elk.layout(graph)
.then(console.log)
.catch(console.error)
首先引用elkjs并且创建实例,然后定义x6中的图结构,包含id、children、edges,还有必不可少的layoutOptions: { 'elk.algorithm': 'layered' },表明布局设置是elkjs算法的分层布局,当然如果你想使用其他布局也可以设置,官方文档里配置 点击这里。 elk可以链式调用,与Promise使用方法一样,layout方法接收参数(graph, options),可以在这里找到:
5、X6基本使用
本文假设你已经会使用了基础的x6特性
1、注册节点 Graph.registerNode
首先X6默认存在内置节点和边,存在默认的特性和样式,但是默认的往往不符合我们的需要,这时我们需要自定义节点或边。 点击这里
//调用 Graph 的静态方法 registerNode 来注册节点,注册以后就可以像使用内置节点那样来使用节点
Graph.registerNode(name: string, cls: typeof Node, overwrite?: boolean)
比如我想要这样的节点效果:
节点和边有自定义样式、文本、链接桩、图片及支持鼠标事件,且不同类型节点表现形式不同。
这里放出示例代码,展示一小部分实现代码:
//注册node
Graph.registerNode(
'elk-node', //定义名称
{
inherit: 'rect', //继承的基类
markup: [ // 定义SVG片段
{
tagName: 'rect',
selector: 'body'
},
{
tagName: 'text',
selector: 'type'
},
{
tagName: 'text',
selector: 'name'
}
],
attrs: {//定制样式
body: {
fill: '#DFE6F9',
stroke: '#0048FF',
strokeWidth: 1,
cursor: 'pointer'
},
type: {
refX: 0.5,
refY: 0.3,
fill: '#ACB9D9',
fontFamily: 'MiSans',
fontSize: 10,
cursor: 'pointer'
// textAnchor: 'end',
// textDecoration: 'underline',
},
name: {
refX: 0.5,
refY: 0.6,
fill: '#000000',
fontFamily: 'MiSans',
fontSize: 10,
cursor: 'pointer'
// fontWeight: '800',
// textAnchor: 'end',
}
},
ports: {
groups: {
//分组
SEND: {
position: {
name: 'absolute'
},
markup: [
{
tagName: 'rect',
selector: 'portBody'
}
],
attrs: {
portBody: {
magnet: 'passive',
fill: '#0048FF',
refWidth: '100%',
refHeight: '100%'
}
}
},
RECEIVE: {
position: {
name: 'absolute'
},
markup: [
{
tagName: 'rect',
selector: 'portBody'
}
],
attrs: {
portBody: {
magnet: 'passive',
fill: '#0048FF',
refWidth: '100%',
refHeight: '100%'
}
}
},
ONLY_RECEIVE: {
markup: {
tagName: 'rect',
selector: 'receiveBody'
},
position: {
name: 'absolute'
},
attrs: {
receiveBody: {
magnet: 'passive', //端口是否连接线
fill: portColor[1],
refWidth: '100%',
refHeight: '100%'
}
}
},
ONLY_SEND: {
markup: {
tagName: 'rect',
selector: 'sendBody'
},
position: {
name: 'absolute'
},
attrs: {
sendBody: {
magnet: 'passive', //端口是否连接线
fill: portColor[0],
refWidth: '100%',
refHeight: '100%'
}
}
}
}
}
},
true
)
markupmarkup 指定了渲染节点/边时使用的 SVG/HTML 片段,使用 JSON 格式描述
attrsattrs 选项定制节点样式,attrs 选项是一个复杂对象,该对象的 Key 是节点中 SVG 元素的选择器(Selector),对应的值是应用到该 SVG 元素的 SVG 属性值(如 fill 和 stroke)
ports groups:链接桩分组
2、自定义边
//注册edge
Graph.registerEdge(
'elk-edge',
{
inherit: 'edge',
attrs: {
line: {
stroke: '#ACB9D9',
strokeWidth: 1, //边宽度随数量不同而不同
targetMarker: {
name: 'block',
width: 4,
height: 4
}
}
}
},
true
)
3、鼠标事件
//示例:边鼠标移入事件,设置边的样式及文本
graph.on('edge:mouseenter', ({ e, edge, view }) => {
// console.log(e, edge, view)
const msg = edge.labels[0].attrs?.customMsg.text
edge.attr('line/stroke', '#0048FF')
edge.prop('labels/0', {
attrs: {
label: {
text: msg
}
}
})
})
4、elkjs使用
elk
.layout(graph)
.then((res) => {
addChildren(res.children || [])
addEdges(res.edges || [])
graph.resetCells(cells)
graph.item.centerContent() // 居中显示
graph.item.zoomTo(1) //默认1倍数,充满屏幕
})
.catch((err) => {
console.log(err)
})
6 总结
elkjs和X6的使用还需要多多去看官方文档,特别是要看elk的文档才能混合配置使用。有问题在评论区留言,互相交流~