echarts多折线按组分类控制显示隐藏

需求:目前有俩个组数组分别为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>

文章到此结束,希望对你有所帮助~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值