灵心如玉,守一生无惧|

SadicZhou

园龄:3年2个月粉丝:7关注:4

在echaerts中渲染50万条数据的优化方案

背景:项目需求中要在页面上渲染大约50万条左右的波形数据图表

 

 那么如何解决渲染中的卡顿呢?

肯定是要从服务端和前端一起优化这是毋庸置疑的。

1.服务端:

服务端耗时最多的一定是在数据库的筛选数据的行为上,本次需求中数据的筛选是根据物理量的类型和时间来进行的。

为了提速,应当取消掉其他的筛选条件,并且使用mongodb和redis,还应该将数据分片发送给前端。

2.前端:

首先我们要搞清楚,优化策略的重点是在数据的拿取上,因为渲染的速度其实远快于数据交互的速度,要想提速首先要解决的是短板。

在数据拿取时我们应当进行轮询,分片的拿到服务端传输的数据,然后进行渲染。

我们来整理一下思路:

1.第一次轮询结束拿到数据后,我们需要进行绘图。然后判断是否进行下一次轮询

2.第二次轮询结束之后我们需要将拿到的数据,append到图表之中,然后判断否进行下一次轮询

3.如何随时的让轮询终止。

这三个就是目前我们需要解决的问题点。

第一次拿到数据之后我们判断数据的长度是否为0,为0则终止轮询,不为0则继续。

后面继续轮询时,每次轮询拿到数据都要判断图表是否存在,存在就dispose,然后重绘。

要注意的点时,我们的图表是可以缩放的,所以在重绘时还需要将缩放条的位置进行记录,然后设置到datazoom里面,这样可以提高用户体验。

下面贴出代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
getListWaveformDat(count) {
 
      this.loading = true;//加载loading动画
      
 
      //获取波形图数据
      getListWaveformDat({
        deviceId: this.queryPointParams.deviceId,
        diId: this.diId,
        reportedOn: this.orgTime,
        keyName: this.dataAxis,
        num: this.pageNum,
        size: 10000,
        count: count ? count : '',
      }).then((res) => {
        if (res.length > 0) {
          this.noData = false//是否加载缺省值图片
          console.log(this.orgchart)
          if (this.orgchart) {
            this.orgchart.dispose();
          }
          this.oscillograph = res;
          let x = [];
          for (let i = 0; i < this.oscillograph.length; i++) {
            x[i] = this.oscillograph[i].count;
          }//处理X轴数据
 
          let y = [];
          for (let i = 0; i < this.oscillograph.length; i++) {
            y[this.oscillograph[i].count * 1 - 1] = this.oscillograph[i].value * 1
          }
          for (let i = 0; i < this.oscillographY.length; i++) {
            if (this.oscillographY[i] == undefined) {
              if (y[i]) {
                this.oscillographY[i] = y[i]
              }
            }
          }//处理Y轴数据
        
          console.log(this.oscillographY)
          this.pageNum = this.pageNum + 1;//轮询次数加1
          this.$nextTick(() => {
            this.orgDraw();//绘制图表
 
          })
 
          this.loading = false;//关闭加载loading
    
          this.getListWaveformDat(x[x.length - 1])//继续轮询
     
 
        }
        else {
         //如果加载的数据为空
          this.loading = false;
          console.log(this.orgchart)
          if (this.pageNum == 1) {
         //如果第一次轮询就为空,加载缺省图片
            this.noData = true;
            if (this.orgchart) {
              this.orgchart.dispose();//清除上一次加载的图表
 
 
            }
           
          this.pageNum = 1;//请求完所有数据之后初始化一下
          return
 
        }
 
      });
 
    },   

  

 

 

 这是接口返回的数据源,X就是count,Y就是Value。因为每次轮询查到的数据都是乱序的,但是图表要求X,Y必须对应所以需要对数据进行重新排序。

思路:1.先获取X轴的长度,然后根据长度生成X,Y两个数组。2.将Y数组的值都设置为undefined,X数组的值设为1-X的长度3.遍历接口的数据,将count作为Y的索引,将value塞入对应的元素中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
getX() {
      getMaxCount(
        {
          deviceId: this.queryPointParams.deviceId,
          reportedOn: this.orgTime,
          keyName: this.dataAxis,
        }
      ).then((res) => {
        console.log(res, '======')
        this.oscillographX = Array.from({ length: res * 1 }, (value, key) => key + 1)
        this.oscillographY = Array.from({ length: res * 1 }, (value, key) => undefined)
        console.log(this.oscillographX);
      })
    },

  处理X,Y轴数据的代码在第一个代码块中已经有就不贴了。

完成数据处理之后就是进行绘图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
orgDraw() {
   let that = this;
   if (this.orgchart) {
     this.orgchart.dispose();
   }
   console.log(this.start, this.end, 'xxx')
   if (this.tabname !== "原始数据") {
     return;
   }
   // if (this.orgchart) {
   //   this.orgchart.dispose()
   // }
   var chartDom = document.getElementById("orgChart");
   var myChart = echarts.init(chartDom);
   const option = {
     title: {
       left: "center",
       text: "原始数据",
     },
     tooltip: {
       trigger: "axis",
       axisPointer: {
         type: "shadow",
       },
     },
     grid: {
       bottom: 90,
     },
     dataZoom: [{
       type: 'inside',//图表下方的伸缩条
       show: true, //是否显示
       realtime: true, //拖动时,是否实时更新系列的视图
       start: this.start, //伸缩条开始位置(1-100),可以随时更改
       end: this.end, //伸缩条结束位置(1-100),可以随时更改
     },
     {
       type: 'slider',//图表下方的伸缩条
       show: true, //是否显示
       realtime: true, //拖动时,是否实时更新系列的视图
       start: this.start, //伸缩条开始位置(1-100),可以随时更改
       end: this.end, //伸缩条结束位置(1-100),可以随时更改
     }
 
     ],
     xAxis: {
       data: this.oscillographX,
       silent: false,
       splitLine: {
         show: false,
       },
       splitArea: {
         show: false,
       },
     },
     yAxis: {
     },
     series: [
       {
         // seriesIndex: 9,
         type: "line",
         data: this.oscillographY,
         large: true,
       },
     ],
   };
   console.log(myChart.appendData)
    
   myChart.setOption(option, true);
   // myChart.appendData({
   //   seriesIndex: 0,
   //   data: this.oscillographY
   // })
   myChart.on('datazoom', function (params) {
     // let xAxis = myChart.getModel().option.xAxis[1];//获取axis
     console.log(params.batch[0].end, params.batch[0].start, 'xAxis')
     that.start = params.batch[0].start;
     that.end = params.batch[0].end;
 
   });//记录datazoom的滚动距离
   this.orgchart = myChart;
   this.isStart = false;
   return;
 },

  绘图中唯一需要做的就是记录datazoom的滚动进度拿到start和end重绘之后进行赋值。

  总结一下:处理的思路就行以一万条数据为一次不断进行轮询,将数据不断的拼接,然后重新绘图。为什么不用echarts提供的appendData()方法呢?因为根本不支持。

本文作者:SadicZhou

本文链接:https://www.cnblogs.com/SadicZhou/p/17191138.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   SadicZhou  阅读(2499)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 尚好的青春 孙燕姿
  2. 2 孙燕姿
  3. 3 克卜勒 孙燕姿
- 孙燕姿
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.