先讲原理:
- 初始化图表
- 绑定点击事件
- 拼好要下钻的option数据
- 重新渲染ECharts
完整代码
<template>
<!-- 月度项目汇总报表 -->
<div class="box">
<h2>数据下转模板</h2>
<!-- 全局 id 不可重复 -->
<div id="chart"></div>
</div>
</template>
<script>
import * as echarts from "echarts";
export default {
name: "chart",
data() {
return {
chartData: [], //源数据
stack: [], // 数据栈 用于数据下转
};
},
methods: {
getData() {
// ...请求数据省略
// 数据格式
let data = [
{
label: "金额",
type: "line",
color:"#ed7d31",
chartData: [
{
name: "位置1",
value: 80,
children: [
{
name: "v11.0",
value: 10,
},
{ name: "v10.0", value: 5 },
{ name: "v9.0", value: 4 },
{ name: "v8.0", value: 3 },
{ name: "v7.0", value: 2 },
{ name: "v6.0", value: 1 },
],
},
{
name: "位置2",
value: 20,
},
{
name: "位置3",
value: 30,
},
{
name: "位置4",
value: 80,
},
{
name: "位置5",
value: 18,
},
],
},
{
label: "采购金额",
type: "bar",
color:"#5470c6",
chartData: [
{
name: "位置1",
value: 80,
children: [
{
name: "v11.0",
value: 10,
children: [
{ name: "w1", value: 10 },
{ name: "w2", value: 800 },
{ name: "w3", value: 700 },
{ name: "w4", value: 20 },
{ name: "w5", value: 500 },
{ name: "w6", value: 40 },
],
},
{
name: "v10.0",
value: 8,
},
{ name: "v9.0", value: 7 },
{ name: "v8.0", value: 6 },
{ name: "v7.0", value: 5 },
{ name: "v6.0", value: 4 },
],
},
{
name: "位置2",
value: 21,
},
{
name: "位置3",
value: 31,
},
{
name: "位置4",
value: 81,
},
{
name: "位置5",
value: 19,
},
],
},
];
this.chartData = data;
console.log(this.chartData, "源数据");
this.init(); //初始化echarts
},
init() {
// 一、 初始化图表
// 拼series数据
let seriesData = this.spellData(this.chartData, "chartData");
console.log(seriesData, "拼好的series数据");
let option = {
// 分类
legend: {
top: -5,
left: 35,
},
// 提示
tooltip: {
trigger: "axis",
},
// 距离
grid: {
top: 25,
left: 30,
right: 5,
bottom: 25,
},
xAxis: {
data: this.chartData[0].chartData.map((item) => item.name), //以第一个数据为标准,因为name是一致的
},
yAxis: {},
// series 数据
series: [...seriesData],
// 默认不显示返回按钮
graphic: [
{
type: "text",
left: 0,
top: 1,
style: {
text: "",
fontSize: 16,
},
},
],
};
let myChart = echarts.init(document.getElementById("chart"));
myChart.setOption(option);
// 二、 数据下砖
// 记录栈
this.stack = [];
this.stack.push(option);
// 点击事件
let that = this;
myChart.off("click"); // 点击之前 先把上一次的解绑,避免两次点击
myChart.on("click", function (event) {
// 数据下钻
that.dataDrillDown(event);
});
// 自适应屏幕
window.onresize = function () {
myChart.resize();
};
},
// 数据下转
dataDrillDown(event) {
console.log(event, "event");
/*
数据下转的查询数据规则有两种
1. 查询亲孩子(自己符合规则的数据)
2. 查找所有孩子(只要name一致 并且也有children就一起渲染) * 默认
*/
// 这里使用的是第二种,如果想使用第一种 在数据下转前 查询父数据内符合规则的即可,而不是遍历全部的数据
// const parentData = that.chartData.filter((item) => {
// if (item.type == event.seriesType && item.label == event.seriesName) {
// return item;
// }
// });
// 1.查找子数据 (这里拿数据的name进行查询的)
let childrenData = [];
function findChildren(arr, event, parentItem) {
arr.filter((item) => {
if (
item.name === event.name &&
item.children &&
item.children.length != 0
) {
item.label = parentItem.label;
item.type = parentItem.type;
item.color = parentItem.color;
childrenData.push(item); //查到的children
} else if (item.children && item.children.length != 0) {
findChildren(item.children, event, parentItem);
}
});
}
this.chartData.forEach((item) => {
findChildren(item.chartData, event, item);
});
if (childrenData.length == 0) return false; //如果查不到证明没有 直接return
console.log(childrenData, "查到的所有符合规则数据");
// 2.拼子series数据
let childrenSeriesData = this.spellData(childrenData, "children");
console.log(childrenSeriesData, "拼好的子series数据");
// 3.初始化下转数据
let option = {
// 分类
legend: {
top: -5,
left: 35,
},
// 提示
tooltip: {
trigger: "axis",
},
// 距离
grid: {
top: 25,
left: 30,
right: 5,
bottom: 25,
},
xAxis: { data: childrenData[0].children.map((item) => item.name) },
yAxis: {},
series: [...childrenSeriesData],
};
this.stack.push(option); //记录栈
let that = this;
// 下转后的返回按钮
option.graphic = [
{
type: "text",
left: 0,
top: 1,
style: {
text: "返回",
fontSize: 16,
},
onclick: function (event) {
// 返回到上一个
let option = that.stack[that.stack.length - 2];
if (!option) return false; // 到头了就停止执行
// "如果是最前面一级 就不显示返回按钮"
if (that.stack.length == 2) {
option.graphic = [
{
style: {
text: "",
},
},
];
}
myChart.setOption(option); //重新渲染
//点击一次返回 往栈里面删除一个
that.stack.pop();
},
},
];
let myChart = echarts.init(document.getElementById("chart"));
myChart.setOption(option, true);
},
// 拼数据
spellData(arr, dataName) {
let seriesData = [];
arr.forEach((item, index) => {
if (!item[dataName]) item[dataName] = []; //边缘处理
let obj = {
color: item.color,
/* 核心数据 */
name: item.label,
type: item.type,
data: item[dataName].map((item) => item.value),
/* 其他数据 */
label: {
show: true,
position: "inside",
fontSize: 18,
},
// 过渡时间和动画
animationDurationUpdate: 500,
universalTransition: {
enabled: true,
divideShape: "split",
},
};
seriesData.push(obj);
});
return seriesData;
},
},
mounted() {
this.getData();
},
};
</script>
<style scoped lang='scss'>
.box {
position: absolute;
width: 100%;
height: 100%;
}
#chart {
width: 100%;
height: 90%;
}
</style>