最近小编接到了一个新的需求,需要对echarts折线图页面进行优化
如图所示,上面的折线图,不同的变量之间值的差额过大,共用同一个Y轴时,折线趋势并不明显,比较影响用户的观看体验。
鉴于第一版的问题,升级了第二版,多Y轴折线图。这样哪怕不同的数据之间差距较大,但因为使用的是不同的坐标Y轴,彼此之间也不会互相影响,折线趋势也能一目了然。
但优化并没有止步于此,升级版的折线图,又提出了新的需求:当图例过多时,并不想查看那么多折线数据,需要在点击对应图例时,隐藏该图例所有的Y轴数据,具体效果如下:
别看这一个小小的需求,小编测验了好多次,花费了一些时间才解决。
最开始小编先用的模拟数据,创建了一个多Y轴图表,后来再加上legend图例控制Y轴显示功能,初步是实现了进阶需求(如上图)。但是在将页面替换成真实接口数据,写死的数据替换成动态生成的yAxis和series时,完成这个功能时,却一直存在bug,如下:
点击对应图例时,只隐藏了Y轴对应的刻度和数值label,但是Y轴轴线和名称仍在。
代码反反复复测试了很多次,也在网上看了一些其他up的参考意见,经过一番修改后,终于完成了需求;
css
<template>
<div class="PNMFlowChart">
<div ref="chartRef" class="chart" ></div>
</div>
</template>
<script setup>
import { getCurrentInstance, ref } from "vue";
import * as echarts from "echarts";
/** 数据初始化 */
const { proxy } = getCurrentInstance();
const chartOption = ref({});
const legendArr = ref([]);
let analysisChart = null;
const colors = [ "#1B9AEE", "#00AF75", "#B147B5", "#D37201", "#8FA008", "#F08080",];
const initChart = (data, name) => {
let time = data.date || [];
let title = name;
legendArr.value = data?.list?.map(item => item.name) || [];
let chartData = data?.list || [];
let legendSelectedData = legendArr.value.reduce((acc, cur) => {
acc[cur] = true; // 默认全部选中
return acc;
}, {});
if (!analysisChart) {
analysisChart = echarts.init(proxy.$refs.chartRef);
} else {
analysisChart.clear();
}
chartOption.value = {
grid: {
left: '10%',
top: '10%',
right: '10%',
bottom: '10%',
containLabel: true
},
legend: {
type: "scroll",
icon: "circle",
data: legendArr.value,
itemGap: 30,
selected: legendSelectedData,
},
tooltip: {
trigger: "axis",
backgroundColor: "#FFFFFF",
color: "#000000",
borderWidth: 0,
borderRadius: 0,
axisPointer: {
type: 'cross'
}
},
toolbox: {
feature: {
saveAsImage: { title: '保存图表', name: title },
},
top: 5,
right: 30
},
dataZoom: [
{
show: true,
start: 0,
end: 100,
height: 20,
}
],
xAxis: {
type: 'category',
name: '时间',
nameTextStyle: {
padding: [0, -20, 0, 0],
},
nameLocation: 'start',
nameGap: 40,
data: time || [],
axisTick: {
alignWithLabel: true
},
axisLabel: {
color: "#666666",
fontSize: 12,
},
axisLine: {
show: true,
lineStyle: {
color: "#666666",
width: 1,
type: "solid",
},
},
},
yAxis: (chartData.length > 0 ? chartData : [{}]).map((item = {}, index) => {
const name = item.name || '数值';
const unit = item.unit || ' ';
let YColors = chartData.length > 0 ? colors[index % colors.length] : "#666666";
const sideIndex = Math.floor(index / 2);
const offset = sideIndex === 0 ? 0 : sideIndex * 70;
return {
type: 'value',
name: `${name}/${unit}`,
show: true, // 默认显示
position: index % 2 === 0 ? 'left' : 'right',
offset: offset,
nameTextStyle: {
color: '#666666',
fontSize: 12,
lineHeight: 40,
opacity: 1,
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#ccc'
}
},
axisLine: {
show: true,
lineStyle: {
color: YColors,
}
},
axisTick: {
show: true,
length: 5,
lineStyle: {
width: 2,
color: YColors,
type: 'solid'
}
},
axisLabel: {
show: true,
color: YColors,
fontSize: 12,
formatter: `{value}`
},
nameGap: 30,
};
}),
series: chartData.map((item, index) => {
return {
name: item.name,
type: "line",
yAxisIndex: index,
lineStyle: {
width: 2,
shadowColor: 'rgba(0,0,0,0.4)',
shadowBlur: 5,
shadowOffsetY: 5
},
itemStyle: {
color: colors[index % colors.length],
},
data: item.data,
};
}),
};
// 设置初始配置
analysisChart.setOption(chartOption.value);
// 绑定图例点击事件,动态控制Y轴显示隐藏(关键的一步)
analysisChart.on('legendselectchanged', (params) => {
const selected = params.selected;
// 根据legend选中状态,更新yAxis的show属性
const yAxisKeys = legendArr.value;
const newOption = {
yAxis: chartOption.value.yAxis.map((axis, index) => ({
...axis,
show: selected[yAxisKeys[index]] ?? true,
})),
legend: {
...chartOption.value.legend,
selected: selected
}
};
// 合并新配置,触发图表更新
analysisChart.setOption(newOption);
});
};
defineExpose({ initChart });
</script>
<style lang="scss" scoped>
.PNMFlowChart {
width: 100%;
height: 630px;
margin-top: 20px;
.chart {
width: 100%;
height: 100%;
}
}
</style>
最终版效果图如下:
完成最终版需求的过程中,小编也踩过一些坑,更没有一蹴而就直达最终版,而是一步步拆解完成的,希望能给到需要做似需求的小伙伴的一些参考,有更好的方案也欢迎一起探讨