需求:目前有俩个组数组分别为sss和aaa,sss和aaa有4个属性,分别为温度、湿度、气压和ppm,根据不同的属性每组画出4条折现,结果应该为8条折现,每条折现颜色不一致,名称也不一致,时间也不一致,通过额外设置的按钮去控制每组的显示和隐藏
1.效果
2.主要代码和讲解
数据源格式如下:
weatherData: [
{
poi_code: 'sss',
time: '2024-10-01 14:14:14',
period_num: 230,
airpressure: 1020.3,
temperature: 30,
humidity: 29,
ppm: 7.13
}
],
2.1 封装一个折线图
折线图上的数据示例我都有标注,只需要传一样的数据就可以实现了
<template>
<!-- 折线图 -->
<div :id="id" class="main" style="width: 100%; height: 100%"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
props: ['sendOption', 'id'],
mounted() {
window.setTimeout(() => {
this.play_echarts();
}, 1000);
},
watch: {
sendOption: {
deep: true,
handler() {
this.play_echarts();
}
}
},
data() {
return {
myChart: null
};
},
methods: {
play_echarts() {
let that = this;
that.$nextTick((_) => {
if (
//判断是否存在echarts实例化对象,如果存在则销毁
that.myChart != null &&
that.myChart != '' &&
that.myChart != undefined
) {
that.myChart.dispose();
}
// const pointName = that.sendOption.pointName;
// const imei = that.sendOption.imei;
// console.log(pointName, imei, "获取到的数据");
let option = {
title: {
text: that.sendOption.title,
x: '20',
y: '-3', //"20",
textStyle: {
color: '#000',
fontFamily: 'Microsoft YaHei',
fontSize: '16'
}
},
tooltip: {
trigger: 'axis',
confine: true //限制tooltip在图表范围内展示
},
legend: {
data: that.sendOption.legend,
selected: that.sendOption.legendSelected[0]
},
grid: {
left: '3%',
right: '4%',
bottom: '6%',
top: '13%',
containLabel: true
},
toolbox: {
right: '10%',
// 自定义工具提示框
tooltip: {
show: true,
trigger: 'axis',
formatter: function (param) {
return '<div>' + param.title + '</div>';
}
},
// 隐藏工具标题
showTitle: false,
feature: {
// 保持图片
saveAsImage: {
type: 'png',
name: that.sendOption.title, //保存文件的名称
excludeComponents: ['toolbox'],
title: '下载为图片',
icon: 'path://M136.533333 0h750.933334c75.093333 0 136.533333 61.44 136.533333 136.533333v750.933334c0 75.093333-61.44 136.533333-136.533333 136.533333H136.533333c-75.093333 0-136.533333-61.44-136.533333-136.533333V136.533333C0 61.44 61.44 0 136.533333 0z m580.266667 409.6c54.613333 0 102.4-47.786667 102.4-102.4S771.413333 204.8 716.8 204.8 614.4 252.586667 614.4 307.2 662.186667 409.6 716.8 409.6z m-273.066667 266.24l-68.266666-109.226667c0-6.826667-6.826667-6.826667-13.653334-13.653333-20.48-6.826667-40.96-6.826667-47.786666 13.653333l-177.493334 273.066667v13.653333c0 20.48 13.653333 34.133333 34.133334 34.133334h696.32c13.653333 0 27.306667-13.653333 27.306666-27.306667 0-6.826667 0-13.653333-6.826666-13.653333l-150.186667-211.626667c-6.826667-13.653333-27.306667-13.653333-40.96-6.826667l-6.826667 6.826667-13.653333 13.653333-95.573333 150.186667c-13.653333 13.653333-34.133333 20.48-47.786667 6.826667-6.826667 0-6.826667-6.826667-6.826667-13.653334L443.733333 675.84z',
iconStyle: {
color: '#409eff',
borderColor: 'none'
}
}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: that.sendOption.xAxis
// data: ['11-05 10:20:00', '11-05 10:21:00', '11-05 10:22:00']//示例代码
},
yAxis: {
type: 'value',
// min: yMin < 0 ? null : yMin,
// max: yMax,
// boundaryGap: true,
boundaryGap: [0.1, 1]
// max: function (value) {
// if (value.max < 3) {
// value.max = 3;
// } else {
// value.max = value.max;
// }
// return value.max;
// },
// boundaryGap: ["60%", "80%"],
// maxInterval: 30,
},
series: that.sendOption.seriesData
// 示例如下
// series: [
// {
// data: [
// ['11-05 10:20:00', 14.06],
// ['11-05 10:22:00', null]
// ],
// type: 'line',
// name: 'sss',
// smooth: true,
// symbolSize: 6
// },
// {
// data: [['11-05 10:21:00', 21.82]],
// type: 'line',
// name: 'aaa',
// smooth: true,
// symbolSize: 6
// },
// ]
};
// 基于准备好的dom,初始化echarts实例
that.myChart = echarts.init(document.querySelector(`#${that.id}`));
window.addEventListener('resize', function () {
if (that.myChart) {
that.myChart.resize();
}
});
// 使用刚指定的配置项和数据显示图表。
that.myChart.setOption(option);
});
},
redraw() {
// 使用刚指定的配置项和数据显示图表。
that.myChart.setOption(option);
}
},
beforeDestroy() {
let that = this;
if (!that.myChart) {
return;
}
that.myChart.dispose();
that.myChart = null;
}
};
</script>
<style lang="scss" scoped>
</style>
2.2 数据转换成折线图需要的数据
折线图封装完后引入页面需要传如下数据给折线图
sendOptionTop: {
title: '', //y轴标题
seriesData: [], //主要数据
xAxis: [], //点名称
legend: [], //标题
showTooltipLevel: true, //显示预警等级
legendSelected: [] //控制显示隐藏
},
数据处理:把原始数据首先转换为分组的键值对
// 根据poi_code对数据进行分组
let groupedData = {};
this.weatherData.forEach((item) => {
// 判断当前poi_code是否存在groupedData中,以下是不存在的情况
if (!groupedData[item.poi_code]) {
// 不存在则创建一个新的键值对
groupedData[item.poi_code] = {
times: [],
temperatures: [],
humidities: [],
airpressures: [],
ppms: []
};
}
groupedData[item.poi_code].times.push(item.time);
groupedData[item.poi_code].temperatures.push([item.time || null, item.temperature || null]); // 处理null值
groupedData[item.poi_code].humidities.push([item.time || null, item.humidity || null]);
groupedData[item.poi_code].airpressures.push([item.time || null, item.airpressure || null]);
groupedData[item.poi_code].ppms.push([item.time || null, item.ppm || null]);
});
console.log(groupedData, '组的数据-------');
转换后的效果如下, 一个组sss分别有4个单独的数据
之后把键值对转换为数组,并且把sss添加到对应的值
let echartsData = [];
for (let code in groupedData) {
echartsData.push({
name: code,
time: groupedData[code].times,
temperature: groupedData[code].temperatures,
humidity: groupedData[code].humidities,
airpressure: groupedData[code].airpressures,
ppm: groupedData[code].ppms
});
}
console.log(echartsData, '');
最后根据属性名进行匹配数据源,最终得到8条折现的数据
let series = [];
// 动态设置xAxis的data和series
echartsData.forEach((data) => {
// option.xAxis.data = data.time; // 设置x轴的时间数据(注意:这里可能需要根据实际情况调整,因为所有组的时间可能不一致)
// 为每个poi_code创建一个series
['temperature', 'humidity', 'airpressure', 'ppm'].forEach((type) => {
series.push({
name: `${data.name} ${
type == 'temperature' ? '温度' : type == 'humidity' ? '湿度' : type == 'airpressure' ? '气压' : type
}`,
type: 'line',
smooth: true,
symbolSize: 6,
data: data[type]
});
});
});
注意这个name,name的值要在legend中
2.3按钮控制
按钮代码如下,只需要把title换成sss和aaa就行
<div
class="item"
v-for="(item, index) in lineChartArr"
:key="index"
:class="{ isSelected: item.isSelect }"
@click="handleLineFilter(item)"
>
<div
class="item-chunk"
:style="{
background: `${!item.isSelect ? item.color : '#e4e5e6'}`
}"
></div>
<div class="item-title">{{ item.title }}</div>
</div>
点击按钮后和legend标签进行匹配,匹配成功就设置legendSelected,注意!不能直接改变legendSelected,不然没有响应只能通过一个变量selected来进行改变了
handleLineFilter(code) {
code.isSelect = !code.isSelect;
this.sendOptionTop.legendSelected = [];
let legendData = this.sendOptionTop.legend;
for (let item of legendData) {
// 检查当前元素是否包含 obj.title
if (code.isSelect && item.indexOf(code.title) > -1) {
// 如果包含,则添加到 result 对象中,并设置值为 false
this.selected[item] = false;
} else if (item.indexOf(code.title) > -1) {
this.selected[item] = true;
}
}
this.lineChartArr.forEach((item) => {
if (item.title === code.title) {
item.isSelect = code.isSelect;
}
});
this.sendOptionTop.legendSelected.push(this.selected);
}
匹配成功后的数据 ,这样就能让sss的组数据不选中了
3.完整代码
<template>
<div class="box">
<div class="top-item">
<div
class="item"
v-for="(item, index) in lineChartArr"
:key="index"
:class="{ isSelected: item.isSelect }"
@click="handleLineFilter(item)"
>
<div
class="item-chunk"
:style="{
background: `${!item.isSelect ? item.color : '#e4e5e6'}`
}"
></div>
<div class="item-title">{{ item.title }}</div>
</div>
</div>
<MultipleLineCharts id="zhexian02" :sendOption="sendOptionTop" />
</div>
</template>
<script>
import MultipleLineCharts from '@/components/multipleLineCharts';
export default {
components: {
MultipleLineCharts
},
data() {
return {
lineChartArr: [
{
color: '#8b8c8c', //'#DC143C',
title: 'sss',
isSelect: false
},
{
color: '#8b8c8c', //'#000000',
title: 'aa',
isSelect: false
}
],
weatherData: [
{
poi_code: 'sss',
time: '2024-10-01 14:14:14',
period_num: 230,
airpressure: 1020.3,
temperature: 30,
humidity: 29,
ppm: 7.13
},
{
poi_code: 'sss',
time: '2024-10-02 13:14:14',
period_num: 527,
airpressure: null,
temperature: 1020.3,
humidity: 64,
ppm: 170
},
{
poi_code: 'sss',
time: '2024-10-03 14:14:14',
period_num: 528,
airpressure: null,
temperature: 756.3,
humidity: 65,
ppm: 53
},
{
poi_code: 'sss',
time: '2024-10-04 14:14:14',
period_num: 529,
airpressure: 54,
temperature: 1020.3,
humidity: null,
ppm: 0
},
{
poi_code: 'aaa',
time: '2024-10-02 13:14:14',
period_num: 527,
airpressure: 32,
temperature: 55,
humidity: null,
ppm: 0
},
{
poi_code: 'aaa',
time: '2024-10-05 11:14:14',
period_num: 122,
airpressure: 12,
temperature: 73,
humidity: 836,
ppm: 0
},
{
poi_code: 'aaa',
time: '2024-10-06 11:14:14',
period_num: 529,
airpressure: 1,
temperature: 23,
humidity: 55,
ppm: 1
},
{
poi_code: 'aaa',
time: '2024-10-07 06:14:14',
period_num: 530,
airpressure: 13,
temperature: 0,
humidity: 35,
ppm: 0
},
{
poi_code: 'aaa',
time: '2024-10-07 16:14:14',
period_num: 531,
airpressure: 33,
temperature: 32,
humidity: 62,
ppm: 0
}
],
sendOptionTop: {
title: '', //y轴标题
seriesData: [], //主要数据
xAxis: [], //点名称
legend: [], //标题
showTooltipLevel: true, //显示预警等级
legendSelected: [] //控制显示隐藏
},
selected: {}
};
},
mounted() {
this.queryWeather();
},
methods: {
queryWeather() {
// 根据poi_code对数据进行分组
let groupedData = {};
this.weatherData.forEach((item) => {
// 判断当前poi_code是否存在groupedData中,以下是不存在的情况
if (!groupedData[item.poi_code]) {
// 不存在则创建一个新的键值对
groupedData[item.poi_code] = {
times: [],
temperatures: [],
humidities: [],
airpressures: [],
ppms: []
};
}
groupedData[item.poi_code].times.push(item.time);
groupedData[item.poi_code].temperatures.push([item.time || null, item.temperature || null]); // 处理null值
groupedData[item.poi_code].humidities.push([item.time || null, item.humidity || null]);
groupedData[item.poi_code].airpressures.push([item.time || null, item.airpressure || null]);
groupedData[item.poi_code].ppms.push([item.time || null, item.ppm || null]);
});
console.log(groupedData, '组的数据-------');
let echartsData = [];
for (let code in groupedData) {
echartsData.push({
name: code,
time: groupedData[code].times,
temperature: groupedData[code].temperatures,
humidity: groupedData[code].humidities,
airpressure: groupedData[code].airpressures,
ppm: groupedData[code].ppms
});
}
console.log(echartsData, '');
let series = [];
// 动态设置xAxis的data和series
echartsData.forEach((data) => {
// option.xAxis.data = data.time; // 设置x轴的时间数据(注意:这里可能需要根据实际情况调整,因为所有组的时间可能不一致)
// 为每个poi_code创建一个series
['temperature', 'humidity', 'airpressure', 'ppm'].forEach((type) => {
series.push({
name: `${data.name} ${
type == 'temperature' ? '温度' : type == 'humidity' ? '湿度' : type == 'airpressure' ? '气压' : type
}`,
type: 'line',
smooth: true,
symbolSize: 6,
data: data[type]
});
});
});
console.log(series, 'series');
let aa = this.weatherData.map((item) => item.time);
this.sendOptionTop.xAxis = this.removeDuplicateDates(aa);
this.sendOptionTop.seriesData = series;
this.sendOptionTop.legend = this.sendOptionTop.seriesData.map((item) => item.name);
},
removeDuplicateDates(dates) {
// 使用 Set 来自动去除重复项
const uniqueDates = new Set(dates);
// 将 Set 转换回 Array
return Array.from(uniqueDates);
},
handleLineFilter(code) {
code.isSelect = !code.isSelect;
this.sendOptionTop.legendSelected = [];
let legendData = this.sendOptionTop.legend;
for (let item of legendData) {
// 检查当前元素是否包含 obj.title
if (code.isSelect && item.indexOf(code.title) > -1) {
// 如果包含,则添加到 result 对象中,并设置值为 false
this.selected[item] = false;
} else if (item.indexOf(code.title) > -1) {
this.selected[item] = true;
}
}
this.lineChartArr.forEach((item) => {
if (item.title === code.title) {
item.isSelect = code.isSelect;
}
});
console.log(this.sendOptionTop.legendSelected);
this.sendOptionTop.legendSelected.push(this.selected);
}
}
};
</script>
<style lang="scss" scoped>
.box {
height: 600px;
width: 50%;
}
.top-item {
width: 100%;
display: flex;
justify-content: center;
margin: 40px 0px 20px;
.item {
display: flex;
margin: 0 10px;
}
}
.item-chunk {
height: 13px;
width: 26px;
margin-top: 3px;
margin-right: 5px;
}
</style>
文章到此结束,希望对你有所帮助~