前言
图表的需求为:
- 展现不同节点之间的联系,比如,公司为节点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
})
}
有任何问题,欢迎大家留言讨论