[VUE2/VUE3]基于echarts的动态折线图组件

[VUE2/VUE3]基于echarts的动态折线图组件

时间格式化代码

export default function formatSecond(value: number) {
    let millisecond: string | number = value % 1000; // 秒
    let second: string | number = Math.floor(value / 1000); // 秒
    let minute = 0; // 分
    let result = '';
    if (second >= 60) {
        minute = Math.floor(second / 60);
        second = Math.floor(second % 60);
    }
    if (millisecond >= 0 && millisecond < 10) {
        millisecond = '00';
    } else if (millisecond >= 10 && millisecond < 100) {
        millisecond = '0' + millisecond.toString().slice(0, 1);
    } else {
        millisecond = millisecond.toString().slice(0, 2);
    }
    if (second >= 0 && second < 10) {
        second = '0' + second;
    }
    if (minute >= 0 && minute < 10) {
        result = '0' + Math.floor(minute) + ':' + second + ':' + millisecond;
    } else {
        result = Math.floor(minute) + ':' + second + ':' + millisecond;
    }
    return result.slice(0, -3);
}

组件代码

<template>
    <div class="echart-container">
        <div id="hzs-echart" style="height: 250px" ref="echart"></div>
        <div class="echart-btns">
            <button v-show="!isStartPaint" @click="startPaint">开始绘图</button>
            <button v-show="isStartPaint" @click="stopPaint">停止绘图</button>
            <button @click="printOptions">打印配置信息</button>
            <button @click="addTag">打标签</button>
            <button @click="viewHistory">查看历史数据</button>
            <button @click="viewNow">查看当前数据</button>
        </div>
    </div>
</template>

<script>
import { defineComponent, markRaw } from 'vue';
import * as echarts from 'echarts';
// import cloneDeep from '@/util/deepCopy';
import formatSecond from '@/util/formatSecond';

const colorList = ['#0f78f4', '#dd536b', '#9462e5', '#a6a6a6', '#e1bb22', '#39c362', '#3ed1cf'];

