闲话
上一篇文章本来打算记录一下自己做的东西,没想到第一次得到了大哥们的点赞特别开心(●'◡'●),接下来我也会多写写东西的。
一.需求和思路
百度地图大多数前端开发者都使用过,或者是高德地图之类的第三插件。(要用好第三方插件,过程总是特别的痛苦┭┮﹏┭┮)很多人一定和我一样遇到过需要实时监控数据点的需求,通过WebSocket、SSe甚至http定时获取和后台建立连接,当数据点发生变化时,后台将数据推送过来,然后前端将地图上的点更新。
那么地图更新的时候会出现那些问题呢?
- 每次更新数据点,就算那个数据点经纬度和图标都没有变化,也会出现闪烁。
- 数据量过大会导致百度地图渲染很慢,出现浏览器卡顿甚至卡死的问题。
- 数据量过多在层级拉小的时候会因为点过于密集导致看不清楚。
思考一下。。。
- 如果可以做到每次只更新改变经纬度或者其它信息了的数据,这样就能避免大面积闪烁问题。
- 如果每次更新不用重新画点只改变经纬度和图标,应该能够提高一些性能。
- 百度地图有一个点聚合的功能,应该可以解决这个问题。
开始动手!
有了想法,那就可以开始动手去实现了!(●'◡'●),其实之前对于百度地图api不是特别的熟悉,只是会简单的使用,这次为了这个优化特地去补习了一下,可能有些地方还是考虑好,欢迎您能评论和我交流交流*^____^*。二.思路实现
如何监听数据变化?
(为了方便 我这里用定时器动态生成数据点模拟数据更新)
首先我对于之前思考的第一点,应该存粹是一个js的问题,只要把新获取的数据与之前的数据进行比较筛选之后拿到我们需要的数据就行了。不过在这之前我们先解决另外一个问题,如果我想把它做成 一个组件我怎么才能知道点数据更新了呢,第一反应是用watch,不过用过的人应该都知道watch对于数组里面存储对象的这种数据无法监控到对象内部数据的改变,如果的确需要监控只能开启深度监听deep: true,考虑到点的数据很多,这种监控会对性能造成很大的影响我选择父容器拿到新的数据的时候主动告知组件更新数据,我们看一下代码。
//父级
<mapBaidu :mapChange="isChange" :mapDateOld="mapDataTableOld" :mapDateNew="mapDataTable"></mapBaidu>
data () {
return {
isChange:false,//数据是否改变
}
},
//组件mapBaidu
watch: {
mapChange: {
handler() {
console.log("数据发现改变");
}
},
}复制代码
我们通过修改isChange的值来进入watch,然后做逻辑处理。
下一步处理数据!
(数据是模拟数据 我们现看一下数据格式,方便看懂后面的话)
{
id:index,//唯一标识
lng:120+Math.random(),//经度
name:`点${index}`,//名称
lat:30+Math.random(),//维度
icon:Math.random()>0.5?"car-normal.png":"car-speeding.png"//图标
}复制代码
知道了数据变化之后我们就应该开始对数据做处理了,首先我们再来看一下我们需要什么数据!
- 旧数据中应该删除的点
- 新数据中应该添加的点
- 旧数据中应该修改经纬度或者图标之类信息的点
//比较新旧数组的不同
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)
);