在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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步