前言
图表的需求为:
- 展现不同节点之间的联系,比如,公司为节点A,张三为节点B,它们之间的联线为雇佣,这些信息皆需展示出来
- 点击节点A,只会高亮与它相关的节点
- 单个节点可拖拽
在echarts
与g6
权衡了一段时间,最终选定echarts
,原因无非以下两种
echarts
文档齐全,上手简单echarts
使用人更多一些,遇到问题可在网上找到对应方案
绘制节点,显示信息
部分节点与连线的原始数据信息如下所示:
var nodes = [ { id: 0, labels: ["Building"], properties: { name: "辉隆大厦", building_id: "4a9387792719s" } } ... ] var links = [ { id: 0, source: 0, target: 10, type: "HIRE", properties: { relation: "雇佣" } } ]
复制
注意点:在
echarts
的关系图里,id必须为字符串,否则节点不会渲染。
随机生成-600~800
之间的坐标点,代码如下所示:
function generateRandomNum() { const startNumber = -600 const endNumber = 800 var choice = endNumber - startNumber + 10; return Math.floor(Math.random() * choice + startNumber) }
复制
处理原始数据,显示节点信息,及连线上的文字信息,代码如下所示:
nodes = nodes.map(a => { const {labels, id, properties} = a const name = labels[0] const { category, symbolSize, value } = this.initSingleNodeParam(name, properties) const showName = properties.name === 'None' ? properties.label : (properties.name || properties.component_name || properties.label) return { id: String(id), name: showName, symbolSize, x: generateRandomNum(), y: generateRandomNum(), label: { show: true }, type: name, value, category, properties } }) links = links.map(a => { return { source: String(a.source), target: String(a.target), label: { normal: { show: true, formatter: a.properties.relation } } } })
复制
initSingleNodeParam
这个函数根据不同的节点类型,返回不同的category
、symbolSize
、value
信息,部分代码如下所示:
initSingleNodeParam(name, properties) { let category = 0 let symbolSize = 40 let value = `类别:楼栋` if (name === 'Room') { category = 1 symbolSize = 32 value = `类别:${properties.label}` } else if (name === 'Company') { category = 2 symbolSize = 32 value = `类别:${properties.label}` } else if (name === 'Person') { ... } return { category, symbolSize, value } }
复制
将参数配置到option
内,初始化图表
const categories = [ { name: 'A' }, { name: 'B' }, { name: 'C' }, { name: 'D' }, { name: 'E' }, { name: 'F' } ] var option = { tooltip: {}, animationDuration: 1500, animationEasingUpdate: 'quinticInOut', hoverAnimation:false, series: [ { // name: '孪生', type: 'graph', layout: 'none', circular:{rotateLabel:true}, animation: false, data: nodes, links: links, categories: categories, roam: true, draggable: false, label: { position: 'right', formatter: '{b}' }, lineStyle: { color: 'source', curveness: 0.3 }, emphasis: { focus: 'adjacency', lineStyle: { width: 5, color: "#ffff00" } }, draggable: true, hoverAnimation:false } ] }; myChart.setOption(option);
复制
节点可拖拽
echarts
官网推荐的办法是,在每个节点上创建一个circle
,拖动circle
时,实时更新节点的坐标位置即可,切记:下面的方法需在myChart.setOption(option)
之后执行:
myChart.setOption({ graphic: echarts.util.map(option.series[0].data, function (item, dataIndex) { //使用图形元素组件在节点上划出一个隐形的图形覆盖住节点 var tmpPos=myChart.convertToPixel({'seriesIndex': 0},[item.x,item.y]); return { type: 'circle', id:String(item.id), position: tmpPos, shape: { cx: 0, cy: 0, r: 20 }, // silent:true, invisible: true, draggable: true, properties: item.properties, nodeType: item.type, dataIndex, ondrag: echarts.util.curry(onPointDragging, dataIndex), z: 100 //使图层在最高层 }; }) }); window.addEventListener('resize', updatePosition); myChart.on('dataZoom', updatePosition); myChart.on('graphRoam', updatePosition); function updatePosition() { //更新节点定位的函数 myChart.setOption({ graphic: echarts.util.map(option.series[0].data, function (item, dataIndex) { var tmpPos=myChart.convertToPixel({'seriesIndex': 0},[item.x,item.y]); return { position: tmpPos }; }) }); } function onPointDragging(dataIndex) { //节点上图层拖拽执行的函数 var tmpPos=myChart.convertFromPixel({'seriesIndex': 0},this.position); option.series[0].data[dataIndex].x = tmpPos[0]; option.series[0].data[dataIndex].y = tmpPos[1]; myChart.setOption(option); updatePosition(); }
复制
添加完上面的方法后,发现一个问题,只能在界面初始化拖动节点,一旦鼠标释放,便再也不能拖动任意节点了。最开始,将echarts
版本降至4.0.0
,发现可任意拖动节点(但不能高亮节点),后面,将echarts
版本固定在5.0.0
,便无该问题了,需注意的是,安装echarts
时,需指定5.0.0
版本
npm install echarts@5.0.0
复制
节点可点击高亮
由于节点本身具备鼠标移入高亮事件,需在节点点击高亮后,特意屏蔽节点mouseover
功能,代码如下所示:
myChart.on("click", params => { const { properties, dataIndex, nodeType } = params.event.target this.prevIndex = dataIndex this.highlight(dataIndex, myChart) const entityProperties = { ...properties, type: nodeType } this.$store.commit("jobInstance/SET_HIGHLIGHTENTITY", entityProperties); }) myChart.on("mouseout", _ => { if (this.prevIndex === null) return this.highlight(this.prevIndex, myChart) }) myChart.on("mouseover", _ => { myChart.dispatchAction({ type: 'downplay' }); })
复制
highlight
函数代码如下所示:
highlight(index, myChart) { myChart.dispatchAction({ type: "highlight", dataIndex: index }) }
复制
有任何问题,欢迎大家留言讨论