上一篇文章原本打算记录一下本身作的东西,没想到第一次获得了大哥们的点赞特别开心(●'◡'●),接下来我也会多写写东西的。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…
其余文章传送门: