上一篇文章原本打算記錄一下本身作的東西,沒想到第一次獲得了大哥們的點贊特別開心(●'◡'●),接下來我也會多寫寫東西的。javascript
百度地圖大多數前端開發者都使用過,或者是高德地圖之類的第三插件。(要用好第三方插件,過程老是特別的痛苦┭┮﹏┭┮)不少人必定和我同樣遇到過須要實時監控數據點的需求,經過WebSocket、SSe甚至http定時獲取和後臺創建鏈接,當數據點發生變化時,後臺將數據推送過來,而後前端將地圖上的點更新。前端
(爲了方便 我這裏用定時器動態生成數據點模擬數據更新)vue
首先我對於以前思考的第一點,應該存粹是一個js的問題,只要把新獲取的數據與以前的數據進行比較篩選以後拿到咱們須要的數據就好了。不過在這以前咱們先解決另一個問題,若是我想把它作成 一個組件我怎麼才能知道點數據更新了呢,第一反應是用watch,不過用過的人應該都知道watch對於數組裏面存儲對象的這種數據沒法監控到對象內部數據的改變,若是的確須要監控只能開啓深度監聽deep: true,考慮到點的數據不少,這種監控會對性能形成很大的影響我選擇父容器拿到新的數據的時候主動告知組件更新數據,咱們看一下代碼。java
//父級
<mapBaidu :mapChange="isChange" :mapDateOld="mapDataTableOld" :mapDateNew="mapDataTable"></mapBaidu>
data () {
return {
isChange:false,//數據是否改變
}
},
//組件mapBaidu
watch: {
mapChange: {
handler() {
console.log("數據發現改變");
}
},
}複製代碼
咱們經過修改isChange的值來進入watch,而後作邏輯處理。git
(數據是模擬數據 咱們現看一下數據格式,方便看懂後面的話)github
{
id:index,//惟一標識
lng:120+Math.random(),//經度
name:`點${index}`,//名稱
lat:30+Math.random(),//維度
icon:Math.random()>0.5?"car-normal.png":"car-speeding.png"//圖標
}複製代碼
知道了數據變化以後咱們就應該開始對數據作處理了,首先咱們再來看一下咱們須要什麼數據!web
//比較新舊數組的不一樣
filterMap(oldPintList, newPintList) {
let delPointID = [], //相對於新獲取的點須要取消的點的id數組
otherPointList = [], //相對於新獲取的點不須要取消的點
addPointList = [], //相對於舊的數據點須要添加的點
newIDList = new Set(), //定義一個數組用來存新數據的id的集合
oldIDList = new Set(); //定義一個數組用來存舊數據的id的集合
newPintList.forEach(item => {
newIDList.add(item.id);
});
oldPintList.forEach(item => {
oldIDList.add(item.id);
});
oldPintList.forEach(item =>
newIDList.has(item.id)? otherPointList.push(item):delPointID.push(item.id)
);
newPintList.forEach(item =>{
if(!oldIDList.has(item.id)){
addPointList.push(item);
}
}
);
let changePonitList = this.filterChange(otherPointList, newPintList); //changePonitList:發生變化的點
return {
delPointID,
addPointList,
changePonitList
};
},
//獲取新數據中發生變化的點
filterChange(otherPointList, newPintList) {
var changePonitList = [];//變化了的點
otherPointList.forEach(point => {
let pList = newPintList.find(item => {
return item.id == point.id;
});//新獲取的數據中對應的那個點
if (pList.lng != point.lng || pList.lat != point.lat || pList.icon != point.icon ) {
changePonitList.push(pList);
}
});
return changePonitList;
}複製代碼
數據處理好了接下來就是怎麼處理這3個數組delPointID、addPointList、changePonitList首先咱們先獲取一下全部的覆蓋物overlaysList=this.map.getOverlays(),循環delPointID找到overlaysList對應的點經過百度地圖提供的removeOverlay方法,刪除對應的點。接下來循環changePonitList找到對應的點經過百度地圖提供的setIcon、setPosition方法從新設置經緯度和圖標。addPointList就不用多說了添加一個點到百度地圖,大部分人應該都會用,值得一提的是最好把每一個點的id、icon的信息保存在marker上,這樣獲取覆蓋物的時候咱們就能獲取到它,方便判斷。咱們看看代碼(●'◡'●)。api
let { delPointID, addPointList, changePonitList } =
this.filterMap(this.mapDateOld,this.mapDateNew);//獲取刪除點、新增點、修改點
this.delEditMarker(changePonitList,delPointID);//修改刪除點
addPointList.forEach(add=>{//添加點
this.addMarker(add);
})
//刪除點
delEditMarker(changePonitList,delPointID) {
let overlaysList;
if (this.pointAggregationType) {//開啓點聚合經過markerClusterer類獲取點
overlaysList = this.markerClusterer.getMarkers().slice(0);
} else {//未開啓點聚合獲取全部覆蓋物
overlaysList = this.map.getOverlays();
}
if (changePonitList.length > 0 || delPointID.length > 0) {//若是存在須要修改和刪除的點
overlaysList.forEach(item => {
//刪除點
if (delPointID.indexOf(item.id) > -1) {
if (this.pointAggregationType) {
this.markerClusterer.removeMarker(item);
} else {
this.map.removeOverlay(item);
}
}
//修改點
changePonitList.forEach(edit=>{
if(item.id == changePonitList[i].id){
let point = new BMap.Point(editPoint.lat, editPoint.lng);
let icon = new BMap.Icon(editPoint.icon, new BMap.Size(29, 29));
item.setIcon(icon);//從新設置圖標
item.setPosition(point);//從新設置經緯度
if (this.pointAggregationType) {
this.markerClusterer.setMarkers(item.id, item);
}
}
});
});
}
},
//添加點
addMarker(add) {
let point = new BMap.Point(add.lng, add.lat);
// console.log(point);
var icon = new BMap.Icon("/img/"+add.icon, new BMap.Size(29, 29)); //設置圖標大小
let marker = new BMap.Marker(point, {
icon: icon
});
marker.id = add.id;
marker.icon = add.icon;
let opts = {
position: point, // 指定文本標註所在的地理位置
offset: new BMap.Size(-10, 26) //設置文本偏移量
};
let label = new BMap.Label(add.name, opts); // 建立文本標註對象
label.setStyle({
color: "000",
fontSize: "12px",
height: "20px",
lineHeight: "20px",
border: "1px solid #000",
fontFamily: "微軟雅黑"
});
this.map.addOverlay(marker);//添加到地圖
marker.disableMassClear();
marker.setLabel(label);
if (this.pointAggregationType) {
this.markerClusterer.addMarker(marker);
}
},
複製代碼
首先咱們來看看官網點聚合的效果圖數組
圖中圖標上有數字的就是聚合點,其實就是再層級拉到很小的時候,把點聚合顯示,而後拉大以後又再顯示出來,能夠看的更加直觀。瀏覽器
首先通常來講加入點聚合以後,可讓地圖看上去更整潔。咱們仍是按以前的思路走,看看有什麼問題,問題基本出如今刪除點添加點和修改點的時候,不能再像之前同樣處理了,由於聚合點下的點是沒有渲染的經過獲取圖層沒法取到它們。那我改如何去更新刪除添加點呢,有點頭痛!!!┭┮﹏┭┮。假如咱們實現了這個效果,那麼咱們添加點或者刪除點是聚合點裏面的點,那麼聚合點上的數字就會發生變化。考慮到這一點我以爲必須去操做百度提供的點聚合的js才能作到了(MarkerClusterer_min.js)。內容我就不貼了,我直接放一個連接吧,東西比較多api.map.baidu.com/library/Mar….
咱們來看一下主要對咱們有用的東西
MarkerClusterer.prototype.getMarkers = function() {
return this._markers//全部的點
};
_map//傳進來Map的對象複製代碼
var indexOf = function(item, source) {
var index = -1;
if (isArray(source)) {
if (source.indexOf) {
index = source.indexOf(item)
} else {
for (var i = 0,
m; m = source[i]; i++) {
if (m === item) {
index = i;
break
}
}
}
}
return index
};
MarkerClusterer.prototype._removeMarker = function(marker) {
var index = indexOf(marker, this._markers);
if (index === -1) {
return false
}
tmplabel = marker.getLabel();
this._map.removeOverlay(marker);
marker.setLabel(tmplabel);
this._markers.splice(index, 1);
return true
};
MarkerClusterer.prototype.removeMarker = function(marker) {
var success = this._removeMarker(marker);
if (success) {
this._clearLastClusters();
this._createClusters()
}
return success
};複製代碼
MarkerClusterer.prototype._pushMarkerTo = function(marker) {
var index = indexOf(marker, this._markers);
if (index === -1) {
marker.isInCluster = false;
this._markers.push(marker)
}
};
MarkerClusterer.prototype.addMarker = function(marker) {
this._pushMarkerTo(marker);
this._createClusters()
};
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)
}
}
};複製代碼
MarkerClusterer.prototype.setMarkers = function(id,marker) {
this._markers.forEach(
(item)=>{
if(item.id==id){
item=marker;
}
}
)
};複製代碼
if (this.map == null) {//地圖還未初始化
return;
}
let { delPointID, addPointList, changePonitList } = this.filterMap(this.mapDateOld,this.mapDateNew);//獲取刪除點、新增點、修改點
if (this.markerClusterer == null && this.pointAggregationType) {//若是點擊後對象爲null,且開啓點聚合,則從新建立點聚合
this.markerClusterer = new BMapLib.MarkerClusterer(this.map, {markers: []});
}
this.delEditMarker(changePonitList,delPointID);//修改刪除點
addPointList.forEach(add=>{//添加點
this.addMarker(add);
})
//添加點
addMarker(add) {
let point = new BMap.Point(add.lng, add.lat);
var icon = new BMap.Icon("/img/"+add.icon, new BMap.Size(29, 29)); //設置圖標大小
let marker = new BMap.Marker(point, {
icon: icon
});
marker.id = add.id;
marker.icon = add.icon;
let opts = {
position: point, // 指定文本標註所在的地理位置
offset: new BMap.Size(-10, 26) //設置文本偏移量
};
let label = new BMap.Label(add.name, opts); // 建立文本標註對象
label.setStyle({
color: "000",
fontSize: "12px",
height: "20px",
lineHeight: "20px",
border: "1px solid #000",
fontFamily: "微軟雅黑"
});
marker.disableMassClear();
marker.setLabel(label);
if (this.pointAggregationType) {
this.markerClusterer.addMarker(marker);//添加到地圖覆蓋物體而且加入到點聚合的makers中
}else{
this.map.addOverlay(marker);//添加到地圖覆蓋物
}
},
//刪除點
delEditMarker(changePonitList,delPointID) {
let overlaysList;
if (this.pointAggregationType) {//開啓點聚合經過markerClusterer類獲取點
overlaysList = this.markerClusterer.getMarkers().slice(0);
} else {//未開啓點聚合獲取全部覆蓋物
overlaysList = this.map.getOverlays();
}
if (changePonitList.length > 0 || delPointID.length > 0) {//若是存在須要修改和刪除的點
overlaysList.forEach(item => {
//刪除點
if (delPointID.indexOf(item.id) > -1) {
if (this.pointAggregationType) {
this.markerClusterer.removeMarker(item);
} else {
this.map.removeOverlay(item);
}
}
//修改點
changePonitList.forEach(edit=>{
if(item.id == changePonitList[i].id){
let point = new BMap.Point(editPoint.lat, editPoint.lng);
let icon = new BMap.Icon(editPoint.icon, new BMap.Size(29, 29));
item.setIcon(icon);//從新設置圖標
item.setPosition(point);//從新設置經緯度
}
});
});
}
}
複製代碼
附上github連接github.com/github30789…
其餘文章傳送門: