leaflet + vue 海量点位批量显示,根据不同缩放级别显示不同数量的点位
最近在项目中遇到一个需求,以前点位是根据区县进行分组聚合式显示的,但是交互不够友好直接,需要不断地点开才行,因此产品要求把所有点位平铺显示,不要分组,根据不同的缩放级别显示不同数量的点位。咨询了同事,给出这样一个方案:
定义一个新数组,循环所有点位,先把点位的经纬度转换成屏幕的坐标(用到 leaflet 的 latLngToContainerPoint 方法),然后计算该点位和新数组里所有点的距离(勾股定理),大于某个距离(比如50px)就push进新数组,然后在地图上显示新数组的点位,这样点位就不会全部密密麻麻的显示在地图上了,而是每个点之间都有一定的距离。
因为循环次数比较多,为了提高渲染速度,做了以下处理:
1. 首先增加一个判断条件,只渲染地图可视范围内的点位,不在可视范围内的点直接退出循环
2. 尽量不要在循环体中去访问 this,很耗费时间,把所有可以保存成变量的都放在外面定义好,直接拿去循环里用
效果如下:
核心代码如下:
1 createPointsByZoom(key) { 2 // 放大到 14 级别以上,展示所有的点位 3 if (this.map.getZoom() > 14) { 4 this.staData.push(...this.points[key]) 5 return 6 } 7 8 const TARGET_DISTANCE = 50 // 两点之间的距离:50px 9 const zoom = this.map.getZoom() 10 const newList = [this.points[0]] // this.points 是指所有点位,默认放入一个点位 11 const bounds = this.map.getBounds() // 地图边界 12 const lat1 = bounds._southWest.lat 13 const lat2 = bounds._northEast.lat 14 const lon1 = bounds._southWest.lng 15 const lon2 = bounds._northEast.lng 16 17 this.points.map(item => { 18 const { latitude, longitude } = item 19 20 // 只画可视范围内的 21 if (!this.isInView(lat1, lat2, lon1, lon2, latitude, longitude)) { 22 return 23 } 24 25 const latLng1 = L.latLng([latitude, longitude]) 26 const location1 = this.map.latLngToContainerPoint(latLng1, zoom) // { x: 123, y: 123 } 27 const { x, y } = location1 28 29 /** 30 * 比较每一个点和容器中的点的距离 31 * latLngToContainerPoint: 将经纬度转换为相对地图容器的屏幕坐标 32 */ 33 const moreThanStandardDistance = newList.every(data => { 34 const latLng2 = L.latLng([data.latitude, data.longitude]) 35 const location2 = this.map.latLngToContainerPoint(latLng2, zoom) 36 // 计算两点之间的屏幕距离, 勾股定理 37 const distanceX = Math.abs(x - location2.x) 38 const distanceY = Math.abs(y - location2.y) 39 const distance = Math.pow(distanceX, 2) + Math.pow(distanceY, 2) 40 return distance > Math.pow(TARGET_DISTANCE, 2) 41 }) 42 43 if (moreThanStandardDistance) { 44 newList.push(item) 45 } 46 }) 47 48 this.staData.push(...newList) 49 }
生活是痛苦的白天,死亡是凉爽的夜晚。