echarts折线图中曲线随时间平滑移动的实时动态折线图

786 阅读2分钟

需求:

当数据跨度不满30分钟时,数据曲线逐渐向右增加,当数据时间跨度超过30分钟后,曲线在近30分钟的时间窗口进行平滑移动过度。

实现思路:

  1. 存储近30分钟的曲线数据,为了保证数据更新时在当前时间窗口数据的完整性,需额外多存储一些数据,可以存储近35分钟的数据。series.data 的数据的存储形式采用[ {name: '', vlaue: [] }, ... ]的形式, data中的每一个数据对象的name必须唯一;
  2. 设置option中的xAxis,通过实时改变min 和 max的值来进行窗口移动

实现代码

  let charts = {
    unit: 'kW',
    names: ['name1', 'name2', 'name3'],
    value: [[], [], []],
  };
  let color = ['rgba(79,154,255', 'rgba(75,243,255', 'rgba(255,168,0'];
  let lineY = [];
  const axisInterval = 30; // 折线图显示时间区间大小(分钟)
  
  watch(
    () => props.dataSource,
    () => {
      if (!props.dataSource) {
        return;
      }
      lineY = [];
      /***************************使用数组存储近35分钟曲线数据**************************/
      for (let i = 0; i < charts.names.length; i++) {
        let x = i;
        if (x > color.length - 1) {
          x = color.length - 1;
        }
        if (
          charts.value[0].length > 0 &&
          (dateUtil(charts.value[0][charts.value[0].length - 1].value[0]).valueOf() -
            dateUtil(charts.value[0][0].value[0]).valueOf()) /
            1000 /
            60 >=
            axisInterval + 5
        ) {
          charts.value[i].shift();
          charts.value[i].push({
            name: `${props.dataSource[i].name}-${props.dataSource[i].time}`,
            value: [props.dataSource[i].time, props.dataSource[i].value],
          });
        } else {
          charts.value[i].push({
            name: `${props.dataSource[i].name}-${props.dataSource[i].time}`,
            value: [props.dataSource[i].time, props.dataSource[i].value],
          });
        }

        /*************************配置series数据**************************/
        let cureData = {
          name: charts.names[i],
          type: 'line',
          color: color[x] + ')',
          smooth: true,
          areaStyle: {
            color: new echarts.graphic.LinearGradient(
              0,
              0,
              0,
              1,
              [
                {
                  offset: 0,
                  color: color[x] + ', 0.3)',
                },
                {
                  offset: 0.8,
                  color: color[x] + ', 0)',
                },
              ],
              false,
            ),
            shadowColor: 'rgba(0, 0, 0, 0.1)',
            shadowBlur: 10,
          },
          symbolSize: 0,
          data: charts.value[i],
        };
        lineY.push(cureData);
      }

      /*************************配置options数据**************************/
      setOptions({
        grid: {
          left: 10,
          right: 10,
          top: 40,
          bottom: 10,
          containLabel: true,
        },
        tooltip: {
          show: true,
          trigger: 'axis',
          textStyle: {
            color: '#fff',
          },
          borderColor: '#32e0da',
          backgroundColor: 'rgba(0,0,0,0.2)', // 背景
          padding: [8, 10], //内边距
          extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影
        },
        legend: {
          top: 10,
          right: 10,
          icon: 'rect',
          textStyle: {
            color: '#d5d5d5',
          },
        },
        xAxis: {
          type: 'time',
          // 不满30分钟时,x轴最小值为即是数据最小时间
          // 30分钟后,x轴最小值为最大值(即当前时间)减去时间窗口间隔(30)
          min: function (value) {
            if (value.max - value.min < 1000 * 60 * axisInterval) {
              return value.min;
            } else {
              return value.max - 1000 * 60 * axisInterval;
            }
          },
          // 不满30分钟时,x轴最大值为最小值加上时间窗口间隔(30)
          // 30分钟后,x轴最小值为最大值(即当前时间)加上一小段间隔,以保证最新数据
          //	与则线图右框保持一定间隔。
          max: function (value) {
            if (value.max - value.min < 1000 * 60 * axisInterval) {
              return value.min + 1000 * 60 * axisInterval;
            } else {
              return value.max + 1000 * 60 * axisInterval * 0.033;
            }
          },
          splitNumber: 5,
          boundaryGap: false, // 横坐标两边不需要留白
          axisLine: {
            lineStyle: {
              color: '#18649e',
              width: 2,
            },
          },
          axisLabel: {
            // rotate: 40,
            margin: 16,
            color: '#fff',
          },
          axisTick: {
            show: false,
          },
        },
        yAxis: {
          type: 'value',
          name: 'kW',
          min: 0,
          max: 400,
          nameTextStyle: {
            color: '#fff',
            verticalAlign: 'middle',
          },
          axisLabel: {
            // rotate: 40,
            margin: 16,
            color: '#fff',
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#18649e',
              width: 2,
            },
          },
          splitLine: {
            lineStyle: {
              color: '#224180',
              type: 'dashed',
            },
          },
        },
        series: lineY,
      });
    },
    { immediate: true },
  );