JavaScript|Echarts5.* 关系图谱(relation graph)添加节点拖拽、点击节点高亮效果

前言 图表的需求为:

  • 展现不同节点之间的联系,比如,公司为节点A,张三为节点B,它们之间的联线为雇佣,这些信息皆需展示出来
  • 点击节点A,只会高亮与它相关的节点
  • 单个节点可拖拽
echartsg6权衡了一段时间,最终选定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必须为字符串,否则节点不会渲染。
【JavaScript|Echarts5.* 关系图谱(relation graph)添加节点拖拽、点击节点高亮效果】随机生成-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这个函数根据不同的节点类型,返回不同的categorysymbolSizevalue信息,部分代码如下所示:
initSingleNodeParam(name, properties) { let category = 0 let symbolSize = 40 let value = https://www.it610.com/article/`类别:楼栋` if (name ==='Room') { category = 1 symbolSize = 32 value = https://www.it610.com/article/`类别:${properties.label}` } else if (name ==='Company') { category = 2 symbolSize = 32 value = https://www.it610.com/article/`类别:${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 }) }

有任何问题,欢迎大家留言讨论

    推荐阅读