1. 程式人生 > >百度地圖js lite api 支援點聚合

百度地圖js lite api 支援點聚合

百度地圖lite api 是專門為h5 繪製海量點設計的,但是偏偏忽略掉了點聚合的需求,所以需要自己動手,做一次二次改造。

 

我們知道點聚合需要引入開源庫:

MarkerClusterer:  http://api.map.baidu.com/library/MarkerClusterer/1.2/src/MarkerClusterer.js

TextIconOverlay: http://api.map.baidu.com/library/TextIconOverlay/1.2/src/TextIconOverlay.js

 

由於是開源庫,我們可以直接把程式碼擼下來儲存直接放到自己的業務裡使用

我們在  MarkerClusterer  addMarkers的時候瀏覽器會報錯,

是因為lite api中的map物件及bounds物件缺乏兩個方法:

map.getDistance  及   bounds.containsPoint

getDistance方法是計算兩個點之間的直線距離,返回數值為米,這個方法網上就有

 1 const EARTH_RADIUS = 6378137.0;
 2 const {PI} = Math;
 3 
 4 function getRad(d){
 5     return d*PI/180.0;
 6
} 7 8 function getDistance(start,end){ 9 let lat1 = +start.lat; 10 let lat2 = +end.lat; 11 let lng1 = +start.lng; 12 let lng2 = +end.lng; 13 if(lat1==lat2 && lng1 == lng2){ 14 return 0; 15 } 16 let f = getRad((lat1 + lat2)/2); 17 let g = getRad((lat1 - lat2)/2); 18
let l = getRad((lng1 - lng2)/2); 19 let sg = Math.sin(g); 20 let sl = Math.sin(l); 21 let sf = Math.sin(f); 22 let s,c,w,r,d,h1,h2; 23 let a = EARTH_RADIUS; 24 let fl = 1/298.257; 25 sg = sg*sg; 26 sl = sl*sl; 27 sf = sf*sf; 28 s = sg*(1-sl) + (1-sf)*sl; 29 c = (1-sg)*(1-sl) + sf*sl; 30 w = Math.atan(Math.sqrt(s/c)); 31 r = Math.sqrt(s*c)/w; 32 d = 2*w*a; 33 h1 = (3*r -1)/2/c; 34 h2 = (3*r +1)/2/s; 35 return d*(1 + fl*(h1*sf*(1-sg) - h2*(1-sf)*sg)); 36 }

我們把這個方法賦到map物件上

 1 var MarkerClusterer = function (map, options) {
 2     if (!map) {
 3         return;
 4     }
 5     map.getDistance = getDistance;  // 這裡
 6     this._map = map;
 7     this._markers = [];
 8     this._clusters = [];
 9 
10     var opts = options || {};
11     this._gridSize = opts["gridSize"] || 60;
12     this._maxZoom = opts["maxZoom"] || 18;
13     this._minClusterSize = opts["minClusterSize"] || 2;
14     this._isAverageCenter = false;
15     if (opts['isAverageCenter'] != undefined) {
16         this._isAverageCenter = opts['isAverageCenter'];
17     }
18     this._styles = opts["styles"] || [];
19 
20     var that = this;
21     this._map.addEventListener("zoomend", function () {
22         that._redraw();
23     });
24 
25     this._map.addEventListener("moveend", function () {
26         that._redraw();
27     });
28 
29     var mkrs = opts["markers"];
30     isArray(mkrs) && this.addMarkers(mkrs);
31 };

map物件就補齊了

containsPoint 是計算點是否在bounds給定的區域中,這個更簡單

 1 var getExtendedBounds = function (map, bounds, gridSize) {
 2     bounds = cutBoundsInRange(bounds);
 3     var pixelNE = map.pointToPixel(bounds.getNorthEast());
 4     var pixelSW = map.pointToPixel(bounds.getSouthWest());
 5     pixelNE.x += gridSize;
 6     pixelNE.y -= gridSize;
 7     pixelSW.x -= gridSize;
 8     pixelSW.y += gridSize;
 9     var newNE = map.pixelToPoint(pixelNE);
10     var newSW = map.pixelToPoint(pixelSW);
11     let nb =  new BMap.Bounds(newSW, newNE);
12     // 寫在這裡
13     nb.containsPoint = function(point){
14         var lat = point.lat;
15         var lng = point.lng;
16         if(!point || !point.lat || !point.lng){
17             return false;
18         } else {
19             return lat>this._swLat && lat < this._neLat && lng<this._neLng && lng>this._swLng;
20         }
21     }
22     return nb;
23 };

至此MarkerClusterer 改造完畢

 

然後是改造TextIconOverlay

由於lite api 返回的MarkerPane

 1 TextIconOverlay.prototype.initialize = function (map) {
 2             this._map = map;
 3 
 4             this._domElement = document.createElement('div');
 5             this._updateCss();
 6             this._updateText();
 7             this._updatePosition();
 8 
 9             this._bind();
10  // 將markerMouseTarget 替換成markerPane
11 this._map.getPanes().markerPane.appendChild(this._domElement);
12             return this._domElement;
13         };

這樣就可以了