一、问题
公司的项目中在百度地图上生成了成千上万的点,所以使用了标记聚合器MarkerClusterer来处理海量点,但是每个点根据异常类型,分为正常(绿色)和异常(红色),这时如果用了聚合器,只有没被聚合的时候才能看得出来是否异常,因此处理逻辑是,一个聚合如果包含一个及以上的异常点,则显示红色。不包含任何异常点就显示绿色图片效果如下:
缩小后
二、解决方案:
1、生成标记marker时,添加是否异常的属性值
let marker = new BMap.Marker(new BMap.Point(X, Y), {icon});
marker.isAbnormal = Boolean(abnormal_type);
2、生成聚合器options时,添加异常图片样式abnormalStyles
let options = {
markers,
styles:[],
abnormalStyles:[]
}
// 设置聚合icon样式
var sizes = [53, 56, 66, 78, 90];
for(var i = 0, size; size = sizes[i]; i++){
options.styles.push({
url:this.normalIconUrl + i + '.png',//绿色图片路径
size: new BMap.Size(size, size)
});
options.abnormalStyles.push({
url:this.abnormalIconUrl + i + '.png',//红色图片路径
size: new BMap.Size(size, size)
});//异常图片样式
}//for循环的简洁写法
this.markerClusterer = new BMapLib.MarkerClusterer(this.map, options); //生成聚合器
3、修改聚合器文件MarkerClusterer_min.js
3.1 将自定义聚合后的图标风格存给MarkerClusterer实例
3.2 给聚合添加方法:判断该聚合对象中是否有异常类型的marker
/**
* 判断一个聚合对象中是否有异常类型的marker
* @param {Marker} markers 该聚合对象中的所有的标记marker。
* @return {Boolean} true 包含异常标记 false 不包含。
*/
Cluster.prototype._isAbnormal = function(markers) {
return markers.find((item)=>{
return item.isAbnormal === true
})
};
3.3 在更新该聚合的显示样式时,如果该聚合包含异常点,则该聚合的样式TextIconOverlay实例重新设置样式,但是看了TextIconOverlay_min.js文件中,只定义了setPosition更新位置和setText更新文字的方法,并没有定义更新图片的方法,所以我们需要自己定义
4、在TextIconOverlay_min.js文件中,定义设置css样式的方法
/**
*设置该覆盖物的css。
*@param {styles} styles 要设置styles。
*@return 无返回值。
*/
TextIconOverlay.prototype.setStyles = function (styles) {
if(styles){
this._styles = styles;
this._updateCss();//写好的更新css的方法
}
};
三、OK,大功告成!理一下思路:
整个修改过程,需要了解一下重绘过程,就很简单了。聚合器重画_reDraw()时,先清除上一次的聚合的结果,在根据所给定的标记,创建聚合点,并且遍历所有聚合点,进行重新渲染render。关键就是重新渲染中的updateClusterMarker函数,更新该聚合的显示样式,也即TextIconOverlay。该函数中,有调用重新渲染更新位置和聚合数字的函数,因此,更新样式也需要在这里进行,查看TextIconOverlay源代码,并没有现成的更新样式的方法,这是可以参考setPosition和setText两个函数来自行定义setStyles方法,简单在初始化函数里找一下,就可以看到有一个_updateCss的方法
所以我们根据_updateCss方法来自定义setStyles方法,修改该样式实例的_styles,并抛出,就可以了