Echarts5.* 关系图谱(relation graph)如何以某节点为圆心,子节点环绕其排列布局?

20 篇文章 1 订阅
4 篇文章 0 订阅

前言

Echarts5.*中,关系图谱(relation graph)中的每个节点必须给xy坐标,才会显示在画布上,在前一篇文章里我采用的方法是,随机生成坐标点,可这样会导致节点布局混乱,无法理清各个节点之间的关系。希望能做到如下的优化:

  1. 选取某个节点作为中心点(取画布中心值)
  2. 特定类型的子节点,会环绕在它父类节点周围显示

后期的效果如下图所示:

选取画布中心点

核心代码如下所示:

<template>
    <div ref="main" id="graph"></div>
</template>

<script>
import * as echarts from 'echarts'
export default {
    name: "graph",
    methods: {
    	getCenterPos() {
            const x = (this.$refs.main.clientWidth - 40) * 0.5
            const y = (this.$refs.main.clientHeight - 200) * 0.5
            return {
                x,
                y
            }
        }
    }
}
</script>

以父节点为圆心,将子节点等分并返回坐标信息

该方法如下所示:

<template>
    <div ref="main" id="graph"></div>
</template>

<script>
import * as echarts from 'echarts'
export default {
    name: "graph",
    methods: {
    	/**
    	 * @param {Object} {x,y} 圆心坐标
    	 * @param {Number} index 索引值,即该子节点在所有同类型子节点中的位置索引(数组索引位置)
    	 * @params {Number} nodesLen 子节点个数
    	 * @params {Number} radius 半径
    	 */
    	circledNodesPosition({x,y}, index, nodesLen, radius = 20) {
            const avd = 360 / nodesLen;
            const ahd = avd * Math.PI / 180
            return {
                x: Math.sin((ahd*index))*radius + x,
                y: Math.cos((ahd*index))*radius + y
            }
        },
    }
</script>

360 / nodesLen,即每个子节点对应的角度
avd * Math.PI / 180, 即每个子节点对应的弧度

Math.sin((ahd*index))*radius,得到该子节点与圆中心的x方向偏移值,若需知道该子节点的x坐标信息,则需加上圆心的x

将所有节点按类型分组

核心代码如下所示:

initGraph() {
	const buildingNode = []
	
	const componentNodes = []
	
	const personNodes = []
	let personCenterPos = null
	
	const companyNodes = []
	let companyCenterPos = null
	
	const roomNodes = []
	let roomCenterPos = null
	
	var center = this.getCenterPos()
	graph.nodes.forEach(a => {
		const {labels, id, properties} = a
		const type = labels[0]
		if (type === 'Building') {
		    buildingNode.push({
		        ...param,
		        x: center.x,
		        y: center.y
		    })
		} else if(type === 'Component') {
		    componentNodes.push({
		        ...param
		    })
		} else if (type === 'Person') {
		    personNodes.push({
		        ...param
		    })
		} else if (type === 'Company') {
		    companyNodes.push({
		        ...param
		    })
		} else if (type === 'Room') {
		    roomNodes.push({
		        ...param
		    })
		}
	})
	componentNodes.forEach((a,index) => {
	    var pos = this.circledNodesPosition(center, index, componentNodes.length)
	    a.x = pos.x
	    a.y = pos.y
	    const cType = a.properties.find(a=> a.key === 'component_name').value
	    if (cType === '人') {
	        personCenterPos = {
	            x: a.x,
	            y: a.y
	        }
	    } else if (cType === '企业') {
	        companyCenterPos = {
	            x: a.x,
	            y: a.y
	        }
	    } else if (cType === '房间') {
	        roomCenterPos = {
	            x: a.x,
	            y: a.y
	        }
	    }
	})
	
	const generateNodesPos = (nodes, centerPos, nodesLen) => {
        nodes.forEach((a,index) => {
		    var pos = this.circledNodesPosition(centerPos, index, nodesLen, 5)
		    a.x = pos.x
		    a.y = pos.y
		})
	}
	
	generateNodesPos(personNodes, personCenterPos, personNodes.length)
	generateNodesPos(companyNodes, companyCenterPos, companyNodes.length)
	generateNodesPos(roomNodes, roomCenterPos, roomNodes.length)
	
	const nodes = [
	    ...buildingNode,
	    ...componentNodes,
	    ...personNodes,
	    ...companyNodes,
	    ...roomNodes
	]
	
	var option = {
	    tooltip: {},
	    animationDuration: 1500,
	    animationEasingUpdate: 'quinticInOut',
	    hoverAnimation:false,
	    series: [
	        {
	            // name: '孪生',
	            type: 'graph',
	            layout: 'none',
	            circular:{rotateLabel:true},
	            animation: false,
	            data: nodes
	            ...
	        }
	    ]
	} 
	myChart.setOption(option);
}

在上面代码中,我先从所有节点中过滤出componentNodes,因为它是类型聚合点,再根据不同类型,将子节点划分到对应数组中,找出同类型中的圆中心点,遍历同类型子节点,生成各个子节点的x,y坐标信息即可

​​

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值