echarts+vue动态生成可配置的桑基(sankey)图
效果展示实现思路桑基图实现的本质也是一条条source-target,节点与节点之间的连线做到完全可配置化,需抽离出大量可配置的属性无数据的节点要进行隐藏,因此需要加是否有数据的判断节点颜色和线条颜色通过设置itemStyle和lineStyle来配置分辨率自适应则需要设置函数来动态计算实现代码//now-size.jslet nowClientWidth = document.documentE
·
效果展示
实现思路
- 桑基图实现的本质也是一条条source-target,节点与节点之间的连线
- 做到完全可配置化,需抽离出大量可配置的属性
- 无数据的节点要进行隐藏,因此需要加是否有数据的判断
- 节点颜色和线条颜色通过设置itemStyle和lineStyle来配置
- 分辨率自适应则需要设置函数来动态计算
实现代码
//now-size.js
let nowClientWidth = document.documentElement.clientWidth;
export function nowSize(val, initWidth = 1920) {
return val * (nowClientWidth / initWidth);
}
<template>
<div class="situation-visit-relation" ref="chart"></div>
</template>
<script>
import { nowSize } from "@/utils/now-size"
import { getAppRelation } from "@/service/situation-service"
import { PAGE_URL_WEBAPP } from "@/constant/page-url-constants"
export default {
data() {
return {
PAGE_URL_WEBAPP,
isLoading: false,
linkMap: {},//连线数据
itemMap: {},//节点-名称映射表
itemList: {},//节点枚举列表
colorMap: {},//连线颜色枚举列表
labelMap: {},//节点-标签名映射表
sourceList: {},//源节点枚举列表
targetList: {},//目标节点枚举列表
itemColorMap: {}//节点-颜色映射表
}
},
mounted() {
this.init();
},
methods: {
// 初始化
async init() {
await getAppRelation().then(res => {
this.itemMap = res.data.itemMap;
this.labelMap = res.data.labelMap;
this.linkMap = res.data.linkMap;
this.sourceList = res.data.sourceList;
this.targetList = res.data.targetList;
this.itemList = res.data.itemList;
this.colorMap = res.data.colorMap;
this.itemColorMap = Object.assign(res.data.sourceColorMap, res.data.targetColorMap);
}).catch(() => {
this.$message.error("获取应用访问关系数据失败")
});
this.paintChart();
},
// 获取图表数据
getChartData() {
let chartData = {
linkData: [],
itemData: [],
};
let itemDataTmp = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (this.linkMap[`${this.sourceList[i]}2${this.targetList[j]}`] !== 0) {
if (itemDataTmp.indexOf(this.sourceList[i]) === -1) {
itemDataTmp.push(this.sourceList[i]);
}
if (itemDataTmp.indexOf(this.targetList[j]) === -1) {
itemDataTmp.push(this.targetList[j]);
}
chartData.linkData.push({
source: this.sourceList[i],
target: this.targetList[j],
value: this.linkMap[`${this.sourceList[i]}2${this.targetList[j]}`],
lineStyle: {
color: this.colorMap[`${this.sourceList[i]}2${this.targetList[j]}`],
},
tooltip: {
show: true,
formatter: (params) => {
return `${this.itemMap[params.data.target]}访问${this.itemMap[params.data.source]
}应用个数:${this.linkMap[
`${params.data.source}2${params.data.target}`
]?.toLocaleString()}个`;
},
},
});
}
}
}
itemDataTmp.forEach((item) => {
let index = this.itemList.indexOf(item);
if (index !== -1) {
chartData.itemData.push({
name: item,
itemStyle: {
color: this.itemColorMap[item],
borderColor: this.itemColorMap[item]
},
tooltip: {
show: false,
},
});
}
});
return chartData;
},
// 绘制图表
paintChart() {
let chartData = this.getChartData();
let linkData = chartData.linkData;
let itemData = chartData.itemData;
let chartDom = this.$echarts.init(this.$refs.chart);
if (chartDom) {
let option = {
tooltip: {
show: true,
},
series: {
type: "sankey",
layout: "none",
top: nowSize(75),
left: nowSize(30),
right: nowSize(100),
nodeWidth: 15,
draggable: false,
emphasis: {
focus: "adjacency",
},
label: {
color: "#fff",
formatter: (params) => {
return this.labelMap[params.name];
},
fontSize: nowSize(12),
size: nowSize(10)
},
data: itemData,
links: linkData,
},
};
chartDom && chartDom.setOption(option);
chartDom.on('click', (params) => {
let query = {};
if (params.data.name) {
if (params.data.name[0] === "v") {
query = {
tab: "list",
visitDomains: this.labelMap[params.data.name],
};
} else {
query = {
tab: "list",
deployDomains: this.labelMap[params.data.name],
};
}
this.$linkTo({
path: PAGE_URL_WEBAPP,
query: query,
});
}
if (params.data.source) {
this.$linkTo({
path: PAGE_URL_WEBAPP,
query: {
tab: "list",
deployDomains: this.labelMap[params.data.source],
visitDomains: this.labelMap[params.data.target],
},
type: "_blank"
});
}
});
let sizeFun = () => {
chartDom.resize();
};
window.addEventListener("resize", sizeFun);
this.$once("hook:beforeDestroy", function () {
this.$echarts.dispose(chartDom);
});
}
},
}
}
</script>
<style lang="less">
.situation-visit-relation {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
}
</style>
更多推荐
已为社区贡献7条内容
所有评论(0)