百度的點聚合算法 是基於方格和距離的聚合算法,即開始的時候地圖上沒有任何已知的聚合點,然后遍歷所有的點,去計算點的外包正方形(由gridSize指定),若此點的外包正方形與現有的聚合點的外包正方形不相交,則新建聚合點,若相交就把該點加到該聚合點,效果如下圖,為了便於查看,筆者特地把外包正方形畫了出來。

好的,筆者開始了作死之旅。上面筆者只是生成了50個隨機點。
接下來要測試下1000個點,嗯有點小卡,但是還能操作,
2000個點,我的天,這shit一樣的卡頓是什么鬼!!
5000個點,好的,完美,動也動不了 簡直漂亮
10000個點,頁面無響應。。。。。。。
-----------我只是一條漂亮的分割線----------
因為,曾經按着baidu的點聚合,在google地圖里 依樣畫葫蘆過,當時總是隱隱的覺得不妥,於是筆者准備查查源碼。
/**
* 根據所給定的標記,創建聚合點
* @return 無返回值
*/
MarkerClusterer.prototype._createClusters = function(){
var mapBounds = this._map.getBounds();
var extendedBounds = getExtendedBounds(this._map, mapBounds, this._gridSize);
for(var i = 0, marker; marker = this._markers[i]; i++){
if(!marker.isInCluster && extendedBounds.containsPoint(marker.getPosition()) ){
this._addToClosestCluster(marker);
}
}
};
/**
* 根據標記的位置,把它添加到最近的聚合中
* @param {BMap.Marker} marker 要進行聚合的單個標記
*
* @return 無返回值。
*/
MarkerClusterer.prototype._addToClosestCluster = function (marker){
var distance = 4000000;
var clusterToAddTo = null;
var position = marker.getPosition();
for(var i = 0, cluster; cluster = this._clusters[i]; i++){
var center = cluster.getCenter();
if(center){
var d = this._map.getDistance(center, marker.getPosition());
if(d < distance){
distance = d;
clusterToAddTo = cluster;
}
}
}
if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)){
clusterToAddTo.addMarker(marker);
} else {
var cluster = new Cluster(this);
cluster.addMarker(marker);
this._clusters.push(cluster);
}
};
以上兩個方法就是前文所述的算法的具體實現,
先排除所有不在可視范圍的點,然后通過比較marker點和聚合點的距離,拿到距離最近的聚合點,判斷marker點是否在聚合點的外包正方形內;
這一段是正常算法需要沒啥問題,看起來問題只能出在 cluster.addMarker(marker); 了
if(this.isMarkerInCluster(marker)){
return false;
}//也可用marker.isInCluster判斷,外面判斷OK,這里基本不會命中
if (!this._center){
this._center = marker.getPosition();
this.updateGridBounds();//
} else {
if(this._isAverageCenter){
var l = this._markers.length + 1;
var lat = (this._center.lat * (l - 1) + marker.getPosition().lat) / l;
var lng = (this._center.lng * (l - 1) + marker.getPosition().lng) / l;
this._center = new BMap.Point(lng, lat);
this.updateGridBounds();
}//計算新的Center
}
marker.isInCluster = true;
this._markers.push(marker);
var len = this._markers.length;
if(len < this._minClusterSize ){
this._map.addOverlay(marker);
//this.updateClusterMarker();
return true;
} else if (len === this._minClusterSize) {
for (var i = 0; i < len; i++) {
this._markers[i].getMap() && this._map.removeOverlay(this._markers[i]);
}
}
this._map.addOverlay(this._clusterMarker);
this._isReal = true;
this.updateClusterMarker();
return true;
};
果然不出所料,在addMarker() 方法內不停的去進行dom操作,不卡才怪。為什么度娘就不等計算結束后,在去一次操作完呢,
於是筆者把標黃的代碼抽離了出來給cluster類加了一個render方法, 然后在MarkerClusterer.createClusters方法最后加了一個遍歷所有聚合點的操作,代碼如下
|
1
2
3
4
5
6
7
8
9
10
11
12
|
render: function() {
var
len =
this
._markers.length;
if
(len <
this
._minClusterSize) {
this
._map.addOverlays(
this
._markers);
}
else
{
this
._map.addOverlay(
this
._clusterMarker);
this
._isReal =
true
;
this
.updateClusterMarker();
}
},<br>
|
最后測試了一下,妥妥的1W無壓力,2W也hold住。(總感覺度娘故意的)