export default defineComponent({
    name: 'ChangeAxisChart',
    props: {
        allDataDict: {
            type: Object,
            default() {
                return {
                    data1: [100, 100, 100],
                    data2: [100, 100, 100],
                    data3: [100, 100, 100]
                };
            }
        },
        checkedKeyList: {
            type: Array,
            default() {
                return ['data1', 'data2'];
            }
        },
        timeList: {
            type: Array,
            default() {
                return [1654896594373, 1654896595373, 1654896596373];
            }
        },
        initTime: {
            type: Number,
            default() {
                return new Date().getTime();
            }
        }
    },
    computed: {
        // 设定要修改的option 和 目标数据集
        targetOption: function () {
            return this.isHistory ? this.optionsHistory : this.options;
        },
        targetDataDict: function () {
            return this.isHistory ? this.chartData.allData : this.chartData.data;
        }
    },
    watch: {
        timeList: {
            immediate: true,
            deep: true,
            handler(newVal, oldVal) {
                // console.log("重置chart")
                // console.log(newVal)
                // console.log('更新timeList');

                if (!this.isStartPaint) {
                    // console.log('没开始画');
                    return;
                }
                if (this.isHistory) {
                    return;
                }
                if (this.checkedKeyList.length === 0) {
                    return;
                }

                this.initChart();
                // this.refreshChart();
            }
        },

        // 更新选择键
        checkedKeyList: {
            immediate: true,
            deep: true,
            handler(newVal, oldVal) {
                // console.log("重置chart")
                // console.log('更新选择键');
                // console.log(newVal);
                if (!this.isStartPaint) {
                    return;
                }
                if (this.isHistory) {
                    return;
                }
                if (newVal.length === 0) {
                    return;
                }
                // this.refreshChart();
                this.initChart();
            }
        }
    },
    data() {
        return {
            // 画图
            echart: null,
            echartHistory: null,

            // 画图数据
            chartData: {
                data: [],
                allData: []
            },

            // 当前数据的配置项
            options: {
                // 图相对于容器的位置
                grid: {
                    left: '10%',
                    right: '10%',
                    bottom: '10%',
                    top: '10%'
                },
                legend: {
                    data: []
                },

                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross'
                    },
                    formatter: function (params) {
                        console.log('axis');
                        console.log(params);
                        if (params.length > 1) {
                            return `<div class='tooltips'>
                          <p>时刻:${formatSecond(params[0].axisValue)}</p>
                          <p>该点左侧y值:${params[0].value[1]}</p>
                          <p>该点右侧y值:${params[1].value[1]}</p>
                        </div> `;
                        } else {
                            return `<div class='tooltips'>
                          <p>时刻:${formatSecond(params[0].axisValue)}</p>
                          <p>该点的值:${params[0].value[1]}</p>
                        </div> `;
                        }
                    }
                },
                color: colorList,
                xAxis: {
                    name: '',
                    // type: 'category',
                    type: 'value',
                    // 以x秒为间隔
                    // minInterval: 2000,
                    minInterval: 2000,

                    axisLabel: {
                        // 坐标轴标签
                        show: true, // 是否显示
                        inside: false, // 是否朝内
                        rotate: 0, // 旋转角度
                        margin: 5, // 刻度标签与轴线之间的距离
                        color: '#999', // 默认取轴线的颜色
                        formatter: function (value) {
                            return formatSecond(value);
                        }
                    },

                    axisPointer: {
                        label: {
                            formatter: function (params) {
                                return formatSecond(params.value);
                            }
                        }
                    }
                },
                yAxis: [
                    {
                        name: '',
                        type: 'value',
                        // scale: true,
                        show: true,
                        axisLine: {
                            lineStyle: {
                                color: colorList[0]
                            }
                        },
                        axisLabel: {
                            // formatter: '{value} °C',
                            color: colorList[0]
                        },
                        max: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.max + Math.floor(h) * 0.2 + 2);
                        },
                        min: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.min - Math.floor(h) * 0.2 - 2);
                        },
                        splitNumber: 5
                    },
                    {
                        name: '',
                        type: 'value',
                        show: true,
                        axisLine: {
                            lineStyle: {
                                color: colorList[1]
                            }
                        },
                        axisLabel: {
                            color: colorList[1]
                        },
                        max: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.max + Math.floor(h) * 0.2 + 2);
                        },
                        min: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.min - Math.floor(h) * 0.2 - 2);
                        },
                        splitNumber: 5
                    }
                ],
                series: []
            },

            // 查看历史数据时候的配置项
            optionsHistory: {
                // 图相对于容器的位置
                grid: {
                    left: '10%',
                    right: '10%',
                    bottom: '20%',
                    top: '10%'
                },
                dataZoom: [
                    {
                        type: 'inside',
                        start: 0
                    },
                    {
                        type: 'slider',
                        show: true,
                        start: 0,
                        height: 16,
                        bottom: '5%'
                    }
                ],
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross',
                        animation: false,
                        label: {
                            backgroundColor: '#505765'
                        }
                    },
                    formatter: function (params) {
                        console.log(params);
                        return `<div class='tooltips'>
                          <p>时刻:${params[0].axisValue}</p>
                          <p>值:${params[0].value[1]}</p>
                        </div> `;
                    }
                },
                color: ['#0f78f4', '#dd536b', '#9462e5', '#a6a6a6', '#e1bb22', '#39c362', '#3ed1cf'],
                xAxis: {
                    // name: '秒',
                    type: 'value',

                    // 以一秒为间隔
                    minInterval: 1000,

                    axisLabel: {
                        // 坐标轴标签
                        show: true, // 是否显示
                        inside: false, // 是否朝内
                        rotate: 0, // 旋转角度
                        margin: 5, // 刻度标签与轴线之间的距离
                        color: '#999', // 默认取轴线的颜色
                        formatter: function (value) {
                            return formatSecond(value);
                        }
                    }
                },
                yAxis: {
                    name: '',
                    type: 'value',
                    scale: true,
                    show: true,
                    max: function (value) {
                        return 1.2 * value.max;
                    }
                },
                series: []
            },

            // 标记点列表
            markPointList: [],

            // 是否是历史数据
            isHistory: false,

            // 是否开始绘图
            isStartPaint: false
        };
    },
    methods: {
        // 取数据,组合成[x,y]
        dealData() {
            const res = {};

            // 取出y的data
            this.checkedKeyList.forEach((key) => {
                // res[key] = []
                // 一条线的数据[[x1,y1],[x2,y2],[x3,y3]]

                // [y1,y2,y3,y4]
                const yList = this.allDataDict[key];

                //  this.timeList [x1,x2,x3]
                // 组合 [[x1,y1],[x2,y2],[x3,y3]]
                res[key] = this.mergeList(this.timeList, yList);
            });

            // console.log(res)
            return res;
        },

        // 合并[x1,x2,x3]  [y1,y2,y3]成一条线 [[x1,y1],[x2,y2],[x3,y3]]
        mergeList(aList, bList) {
            // console.log(aList);
            // console.log(bList);

            if (aList.length !== bList.length) {
                return [];
            }
            const res = [];
            for (let i = 0; i < aList.length; i++) {
                if (bList[i] !== '') {
                    res.push([aList[i] - this.initTime, bList[i]]);
                }
            }
            return res;
        },

        // 设置数据
        initChartData() {
            // 画多条线
            const series = [];

            // for (let lineData of this.targetDataDict) {
            //   series.push(this.getSeries(lineData))
            // }
            Object.keys(this.targetDataDict).forEach((key, index) => {
                series.push(this.getSeries(this.targetDataDict[key], key));
                series[index]['yAxisIndex'] = index;

                // 设置一下颜色
                series[index]['itemStyle'] = {
                    normal: {
                        lineStyle: {
                            color: colorList[index]
                        }
                    }
                };
            });
            this.options.series = series;

            // console.log("要画图了!")
            // console.log(this.options)

            // 配置一下已经打标记的点
            for (let i = 0; i < this.targetOption.series.length; i++) {
                const line = this.targetOption.series[i];
                line.markPoint.data = this.markPointList[i];
            }
        },

        // 把echart画出来
        initChart() {
            // 处理一下数据
            this.chartData.data = this.dealData();

            // console.log(this.chartData)

            // 处理其他选项
            this.options.legend.data = this.checkedKeyList;

            // 配置图数据
            this.initChartData();

            // 画当前的数据
            if (!this.echart) {
                this.echart = markRaw(echarts.init(this.$refs.echart));
                // this.echart = echarts.init(this.$refs.echart);
            }
            // this.clearChart()

            // console.log('将按照如下配置绘制图像');
            // console.log(this.targetOption);

            try {
                setTimeout(() => {
                    this.echart.setOption(this.targetOption);
                }, 30);
            } catch (e) {
                console.log('捕捉到异常');
                console.log(e);
            }

            // 存入
            localStorage.setItem('chartOption', JSON.stringify(this.targetOption));

            // 清除
            // localStorage.removeItem('chartOption');
        },

        // 开始画图
        drawChart() {
            const chartOption = localStorage.getItem('chartOption');
            if (!chartOption) {
                return;
            }

            if (this.echart) {
                this.clearChart();
                // this.echart = echarts.init(this.$refs.echart);
                this.echart = markRaw(echarts.init(this.$refs.echart));
            }

            try {
                setTimeout(() => {
                    this.echart.setOption(chartOption);
                }, 30);
            } catch (e) {
                console.log('捕捉到异常');
                console.log(e);
            }
        },

        // resize重新布局
        resizeChart() {
            this.echart ? this.echart.resize() : '';
            this.echartHistory ? this.echartHistory.resize() : '';
        },

        // 打标签
        addTag() {
            // console.log("add tag")

            // 对每条折线,都获取到现在最后一个点,然后推入标记标签列表中
            for (let i = 0; i < this.options.series.length; i++) {
                const line = this.options.series[i];
                const lastPoint = line['data'].slice(-1)[0];

                // 设置一下markPoint的列表
                if (this.markPointList[i] === undefined) {
                    this.markPointList[i] = [];
                }

                // 推入标记点列表
                this.markPointList[i].push({
                    name: '标记点',
                    value: lastPoint[1],
                    coord: lastPoint
                });
            }

            // 标签画入图中
            this.setMarkPoints();

            // 刷新一下
            // this.refreshChart();
            this.initChart();
        },

        // 将标记的点添加到配置项中
        setMarkPoints() {
            for (let i = 0; i < this.targetOption.series.length; i++) {
                const line = this.targetOption.series[i];
                line.markPoint.data = this.markPointList[i];
            }
        },

        // 配置series
        getSeries(dataList, name = '') {
            return {
                name: name,
                type: 'line',
                animation: false,
                symbol: 'none',
                lineStyle: {
                    width: 1
                },
                data: dataList,
                markPoint: {
                    effect: {
                        show: true,
                        shadowBlur: 0
                    },
                    data: []
                }
            };
        },

        //判断是不是有多条线
        isMultiLine() {
            return Object.keys(this.targetDataDict).length > 1;
        },

        // 新版本查看历史数据
        viewHistory() {
            // console.log("viewHistory")
            this.isHistory = true;

            const historyOption = {};
            Object.assign(historyOption, this.options);
            historyOption.grid = {
                left: '10%',
                right: '10%',
                bottom: '20%',
                top: '10%'
            };
            historyOption.dataZoom = [
                {
                    type: 'inside',
                    start: 0
                },
                {
                    type: 'slider',
                    show: true,
                    start: 0,
                    height: 16,
                    bottom: '5%'
                }
            ];
            // // 配置一下历史选项
            this.echart.clear();
            setTimeout(() => {
                this.echart.setOption(historyOption);
            }, 50);
        },

        // 查看当前数据
        viewNow() {
            this.clearChart();
            this.isHistory = false;
            this.initChart();
        },

        // 清空图标
        clearChart() {
            if (this.echart) {
                this.echart.clear();
            }
        },

        // 彻底清空图表
        clearChartPlus() {
            if (this.echart) {
                this.echart.clear();
            }
            this.options = {
                // 图相对于容器的位置
                grid: {
                    left: '10%',
                    right: '10%',
                    bottom: '10%',
                    top: '10%'
                },
                legend: {
                    data: []
                },
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross',
                        animation: false,
                        label: {
                            backgroundColor: '#505765'
                        }
                    },
                    formatter: (params) => {
                        console.log(params);
                        if (params.length > 1) {
                            return `<div class='tooltips'>
                          <p>时刻:${formatSecond(params[0].axisValue)}</p>
                          <p>该点左侧y值:${params[0].value[1]}</p>
                          <p>该点右侧y值:${params[1].value[1]}</p>
                        </div> `;
                        } else {
                            return `<div class='tooltips'>
                          <p>时刻:${formatSecond(params[0].axisValue)}</p>
                          <p>该点的值:${params[0].value[1]}</p>
                        </div> `;
                        }
                    }
                },
                color: colorList,
                xAxis: {
                    name: '',
                    type: 'value',

                    minInterval: 2000,
                    // minInterval: 2000,

                    axisLabel: {
                        // 坐标轴标签
                        show: true, // 是否显示
                        inside: false, // 是否朝内
                        rotate: 0, // 旋转角度
                        margin: 5, // 刻度标签与轴线之间的距离
                        color: '#999', // 默认取轴线的颜色
                        formatter: function (value) {
                            return formatSecond(value);
                        }
                    }
                },
                yAxis: [
                    {
                        name: '',
                        type: 'value',
                        // scale: true,
                        show: true,
                        axisLine: {
                            lineStyle: {
                                color: colorList[0]
                            }
                        },
                        axisLabel: {
                            // formatter: '{value} °C',
                            color: colorList[0]
                        },
                        max: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.max + Math.floor(h) * 0.2 + 2);
                        },
                        min: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.min - Math.floor(h) * 0.2 - 2);
                        },
                        splitNumber: 5
                    },
                    {
                        name: '',
                        type: 'value',
                        // scale: true,
                        show: true,
                        axisLine: {
                            lineStyle: {
                                color: colorList[1]
                            }
                        },
                        axisLabel: {
                            // formatter: '{value} °C',
                            color: colorList[1]
                        },
                        max: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.max + Math.floor(h) * 0.2 + 2);
                        },
                        min: function (value) {
                            const h = value.max - value.min;
                            return Math.floor(value.min - Math.floor(h) * 0.2 - 2);
                        },
                        splitNumber: 5
                    }
                ],
                series: []
            };

            // 清空标记点
            this.markPointList = [];
        },

        // 打印配置信息,测试用
        printOptions() {
            console.log(this.targetOption);
        },

        // 开始画图
        startPaint() {
            // 初始时间
            // this.initTime = new Date().getTime()
            // if (!this.initTime) {
            //     this.initTime = new Date().getTime();
            // }
            // 是否开始画
            this.isStartPaint = true;

            console.log('开始绘图');
            console.log(this.isStartPaint);
            console.log(this.initTime);
        },

        // 停止画图
        stopPaint() {
            // 是否开始画
            this.isStartPaint = false;
        },

        // 手动刷新一下
        refreshChart() {
            if (!this.isStartPaint) {
                return;
            }
            if (this.isHistory) {
                return;
            }
            if (this.checkedKeyList.length === 0) {
                return;
            }

            // console.log("绘图initChart")

            this.clearChart();
            this.initChart();
        }

        // 重新设置开始时间
        // resetStartTime() {
        //     this.initTime = new Date().getTime();
        // }
    },

    // 生命周期相关
    mounted() {
        // this.initTime = new Date().getTime();
        window.addEventListener('resize', this.resizeChart);
    },
    unmounted() {
        window.removeEventListener('resize', this.resizeChart);
    }
});
</script>

