官网:series-graph
官网示例:关系图
前提是项目中有Echarts包,要是没有,则需要添加该包npm install Echarts
。该文用的版本是"echarts": "^5.4.3"
。
- 关系图组件a.vue
<template>
<div class="contentWrap">
<!-- 关系层级过滤 -->
<a-row>
<a-col :span="24">
<a-form-item label="关系层级" :labelCol="{ xs: { span: 24 }, sm: { span: 5 } }" :wrapperCol="{ xs: { span: 24 }, sm: { span: 16 } }">
<a-select placeholder="请选择关系层级" v-model:value="selectedLevel" @change="updateChart">
<template v-for="(obj, index) in levelOptions" :key="index">
<a-select-option :value="obj.value"> {{ obj.label }}</a-select-option>
</template>
</a-select>
</a-form-item>
</a-col>
</a-row>
//放echart图标的
<div v-if="data.nodes.length" ref="chartContainer" class="wrap"></div>
<a-empty v-else description="暂无数据" />
</div>
</template>
- 配置项及逻辑处理
<script lang="ts" setup>
import { ref, unref, reactive, nextTick, onMounted, onUnmounted, defineProps, watch} from 'vue';
import * as echarts from 'echarts';
const chartContainer = ref<HTMLDivElement | null>(null);
let myChart = reactive({});
const selectedLevel = ref('1');
const levelOptions = ref([
{ label: '一级关系', value: '1' },
{ label: '二级关系', value: '2' },
{ label: '三级关系', value: '3' },
]);
// 接口返回的数据格式如下
let data = reactive({
// 关键点,nodes的那么不能重复,所以需要加上id加以区别,让data中的节点的name不能重复。
nodes: [
{ id: '0', name: '张三', level: '0', parent: '', itemStyle: {color: '#ee6666'} },
{ id: '1', name: '李四', level: '1', parent: '张三', itemStyle: {color: '#9fe080'} },
{ id: '2', name: '王五', level: '1', parent: '张三', itemStyle: {color: '#9fe080'} },
{ id: '3', name: '赵六', level: '2', parent: '李四', itemStyle: {color: '#fc8452'} },
{ id: '4', name: '孙七', level: '2', parent: '王五', itemStyle: {color: '#fc8452'} },
{ id: '5', name: '孙七', level: '2', parent: '张三', itemStyle: {color: '#fc8452'} },
{ id: '6', name: '周八', level: '2', parent: '王五', itemStyle: {color: '#fc8452'} },
],
links: [
{ source: 0, target: 1, level: '1', category: "夫妻" },
{ source: 0, target: 2, level: '1', category: "邻居" },
{ source: 1, target: 0, level: '1', category: "夫妻" },
{ source: 1, target: 3, level: '2', category: "堂兄弟" },
{ source: 2, target: 4, level: '2', category: "夫妻" },
{ source: 4, target: 0, level: '2', category: "祖孙" },
{ source: 2, target: 5, level: '2', category: "姐妹" },
{ source: 2, target: 6, level: '2', category: "姐妹" },
]
});
let timmer = ref(null);
const props = defineProps({
cstGxGraphData: { type: Object, default: ()=>{} },
});
const option = reactive({
series: [{
type: 'graph', // 图形类别-graph关系图
layout: 'force', // 布局方式,force为力引导布局
symbolSize: 40, // 节点的大小-圆圈
roam: true, // 允许用户拖动和缩放图表
label: { // 图形上的文本标签-圆圈里边展示的内容
show: true,
},
edgeSymbol: ['circle', 'arrow'], // 连接线两端的形状,此为一端圆圈一端箭头
edgeSymbolSize: [4, 8], //连接线两端形状的大小
edgeLabel: {
show: true,
fontSize: 14,
formatter: function(param) {// 标签内容-category
return param.data.category;
}
},
data: [],// 数据
links: [],// 关系连接线及关系内容
lineStyle: { // 连接线的样式
width: 2,
curveness: 0
},
emphasis: { // 高亮状态的图形样式。
focus: 'adjacency',
lineStyle: {
width: 3,
curveness: 0
}
},
force: { // 力引导布局相关的配置项
repulsion: 100,//节点之间的斥力因子,即值越大节点间的连线越长
edgeLength: 90 //引力因子,值越大越往中心靠拢
},
zoom: 2, // 默认图标放大的倍数
scaleLimit: {// 限制放大缩小的倍数
min: 1,
max: 5
},
//组件离容器上下左右侧的距离。
left: 10,
right: 10,
top: 10,
bottom: 10,
}]
});
// 监听父组件传递过来的数据,由于改数据是在父组件中异步请求回来的数据,有延迟,需要监听,否则,拿出来的数据是上一次的数据
watch(
() => props.cstGxGraphData,
(newValue, oldValue) => {
if(newValue.nodes.length) {
data.nodes = newValue.nodes;
nextTick(() => {
// console.log(newValue, 'DOM已更新watch:', oldValue,);
if(Object.keys(myChart).length) {
updateChart();
}
});
}
if(newValue.links.length) {
data.links = newValue.links;
}
},{
deep:true,
immediate:true,
});
// 生命周期
onMounted(()=>{
// 初始化echart
myChart = echarts.init(chartContainer.value);
// console.log(chartContainer.value, 'myChart1:',myChart);
//随着屏幕大小调节图表
window.addEventListener("resize", () => {
console.log('窗口变化啦');
timmer.value = setTimeout(function (){
myChart.resize();
},200)
});
});
onUnmounted(() => {
// 移除监听
window.removeEventListener('resize', () => {
myChart.resize()
}); // 组件销毁前移除事件监听
});
// 关系图配置项
function updateChart() {
const level = selectedLevel.value;
// console.log(level);
// 根据层级过滤对应的数据
const nodes = data.nodes.filter(node => node.level <= level);
const links = data.links.filter(link => link.level <= level);
console.log('关系图配置项:',level,nodes,links);
// chartData.nodes = nodes
// chartData.links = lksinks
drawGraph(nodes,links);
};
function drawGraph(nodes,links) {
if(myChart) {
myChart.dispose(); // 清除上一次已经画过得图,这样才能实时才到最新数据的图
myChart = echarts.init(chartContainer.value);
}
option.series[0].data = nodes;
option.series[0].links = links;
myChart.setOption(option, true); //true用来解决数据不更新问题
myChart.resize()
}
</script>
- 组件样式
<style lang="less" scoped>
.contentWrap {
width: 100%;
height: 100%;
}
.wrap {
width: 100%;
height: calc(100% - 56px);
}
</style>
- 效果图:可以放大缩小,移动