百度地图,点聚合展示速度优化

匿名 (未验证) 提交于 2019-12-02 21:53:52

大致问题,由于百度地图点聚合在超过1000个点的时候会出现稍许卡顿,而超过5000之后明显卡坤甚至浏览器崩溃的情况,所以需要修改百度地图外链引入的MarkerClusterer_min.js文件。

以下为修改后的文件内容

  1 /**   2  * @fileoverview MarkerClusterer标记聚合器用来解决加载大量点要素到地图上产生覆盖现象的问题,并提高性能。   3  * 主入口类是<a href="symbols/BMapLib.MarkerClusterer.html">MarkerClusterer</a>,   4  * 基于Baidu Map API 1.2。   5  *   6  * @author Baidu Map Api Group    7  * @version 1.2   8  */   9    10   11 /**   12  * @namespace BMap的所有library类均放在BMapLib命名空间下  13  */  14 var BMapLib = window.BMapLib = BMapLib || {};  15 (function(){  16       17     /**  18      * 获取一个扩展的视图范围,把上下左右都扩大一样的像素值。  19      * @param {Map} map BMap.Map的实例化对象  20      * @param {BMap.Bounds} bounds BMap.Bounds的实例化对象  21      * @param {Number} gridSize 要扩大的像素值  22      *  23      * @return {BMap.Bounds} 返回扩大后的视图范围。  24      */  25     var getExtendedBounds = function(map, bounds, gridSize){  26         bounds = cutBoundsInRange(bounds);  27         var pixelNE = map.pointToPixel(bounds.getNorthEast());  28         var pixelSW = map.pointToPixel(bounds.getSouthWest());   29         pixelNE.x += gridSize;  30         pixelNE.y -= gridSize;  31         pixelSW.x -= gridSize;  32         pixelSW.y += gridSize;  33         var newNE = map.pixelToPoint(pixelNE);  34         var newSW = map.pixelToPoint(pixelSW);  35         return new BMap.Bounds(newSW, newNE);  36     };  37   38     /**  39      * 按照百度地图支持的世界范围对bounds进行边界处理  40      * @param {BMap.Bounds} bounds BMap.Bounds的实例化对象  41      *  42      * @return {BMap.Bounds} 返回不越界的视图范围  43      */  44     var cutBoundsInRange = function (bounds) {  45         var maxX = getRange(bounds.getNorthEast().lng, -180, 180);  46         var minX = getRange(bounds.getSouthWest().lng, -180, 180);  47         var maxY = getRange(bounds.getNorthEast().lat, -74, 74);  48         var minY = getRange(bounds.getSouthWest().lat, -74, 74);  49         return new BMap.Bounds(new BMap.Point(minX, minY), new BMap.Point(maxX, maxY));  50     };   51   52     /**  53      * 对单个值进行边界处理。  54      * @param {Number} i 要处理的数值  55      * @param {Number} min 下边界值  56      * @param {Number} max 上边界值  57      *   58      * @return {Number} 返回不越界的数值  59      */  60     var getRange = function (i, mix, max) {  61         mix && (i = Math.max(i, mix));  62         max && (i = Math.min(i, max));  63         return i;  64     };  65   66     /**  67      * 判断给定的对象是否为数组  68      * @param {Object} source 要测试的对象  69      *  70      * @return {Boolean} 如果是数组返回true,否则返回false  71      */  72     var isArray = function (source) {  73         return '[object Array]' === Object.prototype.toString.call(source);  74     };  75   76     /**  77      * 返回item在source中的索引位置  78      * @param {Object} item 要测试的对象  79      * @param {Array} source 数组  80      *  81      * @return {Number} 如果在数组内,返回索引,否则返回-1  82      */  83     var indexOf = function(item, source){  84         var index = -1;  85         if(isArray(source)){  86             if (source.indexOf) {  87                 index = source.indexOf(item);  88             } else {  89                 for (var i = 0, m; m = source[i]; i++) {  90                     if (m === item) {  91                         index = i;  92                         break;  93                     }  94                 }  95             }  96         }          97         return index;  98     };  99  100     /** 101      *@exports MarkerClusterer as BMapLib.MarkerClusterer 102      */ 103     var MarkerClusterer =   104         /** 105          * MarkerClusterer 106          * @class 用来解决加载大量点要素到地图上产生覆盖现象的问题,并提高性能 107          * @constructor 108          * @param {Map} map 地图的一个实例。 109          * @param {Json Object} options 可选参数,可选项包括:<br /> 110          *    markers {Array<Marker>} 要聚合的标记数组<br /> 111          *    girdSize {Number} 聚合计算时网格的像素大小,默认60<br /> 112          *    maxZoom {Number} 最大的聚合级别,大于该级别就不进行相应的聚合<br /> 113          *    minClusterSize {Number} 最小的聚合数量,小于该数量的不能成为一个聚合,默认为2<br /> 114          *    isAverangeCenter {Boolean} 聚合点的落脚位置是否是所有聚合在内点的平均值,默认为否,落脚在聚合内的第一个点<br /> 115          *    styles {Array<IconStyle>} 自定义聚合后的图标风格,请参考TextIconOverlay类<br /> 116          */ 117         BMapLib.MarkerClusterer = function(map, options){ 118             if (!map){ 119                 return; 120             } 121             this._map = map; 122             this._markers = []; 123             this._clusters = []; 124              125             var opts = options || {}; 126             this._gridSize = opts["gridSize"] || 60; 127             this._maxZoom = opts["maxZoom"] || 18; 128             this._minClusterSize = opts["minClusterSize"] || 2;            129             this._isAverageCenter = false; 130             if (opts['isAverageCenter'] != undefined) { 131                 this._isAverageCenter = opts['isAverageCenter']; 132             }     133             this._styles = opts["styles"] || []; 134          135             var that = this; 136             this._map.addEventListener("zoomend",function(){ 137                 that._redraw();      138             }); 139      140             this._map.addEventListener("moveend",function(){ 141                  that._redraw();      142             }); 143     144             var mkrs = opts["markers"]; 145             isArray(mkrs) && this.addMarkers(mkrs); 146         }; 147  148     /** 149      * 添加要聚合的标记数组。 150      * @param {Array<Marker>} markers 要聚合的标记数组 151      * 152      * @return 无返回值。 153      */ 154     MarkerClusterer.prototype.addMarkers = function(markers){ 155         for(var i = 0, len = markers.length; i <len ; i++){ 156             this._pushMarkerTo(markers[i]); 157         } 158         this._createClusters();    159     }; 160  161     /** 162      * 把一个标记添加到要聚合的标记数组中 163      * @param {BMap.Marker} marker 要添加的标记 164      * 165      * @return 无返回值。 166      */ 167     MarkerClusterer.prototype._pushMarkerTo = function(marker){ 168         var index = indexOf(marker, this._markers); 169         if(index === -1){ 170             marker.isInCluster = false; 171             this._markers.push(marker);//Marker拖放后enableDragging不做变化,忽略 172         } 173     }; 174  175     /** 176      * 添加一个聚合的标记。 177      * @param {BMap.Marker} marker 要聚合的单个标记。 178      * @return 无返回值。 179      */ 180     MarkerClusterer.prototype.addMarker = function(marker) { 181         this._pushMarkerTo(marker); 182         this._createClusters(); 183     }; 184  185     /** 186      * 根据所给定的标记,创建聚合点,并遍历所有聚合点 187      * @return 无返回值 188      */ 189     MarkerClusterer.prototype._createClusters = function(){ 190         var mapBounds = this._map.getBounds(); 191         var extendedBounds = getExtendedBounds(this._map, mapBounds, this._gridSize); 192         for(var i = 0, marker; marker = this._markers[i]; i++){ 193             if(!marker.isInCluster && extendedBounds.containsPoint(marker.getPosition()) ){  194                 this._addToClosestCluster(marker); 195             } 196         }    197          198         var len = this._markers.length; 199         for (var i = 0; i < len; i++) { 200             if(this._clusters[i]){ 201                 this._clusters[i].render(); 202             } 203         } 204     }; 205  206     /** 207      * 根据标记的位置,把它添加到最近的聚合中 208      * @param {BMap.Marker} marker 要进行聚合的单个标记 209      * 210      * @return 无返回值。 211      */ 212     MarkerClusterer.prototype._addToClosestCluster = function (marker){ 213         var distance = 4000000; 214         var clusterToAddTo = null; 215         var position = marker.getPosition(); 216         for(var i = 0, cluster; cluster = this._clusters[i]; i++){ 217             var center = cluster.getCenter(); 218             if(center){ 219                 var d = this._map.getDistance(center, marker.getPosition()); 220                 if(d < distance){ 221                     distance = d; 222                     clusterToAddTo = cluster; 223                 } 224             } 225         } 226      227         if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)){ 228             clusterToAddTo.addMarker(marker); 229         } else { 230             var cluster = new Cluster(this); 231             cluster.addMarker(marker);             232             this._clusters.push(cluster); 233         }     234     }; 235  236     /** 237      * 清除上一次的聚合的结果 238      * @return 无返回值。 239      */ 240     MarkerClusterer.prototype._clearLastClusters = function(){ 241         for(var i = 0, cluster; cluster = this._clusters[i]; i++){             242             cluster.remove(); 243         } 244         this._clusters = [];//置空Cluster数组 245         this._removeMarkersFromCluster();//把Marker的cluster标记设为false 246     }; 247  248     /** 249      * 清除某个聚合中的所有标记 250      * @return 无返回值 251      */ 252     MarkerClusterer.prototype._removeMarkersFromCluster = function(){ 253         for(var i = 0, marker; marker = this._markers[i]; i++){ 254             marker.isInCluster = false; 255         } 256     }; 257     258     /** 259      * 把所有的标记从地图上清除 260      * @return 无返回值 261      */ 262     MarkerClusterer.prototype._removeMarkersFromMap = function(){ 263         for(var i = 0, marker; marker = this._markers[i]; i++){ 264             marker.isInCluster = false; 265             this._map.removeOverlay(marker);        266         } 267     }; 268  269     /** 270      * 删除单个标记 271      * @param {BMap.Marker} marker 需要被删除的marker 272      * 273      * @return {Boolean} 删除成功返回true,否则返回false 274      */ 275     MarkerClusterer.prototype._removeMarker = function(marker) { 276         var index = indexOf(marker, this._markers); 277         if (index === -1) { 278             return false; 279         } 280         this._map.removeOverlay(marker); 281         this._markers.splice(index, 1); 282         return true; 283     }; 284  285     /** 286      * 删除单个标记 287      * @param {BMap.Marker} marker 需要被删除的marker 288      * 289      * @return {Boolean} 删除成功返回true,否则返回false 290      */ 291     MarkerClusterer.prototype.removeMarker = function(marker) { 292         var success = this._removeMarker(marker); 293         if (success) { 294             this._clearLastClusters(); 295             this._createClusters(); 296         } 297         return success; 298     }; 299      300     /** 301      * 删除一组标记 302      * @param {Array<BMap.Marker>} markers 需要被删除的marker数组 303      * 304      * @return {Boolean} 删除成功返回true,否则返回false 305      */ 306     MarkerClusterer.prototype.removeMarkers = function(markers) { 307         var success = false; 308         for (var i = 0; i < markers.length; i++) { 309             var r = this._removeMarker(markers[i]); 310             success = success || r;  311         } 312  313         if (success) { 314             this._clearLastClusters(); 315             this._createClusters(); 316         } 317         return success; 318     }; 319  320     /** 321      * 从地图上彻底清除所有的标记 322      * @return 无返回值 323      */ 324     MarkerClusterer.prototype.clearMarkers = function() { 325         this._clearLastClusters(); 326         this._removeMarkersFromMap(); 327         this._markers = []; 328     }; 329  330     /** 331      * 重新生成,比如改变了属性等 332      * @return 无返回值 333      */ 334     MarkerClusterer.prototype._redraw = function () { 335         this._clearLastClusters(); 336         this._createClusters(); 337     }; 338  339     /** 340      * 获取网格大小 341      * @return {Number} 网格大小 342      */ 343     MarkerClusterer.prototype.getGridSize = function() { 344         return this._gridSize; 345     }; 346  347     /** 348      * 设置网格大小 349      * @param {Number} size 网格大小 350      * @return 无返回值 351      */ 352     MarkerClusterer.prototype.setGridSize = function(size) { 353         this._gridSize = size; 354         this._redraw(); 355     }; 356  357     /** 358      * 获取聚合的最大缩放级别。 359      * @return {Number} 聚合的最大缩放级别。 360      */ 361     MarkerClusterer.prototype.getMaxZoom = function() { 362         return this._maxZoom;        363     }; 364  365     /** 366      * 设置聚合的最大缩放级别 367      * @param {Number} maxZoom 聚合的最大缩放级别 368      * @return 无返回值 369      */ 370     MarkerClusterer.prototype.setMaxZoom = function(maxZoom) { 371         this._maxZoom = maxZoom; 372         this._redraw(); 373     }; 374  375     /** 376      * 获取聚合的样式风格集合 377      * @return {Array<IconStyle>} 聚合的样式风格集合 378      */ 379     MarkerClusterer.prototype.getStyles = function() { 380         return this._styles; 381     }; 382  383     /** 384      * 设置聚合的样式风格集合 385      * @param {Array<IconStyle>} styles 样式风格数组 386      * @return 无返回值 387      */ 388     MarkerClusterer.prototype.setStyles = function(styles) { 389         this._styles = styles; 390         this._redraw(); 391     }; 392  393     /** 394      * 获取单个聚合的最小数量。 395      * @return {Number} 单个聚合的最小数量。 396      */ 397     MarkerClusterer.prototype.getMinClusterSize = function() { 398         return this._minClusterSize; 399     }; 400  401     /** 402      * 设置单个聚合的最小数量。 403      * @param {Number} size 单个聚合的最小数量。 404      * @return 无返回值。 405      */ 406     MarkerClusterer.prototype.setMinClusterSize = function(size) { 407         this._minClusterSize = size; 408         this._redraw(); 409     }; 410  411     /** 412      * 获取单个聚合的落脚点是否是聚合内所有标记的平均中心。 413      * @return {Boolean} true或false。 414      */ 415     MarkerClusterer.prototype.isAverageCenter = function() { 416         return this._isAverageCenter; 417     }; 418  419     /** 420      * 获取聚合的Map实例。 421      * @return {Map} Map的示例。 422      */ 423     MarkerClusterer.prototype.getMap = function() { 424       return this._map; 425     }; 426  427     /** 428      * 获取所有的标记数组。 429      * @return {Array<Marker>} 标记数组。 430      */ 431     MarkerClusterer.prototype.getMarkers = function() { 432         return this._markers; 433     }; 434  435     /** 436      * 获取聚合的总数量。 437      * @return {Number} 聚合的总数量。 438      */ 439     MarkerClusterer.prototype.getClustersCount = function() { 440         var count = 0; 441         for(var i = 0, cluster; cluster = this._clusters[i]; i++){ 442             cluster.isReal() && count++;      443         } 444         return count; 445     }; 446  447     /** 448      * @ignore 449      * Cluster 450      * @class 表示一个聚合对象,该聚合,包含有N个标记,这N个标记组成的范围,并有予以显示在Map上的TextIconOverlay等。 451      * @constructor 452      * @param {MarkerClusterer} markerClusterer 一个标记聚合器示例。 453      */ 454     function Cluster(markerClusterer){ 455         this._markerClusterer = markerClusterer; 456         this._map = markerClusterer.getMap(); 457         this._minClusterSize = markerClusterer.getMinClusterSize(); 458         this._isAverageCenter = markerClusterer.isAverageCenter(); 459         this._center = null;//落脚位置 460         this._markers = [];//这个Cluster中所包含的markers 461         this._gridBounds = null;//以中心点为准,向四边扩大gridSize个像素的范围,也即网格范围 462         this._isReal = false; //真的是个聚合 463      464         this._clusterMarker = new BMapLib.TextIconOverlay(this._center, this._markers.length, {"styles":this._markerClusterer.getStyles()}); 465         //this._map.addOverlay(this._clusterMarker); 466     } 467     468     /** 469      * 向该聚合添加一个标记。 470      * @param {Marker} marker 要添加的标记。 471      * @return 无返回值。 472      */ 473     Cluster.prototype.addMarker = function(marker){ 474         if(this.isMarkerInCluster(marker)){ 475             return false; 476         }//也可用marker.isInCluster判断,外面判断OK,这里基本不会命中 477      478         if (!this._center){ 479             this._center = marker.getPosition(); 480             this.updateGridBounds();// 481         } else { 482             if(this._isAverageCenter){ 483                 var l = this._markers.length + 1; 484                 var lat = (this._center.lat * (l - 1) + marker.getPosition().lat) / l; 485                 var lng = (this._center.lng * (l - 1) + marker.getPosition().lng) / l; 486                 this._center = new BMap.Point(lng, lat); 487                 this.updateGridBounds(); 488             }//计算新的Center 489         } 490      491         marker.isInCluster = true; 492         this._markers.push(marker); 493      494 //        var len = this._markers.length; 495 //        if(len < this._minClusterSize ){      496 //            this._map.addOverlay(marker); 497 //            //this.updateClusterMarker(); 498 //            return true; 499 //        } else if (len === this._minClusterSize) { 500 //            for (var i = 0; i < len; i++) { 501 //                this._markers[i].getMap() && this._map.removeOverlay(this._markers[i]); 502 //            } 503 //             504 //        }  505 //        this._map.addOverlay(this._clusterMarker); 506 //        this._isReal = true; 507 //        this.updateClusterMarker(); 508 //        return true; 509     }; 510      511     /** 512      * 进行dom操作 513      * @return 无返回值 514      */ 515      Cluster.prototype.render = function(){ 516          var len = this._markers.length; 517            518          if (len < this._minClusterSize) { 519               for (var i = 0; i < len; i++) { 520                  this._map.addOverlay(this._markers[i]); 521              } 522          } else { 523              this._map.addOverlay(this._clusterMarker); 524              this._isReal = true; 525              this.updateClusterMarker(); 526          } 527      } 528      529     /** 530      * 判断一个标记是否在该聚合中。 531      * @param {Marker} marker 要判断的标记。 532      * @return {Boolean} true或false。 533      */ 534     Cluster.prototype.isMarkerInCluster= function(marker){ 535         if (this._markers.indexOf) { 536             return this._markers.indexOf(marker) != -1; 537         } else { 538             for (var i = 0, m; m = this._markers[i]; i++) { 539                 if (m === marker) { 540                     return true; 541                 } 542             } 543         } 544         return false; 545     }; 546  547     /** 548      * 判断一个标记是否在该聚合网格范围中。 549      * @param {Marker} marker 要判断的标记。 550      * @return {Boolean} true或false。 551      */ 552     Cluster.prototype.isMarkerInClusterBounds = function(marker) { 553         return this._gridBounds.containsPoint(marker.getPosition()); 554     }; 555      556     Cluster.prototype.isReal = function(marker) { 557         return this._isReal; 558     }; 559  560     /** 561      * 更新该聚合的网格范围。 562      * @return 无返回值。 563      */ 564     Cluster.prototype.updateGridBounds = function() { 565         var bounds = new BMap.Bounds(this._center, this._center); 566         this._gridBounds = getExtendedBounds(this._map, bounds, this._markerClusterer.getGridSize()); 567     }; 568  569     /** 570      * 更新该聚合的显示样式,也即TextIconOverlay。 571      * @return 无返回值。 572      */ 573     Cluster.prototype.updateClusterMarker = function () { 574         if (this._map.getZoom() > this._markerClusterer.getMaxZoom()) { 575             this._clusterMarker && this._map.removeOverlay(this._clusterMarker); 576             for (var i = 0, marker; marker = this._markers[i]; i++) { 577                 this._map.addOverlay(marker); 578             } 579             return; 580         } 581  582         if (this._markers.length < this._minClusterSize) { 583             this._clusterMarker.hide(); 584             return; 585         } 586  587         this._clusterMarker.setPosition(this._center); 588          589         this._clusterMarker.setText(this._markers.length); 590  591         var thatMap = this._map; 592         var thatBounds = this.getBounds(); 593         this._clusterMarker.addEventListener("click", function(event){ 594             thatMap.setViewport(thatBounds); 595         }); 596  597     }; 598  599     /** 600      * 删除该聚合。 601      * @return 无返回值。 602      */ 603     Cluster.prototype.remove = function(){ 604         for (var i = 0, m; m = this._markers[i]; i++) { 605                 this._markers[i].getMap() && this._map.removeOverlay(this._markers[i]); 606         }//清除散的标记点 607         this._map.removeOverlay(this._clusterMarker); 608         this._markers.length = 0; 609         delete this._markers; 610     } 611  612     /** 613      * 获取该聚合所包含的所有标记的最小外接矩形的范围。 614      * @return {BMap.Bounds} 计算出的范围。 615      */ 616     Cluster.prototype.getBounds = function() { 617         var bounds = new BMap.Bounds(this._center,this._center); 618         for (var i = 0, marker; marker = this._markers[i]; i++) { 619             bounds.extend(marker.getPosition()); 620         } 621         return bounds; 622     }; 623  624     /** 625      * 获取该聚合的落脚点。 626      * @return {BMap.Point} 该聚合的落脚点。 627      */ 628     Cluster.prototype.getCenter = function() { 629         return this._center; 630     }; 631  632 })();

被修改的地方为三处

第一:在第198行,MarkerClusterer.createClusters最后加入了以下代码

 var len = this._markers.length;  for (var i = 0; i < len; i++) {       if(this._clusters[i]){          this._clusters[i].render();       }   }

第二:在第494行注释了如下代码

//        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;

第三:在第511行,加入了新方法

/**      * 进行dom操作      * @return 无返回值      */      Cluster.prototype.render = function(){          var len = this._markers.length;                     if (len < this._minClusterSize) {               for (var i = 0; i < len; i++) {                  this._map.addOverlay(this._markers[i]);              }          } else {              this._map.addOverlay(this._clusterMarker);              this._isReal = true;              this.updateClusterMarker();          }      }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!