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

小程序地图组件相比于高德、百度等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
       })
  }
}

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

相关推荐
passerby606130 分钟前
完成前端时间处理的另一块版图
前端·github·web components
掘了37 分钟前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅40 分钟前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte2 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc