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

那么如何解决渲染中的卡顿呢?
肯定是要从服务端和前端一起优化这是毋庸置疑的。
1.服务端:
服务端耗时最多的一定是在数据库的筛选数据的行为上,本次需求中数据的筛选是根据物理量的类型和时间来进行的。
为了提速,应当取消掉其他的筛选条件,并且使用mongodb和redis,还应该将数据分片发送给前端。
2.前端:
首先我们要搞清楚,优化策略的重点是在数据的拿取上,因为渲染的速度其实远快于数据交互的速度,要想提速首先要解决的是短板。
在数据拿取时我们应当进行轮询,分片的拿到服务端传输的数据,然后进行渲染。
我们来整理一下思路:
1.第一次轮询结束拿到数据后,我们需要进行绘图。然后判断是否进行下一次轮询
2.第二次轮询结束之后我们需要将拿到的数据,append到图表之中,然后判断否进行下一次轮询
3.如何随时的让轮询终止。
这三个就是目前我们需要解决的问题点。
第一次拿到数据之后我们判断数据的长度是否为0,为0则终止轮询,不为0则继续。
后面继续轮询时,每次轮询拿到数据都要判断图表是否存在,存在就dispose,然后重绘。
要注意的点时,我们的图表是可以缩放的,所以在重绘时还需要将缩放条的位置进行记录,然后设置到datazoom里面,这样可以提高用户体验。
下面贴出代码:
- 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塞入对应的元素中。
- 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轴数据的代码在第一个代码块中已经有就不贴了。
完成数据处理之后就是进行绘图。
- 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()方法呢?因为根本不支持。