性能优化 - 解决使用data range intensity在大批量数据下渲染性能缓慢
314513535 opened this issue · comments
背景
项目中需要基于百度地图在一屏绘制大量栅格图形,数据量大概在几千到4万不等。同时需要对多边形的不同count值才用渐变色的分级着色(data range intensity)功能。之前只在Chrome浏览器上测试过,发现性能还行。但最近随着Chrome升级到V76版本后,性能暴降,于是做了几轮测试,发现
在V76及之后的Chrome版本上,绘制大概18000个栅格,需要消耗平均10~13秒。在其他浏览器,比如IE 11, Edge, Firefox上也要消耗至少10秒的时间,说明慢的原因不在于浏览器本身,Chrome升级后应该是把原先内置的某种优化废弃了。使用的option如下:
{
size: 20,
fillStyle: 'rgba(100, 100, 100, 0.9)',
max: 49,
maxSize: 35,
minSize: 0,
min: 0,
globalAlpha: 0.7,
context: '2d',
draw: 'intensity',
gradient: {
"0": " rgba(8,108,162,0.9)",
"0.01": " rgba(0, 187, 63, 0.9)",
"0.25": " rgba(255, 198, 0, 0.9)",
"0.5": " rgba(255, 146, 0, 0.9)",
"0.75": " rgba(255, 40, 0, 0.9)"
}
}
原因分析
仔细查看代码后发现了在渲染时BaseLayer会调用processData方法。该方法中会遍历data,在我的case中就是循环18000次。由于使用了intensity,每一次都会调用其getColor方法
`processData(data) {
var self = this;
var draw = self.options.draw;
if (draw == 'bubble' || draw == 'intensity' || draw == 'category' || draw == 'choropleth' || draw == 'simple') {
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (self.options.draw == 'bubble') {
data[i]._size = self.intensity.getSize(item.count);
} else {
data[i]._size = undefined;
}
var styleType = '_fillStyle';
if (data[i].geometry.type === 'LineString' || self.options.styleType === 'stroke') {
styleType = '_strokeStyle';
}
if (self.options.draw == 'intensity') {
data[i][styleType] = self.intensity.getColor(item.count);
} else if (self.options.draw == 'category') {
data[i][styleType] = self.category.get(item.count);
} else if (self.options.draw == 'choropleth') {
data[i][styleType] = self.choropleth.get(item.count);
}
}
}
}`
而在getColor方法中,会调用this.paletteCtx.getImageData 来获得ColorSet。正是这个地方造成性能的缓慢。
`Intensity.prototype.getColor = function (value) {
var imageData = this.getImageData(value);
return "rgba(" + imageData[0] + ", " + imageData[1] + ", " + imageData[2] + ", " + imageData[3] / 256 + ")";
}
Intensity.prototype.getImageData = function (value) {
var imageData = this.paletteCtx.getImageData(0, 0, 256, 1).data;
if (value === undefined) {
return imageData;
}
var max = this.max;
var min = this.min;
if (value > max) {
value = max;
}
if (value < min) {
value = min;
}
var index = Math.floor((value - min) / (max - min) * (256 - 1)) * 4;
return [imageData[index], imageData[index + 1], imageData[index + 2], imageData[index + 3]];
}`
解决方案
这个ColorSet显然与传入的value无关,可以提取到data 循环的外部
`Intensity.prototype.getColorSet = function () {
return this.paletteCtx.getImageData(0, 0, 256, 1).data;
};
Intensity.prototype.getColorFromColorSet = function (value, colorSet) {
var imageData = this.getImageDataFromColorSet(value, colorSet);
return "rgba(" + imageData[0] + ", " + imageData[1] + ", " + imageData[2] + ", " + imageData[3] / 256 + ")";
};
Intensity.prototype.getImageDataFromColorSet = function (value, colorSet) {
if (value === undefined) {
return colorSet;
}
var max = this.max;
var min = this.min;
if (value > max) {
value = max;
}
if (value < min) {
value = min;
}
var index = Math.floor((value - min) / (max - min) * (256 - 1)) * 4;
return [colorSet[index], colorSet[index + 1], colorSet[index + 2], colorSet[index + 3]];
};
然后在循环内使用预先准备好的ColorSet
processData(data) {
var self = this;
var draw = self.options.draw;
if (draw == 'bubble' || draw == 'intensity' || draw == 'category' || draw == 'choropleth' || draw == 'simple') {
var colorSet = self.intensity.getColorSet();
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (self.options.draw == 'bubble') {
data[i]._size = self.intensity.getSize(item.count);
} else {
data[i]._size = undefined;
}
var styleType = '_fillStyle';
if (data[i].geometry.type === 'LineString' || self.options.styleType === 'stroke') {
styleType = '_strokeStyle';
}
if (self.options.draw == 'intensity') {
data[i][styleType] = self.intensity.getColorFromColorSet(item.count, colorSet);
} else if (self.options.draw == 'category') {
data[i][styleType] = self.category.get(item.count);
} else if (self.options.draw == 'choropleth') {
data[i][styleType] = self.choropleth.get(item.count);
}
}
}
}`
测试后发现在新版Chrome及其他主流浏览器下,同样渲染18000个栅格仅需要1~2秒,问题解决。
望能采纳该意见及早进行修复。