两万+数据使用echarts图表展示(vue2+echarts4.2)

103 阅读3分钟

最近遇到项目中遇到的新问题如后端返回数据不分类直接将两万多条数据一次性返回过来,前端应该如何处理展示到echarts图表中。如图

image.png

image.png 当时看到好家伙数据直接返回两万+而且没有任何处理,只好慢慢想想应该如何处理! 首先要考虑两个问题第一个是将同一个设备同一传感器的数据放置在一个数组中,然后在按照时间顺序一天从00:00:00-23:59:00这个时间段排序两个限制条件来排列好数据展示出来,因为设备传递数据是分钟级最终实现出来的效果, image.png

image.png image.png 根据父组件传递来的类型来改变子组件中图表展示的样式,因为数据量大还要考虑优化问题,父组件中使用子组件考虑使用v-show而不是v-if,因为dom操作会导致页面卡顿,以及使用echarts中的 sampling: "lttb",来优化echarts

NPM 安装 ECharts

你可以使用如下命令通过 npm 安装 ECharts

npm install echarts --save
#echarts官网  https://echarts.apache.org/handbook/zh/basics/import/

在unit/index.js中添加时间轴方法

/**
 * 生成时间轴时间
 */
export function generateTimeArray() {
  const timeArray = [];
  let currentTime = new Date();

  // 设置起始时间
  currentTime.setHours(0);
  currentTime.setMinutes(1);
  currentTime.setSeconds(0);
  currentTime.setMilliseconds(0);

  // 设置结束时间
  const endTime = new Date();
  endTime.setHours(23);
  endTime.setMinutes(59);
  endTime.setSeconds(59);
  endTime.setMilliseconds(0);

  while (currentTime <= endTime) {
    // 格式化时间为 HH:MM:SS
    const hours = String(currentTime.getHours()).padStart(2, '0');
    const minutes = String(currentTime.getMinutes()).padStart(2, '0');
    const seconds = String(currentTime.getSeconds()).padStart(2, '0');
    timeArray.push(`${hours}:${minutes}:${seconds}`);

    // 增加一分钟
    currentTime.setMinutes(currentTime.getMinutes() + 1);
  }

  return timeArray;
}

后台返回给我们的时间格式中是有空缺的并不是完整的时间,前台页面中展示的数据样式是时间不能有空缺如果该时间段不存在数据就是默认null所以要生成要给具体的时间轴排列

创建组件eCharts-from

<template>
  <div class="line-echarts">
    <div id="myChartLine" style="width: 100%; height: 70vh"></div>
  </div>
</template>

<script>
  import { generateTimeArray } from "@/util";
  import echarts from "echarts";
  export default {
    props: {
      radioValue: {
        type: String,
        default: "line",
      },
    },
    data() {
      return {
        interval: 55,
        colorIndex: 0,
        eChartsList: {},
        colorType: "",
        dataList: [],
        myChart: null,
        seriesNames: null,
        generateTimeArray: {},
      };
    },
    mounted() {
      this.$echarts = echarts;
      this.generateTimeArray = generateTimeArray();
    },
    methods: {
      init(data = []) {
        this.dataList = data;
        this.dataProcessing();
      },
      dataProcessing() {
        let seriesNames = new Set();
        this.dataList.forEach((item) => {
          seriesNames.add(item.pDeviceName + "-" + item.deviceName);
        });
        this.seriesNames = seriesNames;
        if (this.myChart) {
          this.colorIndex = 0;
          // this.myChart.dispose();
        }
        this.$nextTick(() => {
          this.chartInit();
        });
      },
      getColor() {
        this.colorIndex >= 14 ? (this.colorIndex = 0) : this.colorIndex++;
        const colors = [
          "#07a5ff",
          "#ffc000",
          "#31dd3d",
          "#22d2fd",
          "#c4ff77",
          "#fd8cf1",
          "#fa6c17",
          "#0576fe",
          "#02D6B0",
          "#90EE90",
          "#FFC0CB",
          "#ADD8E6",
          "#5470c6",
          "#fac858",
          "#FFA500",
          "#de8276",
          "#ada9bf",
          "#867F50",
          "#DDA0DD",
          "#f68f6e",
          "#649a8b",
        ];
        this.colorType = "";
        this.colorType = colors[this.colorIndex];
      },
      hexToRgba(hex, alpha) {
        let r = parseInt(hex.slice(1, 3), 16);
        let g = parseInt(hex.slice(3, 5), 16);
        let b = parseInt(hex.slice(5, 7), 16);
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
      },
      chartInit() {
        let chartDom = document.querySelector("#myChartLine");
        this.myChart = this.$echarts.init(chartDom);
        let seriesDataMap = new Map();
        this.seriesNames.forEach((name) => {
          seriesDataMap.set(
            name,
            new Array(this.generateTimeArray.length).fill(null)
          ); // 初始化为 null
        });

        // 填充数据
        this.dataList.forEach((item) => {
          let name = item.pDeviceName + "-" + item.deviceName;
          let index = this.generateTimeArray.indexOf(item.ts.slice(11, 19));
          if (seriesDataMap.has(name) && index !== -1) {
            seriesDataMap.get(name)[index] = item.val;
          }
        });
        let typeValue = "line";
        if (this.radioValue == "lineArea") {
          typeValue = "line";
        } else {
          typeValue = this.radioValue;
        }

        // 准备 seriesData
        let seriesData = [];
        this.seriesNames.forEach((name) => {
          this.getColor();
          seriesData.push({
            name: name,
            sampling: "lttb",
            type: typeValue,
            smooth: true,
            showSymbol: false,
            symbol: "circle",
            symbolSize: 4,
            emphasis: {
              focus: "series",
              lineStyle: {
                borderColor: "#333", // 鼠标悬浮时线条边框颜色
                borderWidth: 4, // 鼠标悬浮时线条边框宽度
                shadowBlur: 10, // 阴影大小
                shadowColor: "rgba(0, 0, 0, 0.5)", // 阴影颜色
                shadowOffsetX: 0, // 阴影水平方向上的偏移
                shadowOffsetY: 5, // 阴影垂直方向上的偏移
              },
            },
            lineStyle: {
              normal: {
                color: this.colorType,
                width: 2,
              },
            },
            itemStyle: {
              color: this.colorType,
            },
            areaStyle:
              this.radioValue == "lineArea"
                ? {
                    color: {
                      type: "linear",
                      x: 0,
                      y: 0,
                      x2: 0,
                      y2: 1,
                      colorStops: [
                        { offset: 0, color: this.hexToRgba(this.colorType, 0.1) },
                        { offset: 1, color: this.hexToRgba(this.colorType, 1) },
                      ],
                      global: false,
                    },
                  }
                : null,
            data: seriesDataMap.get(name),
          });
        });

        const option = {
          // animation: false,
          tooltip: {
            trigger: "axis",
            axisPointer: {
              type: "cross",
              crossStyle: {
                color: "#999",
                type: "dashed",
              },
              lineStyle: {
                type: "dashed",
                color: "#999",
              },
              label: {
                backgroundColor: "#6e7079",
                borderColor: "#6e7079",
                borderWidth: 1,
              },
            },
            textStyle: {
              color: "#fff",
              fontSize: 13,
            },
            confine: true,
          },
          grid: {
            containLabel: true,
            bottom: "6%",
            top: "15%",
            left: "2%",
            right: "2%",
          },
          legend: {
            right: "2%",
            left: "2%",
            itemWidth: 14,
            itemHeight: 6,
            itemGap: 20,
            textStyle: {
              fontSize: 14,
              color: "#606266",
              padding: [0, 0, 0, 4],
            },
          },
          dataZoom: [
            {
              type: "slider",
              start: 0,
              end: 100,
              handleSize: 8,
            },
            {
              type: "inside",
              start: 0,
              end: 100,
            },
          ],
          xAxis: {
            type: "category",
            data: this.generateTimeArray,
            axisLabel: {
              interval: this.interval,
              show: true,
              fontSize: 13,
              color: "#999",
            },
            axisLine: {
              show: true,
              lineStyle: {
                color: "#999",
              },
            },
            axisTick: {
              show: true,
            },
          },
          yAxis: [
            {
              type: "value",
              nameTextStyle: {
                color: "#999",
                fontSize: 13,
                align: "center",
                padding: [0, 30, 0, 0],
              },
              axisLabel: {
                show: true,
                fontSize: 14,
                color: "#999",
              },
              axisLine: {
                show: false,
                lineStyle: {
                  color: "#999",
                },
              },
              axisTick: {
                show: false,
              },
              splitLine: {
                lineStyle: {
                  color: "#b9bec9",
                  type: "solid",
                },
              },
            },
          ],
          series: seriesData,
        };

        this.myChart.setOption(option);

        window.addEventListener("resize", () => {
          if (this.myChart) {
            this.myChart.resize();
          }
        });
      },
    },
  };
</script>

<style lang="less" scoped>
</style>