Echarts绘制动态折线图,分段绘制不同颜色

一、需求描述

  最近遇到了一个需求,需要接收实时数据绘制曲线图,并且能够根据选中项绘制多个图表,固定区间使用红色线段。

  摸着石头过河,尝试了许多方式,踩了许多坑。记录一下。

二、效果展示

三、解决方法

   1、确定需要连接的topic,以及容器的准备
 使用可以多选的下拉选择,直接遍历选中的数据,即可将绘制图形的容器准备好。

// 确定需要连接的topic,以及容器的准备
//使用可以多选的下拉选择,直接遍历选中的数据,即可将绘制图形的容器准备好
<div class="topic-select">
      <span>topic选择</span>
      <el-select
        v-model="topic"
        :multiple="true"
        collapse-tags
        @change="changeTopic"
        style="width: 30%"
        placeholder="请选择topic"
      >
        <el-option
          v-for="item in topicList"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        ></el-option>
      </el-select>
      <el-button @click="connectMqtt">确定</el-button>
    </div>
    <div
      class="chart-container"
      :id="`chart-container-${item}`"
      v-for="(item, index) in topic"
      :key="index"
    ></div>

2、连接mqtt,接收数据

// 初始化分段区间的二维数组
this.pieces = new Array(this.topic.length).fill([]);
// 循环select的选中项进行建立连接
      this.topic.map((item, index) => {
        for (let i = 0; i < this.topicList.length; i++) {
          if (item == this.topicList[i].value) {
            //三个参数 订阅的主题、当前主题的分段区间、当前主题的下标,用来存储每个图表的数据
            this.createMqtt(item,this.topicList[i].threshold index);
          }
        }
      });

3、接受数据,处理区间

createMqtt(topic, threshold, index) {
      this.chartData[index] = [];
      this.pieces[index] = [];

//threshold区间的格式例如 [[36,45],[88,98]] 
// 需要将区间扩充到对与整个线段 进行分段
// [[0,36],[36,45],[45,88],[88,98],[98,∞]]  类似这种形式
// 使用echarts中的visualMap中的pieces进行将整个折线进行分段 
// 下面这种方式并不高明,但是解决了问题
      for (let i = 0; i < threshold.length; i++) {
        if (threshold.length == 1) {
          this.pieces[index].push({
            gt: 0,
            lte: threshold[i][0],
            color: "green",
          });
          this.pieces[index].push({
            gt: threshold[i][0],
            lte: threshold[i][1],
            color: "red",
          });
          this.pieces[index].push({
            gt: threshold[i][1],
            color: "green",
          });
        }
        if (i == 0) {
          this.pieces[index].push({
            gt: 0,
            lte: threshold[i][0],
            color: "green",
          });
          this.pieces[index].push({
            gt: threshold[i][0],
            lte: threshold[i][1],
            color: "red",
          });
        } else if (i == threshold.length - 1) {
          this.pieces[index].push({
            gt: threshold[i - 1][1],
            lte: threshold[i][0],
            color: "green",
          });
          this.pieces[index].push({
            gt: threshold[i][0],
            lte: threshold[i][1],
            color: "red",
          });
          this.pieces[index].push({
            gt: threshold[i][1],
            color: "green",
          });
        } else {
          this.pieces[index].push({
            gt: threshold[i - 1][1],
            lte: threshold[i][0],
            color: "green",
          });
          this.pieces[index].push({
            gt: threshold[i][0],
            lte: threshold[i][1],
            color: "red",
          });
        }
      }
      //创建链接,接收数据
      mqttTopic = "xxx-" + topic;
      mqtt[index] = new mqttHandle(mqttTopic);
      client = mqtt[index].createConnect();
//  初始化图表
      this.initChart(topic, index);

      client.on("message", (topic, message) => {
        // this.chartData的数据格式 
//[
 //[[time,data],[time,data]],//图1
 //[[time,data],[time,data]],//图2
//]
        try {
          let receiveNews = JSON.parse(message.toString());
          this.chartData[index].push([receiveNews.time, receiveNews.data]);

        } catch (error) {}
      });
    },

