举一反三,小程序地图中如何优化渲染大量添加物!

小程序地图组件相比于高德、百度等WebApi,灵活度是要差一些的,而且移动端的性能参差不齐,和PC也是没法比的。但是优化的思路是大相径庭的,关于PC端地图海量点在不用点聚合情况下的优化我已经在上一篇文章中有了详细的说明,这篇文章我们就来说说小程序该怎么实现。

首先优化思路还是以下几点:

  • 切割数据数组,分组轮询
  • 根据地图事件轮询更新信息
  • 根据当前地图缩放大小判断是否显示区域、标签

相比于高德地图API,小程序的地图添加物主要是直接控制几个数组实现的,所以在实现的过程中我们要在合适的时机改变数组,防止频繁操作数组。

先看下小程序地图组件的使用

html 复制代码
<map
   show-location
   longitude="{{longitude}}"
   latitude="{{latitude}}"
   markers="{{markers}}"
   polygons="{{polygons}}"
   circles="{{circles}}"
   scale="{{scale}}"
   bindregionchange="regionchange"></map>

事件更新

首先我们要在地图视口发生变化的时候触发重新计算页面添加物的逻辑:

js 复制代码
  regionchange(e) {
    if(e.type == 'end'){
      // 通过防抖和地图信息比对,防止地图拖动时,触发多次的请求
      if (this.timer) clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        if (e.causedBy !== 'scale' && (e.detail.centerLocation.latitude !== this.data.latitude || e.detail.centerLocation.longitude !== this.data.longitude)) {
          this.currentScale = e.detail.scale
          this.setData({
            longitude: e.detail.centerLocation.longitude,
            latitude: e.detail.centerLocation.latitude
          }, () => {
            this.chunkLoad()
          })
        } else if (e.causedBy === 'scale' && e.detail.scale !== this.currentScale) {
          this.currentScale = e.detail.scale
          this.chunkLoad()
        }
      }, 300)
    }
  },

页面缩放比例和中心点变化的时候我们就会去更新页面信息。

数组切割

这块的处理逻辑和PC端没有区别,但是PC端我们使用了定时器来分批渲染,可以让页面慢慢渲染添加物,但是小程序是通过数组控制的添加物,我们要确保数组结果的准确性,让页面尽量少地重新渲染,所以就用一个缓存数组来暂存,最后再用setData一次性加入到地图中:

js 复制代码
// 切割方法
function chunkArray (chunkedArr, chunkSize) {
  const chunkedArr = []
  let i = 0
  while (i < arr.length) {
    chunkedArr.push(arr.slice(i, i + chunkSize))
    i += chunkSize
  }
  return chunkedArr
}

this.listChunk = chunkArray(list, 100)
js 复制代码
chunkLoad() {
  let that = this
  // 调用 getRegion 方法获取当前地图可见区域信息
  that.map.getRegion({
    success: function(res) {
      that.mapRegion = res
      that.markerCaches = []
      that.polygonCaches = []
      if (!that.mapRegion) return
      // 分块加载,防止同一帧内轮询次数过多
      for (let i = 0; i < that.listChunk.length; i++) {
        setTimeout(() => {
          that.drawMap(that.listChunk, i, 'site')
        }, i * 100)
      }
    }
  })
}

然后我们再看看加载添加物的方法:

js 复制代码
function drawMap(list, chunkIndex) {
  for (let index = 0; index < list[chunkIndex].length; index++) {
       const item = list[chunkIndex][index]
       const { lat, lon } = park || {}
       if (!lat || !lon) continue
       const contains = contains({longitude: lon, latitude: lat})
       // 判断当前marker在视口内时创建标签与区域
       if (contains) {
         const marker = {...}
         const polygon = {...}
         this.markerCache.push(marker)
         this.polygonCaches.push(polygon)
       }
    	 this.setData({
         markers: this.markerCache,
         polygons: this.polygonCaches
       })
  }
}
// 通过经纬度比对判断当前点是否在视野范围内
function contains(point) {
    const { longitude, latitude } = point
    const area = this.mapRegion
    return area.northeast.longitude > longitude && area.southwest.longitude < longitude && area.northeast.latitude > latitude && area.southwest.latitude < latitude
}

缩放优化

最后一步就是优化显示了,还是之前文章说到的当缩小到一定程度,地图上上千个点堆叠在一起,本身已经没有了意义,所以还需要根据缩放信息去判断页面上的信息是否应该展示或者说换一种方式展示。

我们继续优化drawMap方法:

js 复制代码
function drawMap(list, chunkIndex) {
  const zoom = this.currentScale;
  for (let index = 0; index < list[chunkIndex].length; index++) {
       ...
       if (contains) {
         let marker = null
         if (zoom <= 13) {
           // 缩小到一定程度,简化页面标签显示,可以简化为一个圆点
           marker = {...}
         } else {
           // 正常显示marker
           marker = {...}
         }
         this.markerCache.push(marker)
         // 根据当前地图缩放大小判断是否显示区域信息
         if (zoom <= 14) continue
         const polygon = {...}
         this.polygonCaches.push(polygon)
       }
    	 this.setData({
         markers: this.markerCache,
         polygons: this.polygonCaches
       })
  }
}

目前为止,我们已经实现了小程序地图组件添加物的动态渲染,当然不同机型和不同数据量使用体验肯定是有差异的,只是目前在我的项目里面够用了,如果还有更好的优化方案欢迎评论区交流。

相关推荐
四喜花露水16 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy26 分钟前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
瑶琴AI前端1 小时前
uniapp实现H5和微信小程序获取当前位置(腾讯地图)
微信小程序·小程序·uni-app
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust1 小时前
css:基础
前端·css
帅帅哥的兜兜1 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
yi碗汤园1 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称1 小时前
购物车-多元素组合动画css
前端·css
编程一生2 小时前
回调数据丢了?
运维·服务器·前端
丶21362 小时前
【鉴权】深入了解 Cookie:Web 开发中的客户端存储小数据
前端·安全·web