優化百度地圖點聚合

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

 

 

好的,筆者開始了做死之旅。上面筆者只是生成了50個隨機點。dom

接下來要測試下1000個點,嗯有點小卡,可是還能操做,測試

2000個點,個人天,這shit同樣的卡頓是什麼鬼!!this

5000個點,好的,完美,動也動不了 簡直漂亮google

10000個點,頁面無響應。。。。。。。spa

 

-----------我只是一條漂亮的分割線----------prototype

由於,曾經按着baidu的點聚合,在google地圖裏 依樣畫葫蘆過,當時老是隱隱的以爲不妥,因而筆者準備查查源碼。code

    /**
     * 根據所給定的標記,建立聚合點
     * @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);
        }    
    };

以上兩個方法就是前文所述的算法的具體實現,blog

先排除全部不在可視範圍的點,而後經過比較marker點和聚合點的距離,拿到距離最近的聚合點,判斷marker點是否在聚合點的外包正方形內;rem

這一段是正常算法須要沒啥問題,看起來問題只能出在  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方法最後加了一個遍歷全部聚合點的操做,代碼以下

 

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

  

 

最後測試了一下,妥妥的1W無壓力,2W也hold住。(總感受度娘故意的)

相關文章
相關標籤/搜索