<style lang="less" scoped>
.echart-container {
    padding: 10px;
    //min-height: 1000px;
    //border: 1px solid black;
}

.echart-btns {
    display: flex;
    justify-content: flex-end;

    button {
        //width: 270px; /* 宽度 */
        //height: 40px; /* 高度 */
        padding: 5px 10px;
        border-width: 0; /* 边框宽度 */
        border-radius: 4px; /* 边框半径 */
        //background: #1E90FF; /* 背景颜色 */
        cursor: pointer; /* 鼠标移入按钮范围时出现手势 */
        outline: none; /* 不显示轮廓线 */
        color: black; /* 字体颜色 */
        font-size: 14px; /* 字体大小 */
        background-image: linear-gradient(180deg, #f2f2f2, #cfcfcf);
        margin: 10px 5px 0;
    }
}

.echart-btns button {
}
</style>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3中使用ECharts动态折线图设置时间轴可以通过以下步骤实现。 1.安装EChartsVue3项目中安装ECharts: ``` npm install echarts --save ``` 2.引入ECharts组件中引入ECharts: ```js import * as echarts from "echarts"; ``` 3.创建实例 在组件中创建一个ECharts实例: ```js const chart = echarts.init(document.querySelector("#chart")); ``` 4.设置配置项 配置项是用于描述图表的样式和数据的,可以在创建实例时进行设置: ```js const options = { xAxis: { type: "category", data: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], }, yAxis: { type: "value", }, series: [ { data: [120, 200, 150, 80, 70, 110, 130], type: "line", }, ], }; ``` 5.设置时间轴 在配置项中添加时间轴配置: ```js const options = { xAxis: { type: "category", data: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], }, yAxis: { type: "value", }, series: [ { data: [120, 200, 150, 80, 70, 110, 130], type: "line", }, ], // 添加时间轴配置 dataZoom: [ { type: "slider", xAxisIndex: 0, filterMode: "filter", start: 0, end: 60, }, ], }; ``` 其中,type为slider表示使用滑动条文件,xAxisIndex为0表示只关联x轴索引为0的轴,filterMode为filter表示按范围过滤数据,start和end分别为时间轴的开始和结束位置。 最后,将配置项应用到ECharts实例中: ```js chart.setOption(options); ``` 这样就可以在动态折线图中显示时间轴了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值