图表的需求为:
在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 [email protected]
由于节点本身具备鼠标移入高亮事件,需在节点点击高亮后,特意屏蔽节点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
})
}
有任何问题,欢迎大家留言讨论