3

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

 1 year ago
source link: https://www.cnblogs.com/SadicZhou/p/17191138.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

2702085-20230308102513783-1135498053.png

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

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

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
}
});
},   

  

2702085-20230320090053261-836532060.png

 这是接口返回的数据源,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()方法呢?因为根本不支持。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK