·················································二更······························································
始终觉得百度的聚合插件很卡,后来发现点多了之后相当吃内存。所以最终还是放弃百度地图插件,将里面核心的东西提出来,重新写了个简版的。
/**
* @namespace BMap的所有library类均放在BMapLib命名空间下
*/
var BMapLib = window.BMapLib = BMapLib || {};
(function() {
var rootMap;
var rootGridSize;
var rootMinClusterSize;
var rootMapOverlays = [];
var rootIsAverageCenter;
/**
* 获取一个扩展的视图范围,把上下左右都扩大一样的像素值。
* @param {Map} map BMap.Map的实例化对象
* @param {BMap.Bounds} bounds BMap.Bounds的实例化对象
* @param {Number} gridSize 要扩大的像素值
*
* @return {BMap.Bounds} 返回扩大后的视图范围。
*/
var getExtendedBounds = function(bounds) {
bounds = cutBoundsInRange(bounds);
var pixelNE = rootMap.pointToPixel(bounds.getNorthEast());
var pixelSW = rootMap.pointToPixel(bounds.getSouthWest());
pixelNE.x += rootGridSize;
pixelNE.y -= rootGridSize;
pixelSW.x -= rootGridSize;
pixelSW.y += rootGridSize;
var newNE = rootMap.pixelToPoint(pixelNE);
var newSW = rootMap.pixelToPoint(pixelSW);
return new BMap.Bounds(newSW, newNE);
};
/**
* 按照百度地图支持的世界范围对bounds进行边界处理
* @param {BMap.Bounds} bounds BMap.Bounds的实例化对象
*
* @return {BMap.Bounds} 返回不越界的视图范围
*/
var cutBoundsInRange = function(bounds) {
var minX = getRange(bounds[0], -180, 180);
var maxX = getRange(bounds[1], -180, 180);
var minY = getRange(bounds[2], -74, 74);
var maxY = getRange(bounds[3], -74, 74);
return new BMap.Bounds(new BMap.Point(minX, minY), new BMap.Point(maxX, maxY));
};
/**
* 紫 红 橙 黄 蓝 绿 单个
*/
var getStylesBylength = function(len) {
var style = {
'cursor': 'pointer',
'padding': 0,
'max-width': 'inherit',
'margin-bottom': 0,
'border': 0,
'color': '#fff',
'font-size': '0.8em',
'border-radius': '50%',
'text-align': 'center',
'box-shadow': '0 0 8px 2px RGBa(135, 185, 255, 0.5), 0 0 8px 2px RGBa(135, 185, 255, 0.5) inset',
};
var color = '';
var size = '';
if (len == 1) {} else if (len < 100) {
color = 'rgba(24,150,3, 0.6)';
size = '28px';
} else if (len < 500) {
color = 'rgba(13, 141, 181, 0.6)';
size = '28px';
} else if (len < 1000) {
color = 'rgba(255,255,0, 0.6)';
size = '28px';
} else if (len < 5000) {
color = 'rgba(255, 165,0, 0.6)';
size = '35px';
} else if (len < 50000) {
color = 'rgba(247, 9, 9, 0.6)';
size = '40px';
} else {
color = 'rgba(183,0,255, 0.6)';
size = '40px';
}
style['background-color'] = color;
style['width'] = size;
style['height'] = size;
style['line-height'] = size;
return style;
};
/**
* 对单个值进行边界处理。
* @param {Number} i 要处理的数值
* @param {Number} min 下边界值
* @param {Number} max 上边界值
*
* @return {Number} 返回不越界的数值
*/
var getRange = function(i, mix, max) {
mix && (i = Math.max(i, mix));
max && (i = Math.min(i, max));
return i;
};
/**
*@exports MarkerClusterer as BMapLib.MarkerClusterer
*/
var MarkerClusterer =
/**
* MarkerClusterer
* @class 用来解决加载大量点要素到地图上产生覆盖现象的问题,并提高性能
* @constructor
* @param {Map} map 地图的一个实例。
* @param {Json Object} options 可选参数,可选项包括:<br />
* markers {Array<Marker>} 要聚合的标记数组<br />
* girdSize {Number} 聚合计算时网格的像素大小,默认60<br />
* maxZoom {Number} 最大的聚合级别,大于该级别就不进行相应的聚合<br />
* minClusterSize {Number} 最小的聚合数量,小于该数量的不能成为一个聚合,默认为2<br />
* isAverangeCenter {Boolean} 聚合点的落脚位置是否是所有聚合在内点的平均值,默认为否,落脚在聚合内的第一个点<br />
* styles {Array<IconStyle>} 自定义聚合后的图标风格,请参考TextIconOverlay类<br />
*/
BMapLib.MarkerClusterer = function(map, options) {
if (!map) {
return;
}
rootMap = map;
this._markers = [];
this._clusters = [];
var opts = options || {};
rootGridSize = opts["gridSize"] || 2000 / map.getZoom();
rootMinClusterSize = opts["minClusterSize"] || 2;
rootIsAverageCenter = true;
if (opts['isAverageCenter'] != undefined) {
rootIsAverageCenter = opts['isAverageCenter'];
}
this._styles = opts["styles"] || [];
var that = this;
var mkrs = opts["markers"];
rootMap.addEventListener("zoomend", function(lv) {
let lvl = lv.target.getZoom();
rootGridSize = 2000 / lvl;
that._redraw2();
});
rootMap.addEventListener("moveend", function() {
that._redraw2();
});
this._markers = mkrs;
this.addMarkers2();
};
MarkerClusterer.prototype.addMarkers2 = function() {
var mapBounds = rootMap.getBounds();
var x_min = mapBounds.Le,
x_max = mapBounds.Ge,
y_min = mapBounds.Wd,
y_max = mapBounds.Ud;
//遍历排除不在屏幕范围的点
let tMks = [];
for (let index = 0, mk; mk = this._markers[index]; index++) {
if (mk) {
if (mk[0] <= x_max && mk[0] >= x_min && mk[1] >= y_min && mk[1] <= y_max)
tMks.push(mk);
}
}
for (var j = 0, mk; mk = tMks[j]; j++) {
this._addToClosestCluster2(mk)
}
//开始渲染
for (var i = 0, cls; cls = this._clusters[i]; i++) {
if (cls) {
cls.render();
}
}
}
MarkerClusterer.prototype._addToClosestCluster2 = function(mk) {
var dis2 = 32400,
d1 = 0,
d2 = 0,
d = 0;
var cluster = null;
for (let i = 0, clus; clus = this._clusters[i]; i++) {
var c = clus.center; //[lng,lat]
d1 = c[0] - mk[0];
d2 = c[1] - mk[1];
d = d1 * d1 + d2 * d2;
if (d < dis2) {
dis2 = d;
cluster = clus;
}
}
if (cluster && cluster.isMarkerInClusterBounds(mk)) {
cluster.addMk(mk)
} else {
var clustera = new Cluster2(this);
clustera.addMk(mk);
this._clusters.push(clustera);
}
};
MarkerClusterer.prototype._redraw2 = function() {
this.clear();
this.addMarkers2();
};
MarkerClusterer.prototype.clear = function() {
rootMapOverlays.forEach(ol => {
rootMap.removeOverlay(ol);
})
for (var i = 0, cluster; cluster = this._clusters[i]; i++) {
cluster.mks = [];
cluster.center = null;
cluster._gridBounds = [];
}
this._clusters = []; //置空Cluster数组
};
function Cluster2() {
this.center = null; //聚合图标的落脚点 ,目前是假的center
this.mks = [];
this._gridBounds = [];
}
Cluster2.prototype.render = function() {
var len = this.mks.length;
if (len < rootMinClusterSize) {
for (var j = 0; j < len; j++) {
let pt = new BMap.Point(this.mks[j][0], this.mks[j][1]);
let marker = new BMap.Marker(pt);
rootMap.addOverlay(marker);
rootMapOverlays.push(marker);
}
} else {
if (rootIsAverageCenter) {
var lngLat = this.mks.reduce((s, i) => {
s[0] = s[0] + i[0];
s[1] = s[1] + i[1];
return s;
}, [0, 0]);
var lng = lngLat[0] / len;
var lat = lngLat[1] / len;
this.center = [lng, lat];
this.updateGridBounds(this.center);
}
var clusterMarker = new BMap.Label(len, {
position: new BMap.Point(this.center[0], this.center[1]), // 指定文本标注所在的地理位置
offset: new BMap.Size(0, -3) //设置文本偏移量
}); // 创建文本标注对象
clusterMarker.setStyle(getStylesBylength(len));
rootMap.addOverlay(clusterMarker);
rootMapOverlays.push(clusterMarker);
var that = this;
clusterMarker.addEventListener('click', (a) => {
var b = that._gridBounds;
rootMap.setViewport(b);
});
}
};
Cluster2.prototype.addMk = function(mk) {
if (!this.center) {
//处理第一个点的情况
this.center = mk;
this.updateGridBounds(mk); //
} else {
// if (rootIsAverageCenter) {
// var l = this.mks.length + 1;
// var lat = (this.center[1] * (l - 1) + mk[1]) / l;
// var lng = (this.center[0] * (l - 1) + mk[0]) / l;
// this.center = [lng, lat];
// this.updateGridBounds(this.center);
// }
}
this.mks.push(mk);
}
Cluster2.prototype.updateGridBounds = function(mk) {
this._gridBounds = getExtendedBounds([mk[0], mk[0], mk[1], mk[1]]);
}
Cluster2.prototype.isMarkerInClusterBounds = function(mk) {
return mk[0] <= this._gridBounds.Ge && mk[0] >= this._gridBounds.Le &&
mk[1] >= this._gridBounds.Wd && mk[1] <= this._gridBounds.Ud;
};
})();
效果还是可以比较快。
image.png
网友评论