4、echarts的配置项

initChart(container, index) {
      let chartDom = document.getElementById(`chart-container-${container}`);
      let myChart = echarts.init(chartDom);
      let option = {
        title: {
          text: container,
          textStyle: {
            fontSize: 20,
            color: "#fff",
          },
        },
        tooltip: {
          trigger: "axis",

          axisPointer: {
            animation: false,
          },
        },
        xAxis: {
         // type 一定要设置为category,才能分段成功   !!!!!!
          type: "category",
          splitLine: {
            show: false,
          },
          name: "时间",
          boundaryGap: false,
          axisLabel: {
            // rotate: 45,
            color: "#fff",
          },
          axisLine: {
            lineStyle: {
              color: "#fff",
            },
          },
          nameTextStyle: {
            fontSize: 16,
            color: "#fff",
          },
        },
        dataZoom: {
          type: "slider",
        },
        visualMap: {
          show: false,
          dimension: 0,
          //处理好的分段区间 index对应每个图表的分段数据
          pieces: this.pieces[index],
        },
        yAxis: {
          type: "value",
          show: true,
          boundaryGap: [0, "100%"],
          splitLine: {
            show: false,
          },
          // min:150,
          axisLabel: {
            color: "#fff",
          },
          axisLine: {
            lineStyle: {
              color: "#fff",
            },
          },
        },

        series: [
          {
            name: "实时数据",
            type: "line",
            showSymbol: false,
            data: this.chartData[index],
          },
        ],
      };
      myChart.setOption(option);
      setInterval(() => {
        myChart.setOption({
          series: [
            {
              data: this.chartData[index],
              itemStyle: {
                show: true, // 显示标记点
                color: "#1890ff", //标记点颜色
              },
            },
          ],
        });
      }, 500);
    },

四、官方示例

可以直接复制展示

function randomData() {
  now = new Date(+now + oneDay);
  value = value + Math.random() * 21 - 10;
  return {
    name: now.toString(),
    value: [
      [now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'),
      Math.round(value)
    ]
  };
}
let data = [];
let now = new Date(1997, 9, 3);
let oneDay = 24 * 3600 * 1000;
let value = Math.random() * 1000;
for (var i = 0; i < 1000; i++) {
  data.push(randomData());
}
option = {
  title: {
    text: 'Dynamic Data & Time Axis'
  },
  tooltip: {
    trigger: 'axis',
    formatter: function (params) {
      params = params[0];
      var date = new Date(params.name);
      return (
        date.getDate() +
        '/' +
        (date.getMonth() + 1) +
        '/' +
        date.getFullYear() +
        ' : ' +
        params.value[1]
      );
    },
    axisPointer: {
      animation: false
    }
  },
  dataZoom:{
    
  },
 visualMap: {
    show: false,
    dimension: 0,
    pieces: [
      {
        gt:0,
        lte:300,
        color:"green"
      },{
        gt:300,
        lte:600,
        color:"red"
      },{
        gt:300,
        color:"green"
      }
    ]
  },
  xAxis: {
    type: 'category',
    splitLine: {
      show: false
    }
  },
  yAxis: {
    type: 'value',
    boundaryGap: [0, '100%'],
    splitLine: {
      show: false
    }
  },
  series: [
    {
      name: 'Fake Data',
      type: 'line',
      showSymbol: false,
      data: data
    }
  ]
};
setInterval(function () {
  for (var i = 0; i < 5; i++) {
    data.shift();
    data.push(randomData());
  }
  myChart.setOption({
    series: [
      {
        data: data
      }
    ]
  });
}, 1000);

五、总结

   成功画出动态数据图表的分段绘制。这里有一点需要注意,visualMap中的pieces中 的gt,lte对应的数值实际上是你在x轴上的下标。也就意味着 如果区间是[40,50],那么分段只会在数据上的第40个点开始变色,而不是x轴横坐标的40。

  个人记录,如有可供参考,非常荣幸。如有错误欢迎指正。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值