百度地圖js lite api 支援點聚合
阿新 • • 發佈:2018-11-07
百度地圖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); 18let 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 };
這樣就可以了