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

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

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

相关推荐
水银嘻嘻21 分钟前
web 自动化之 Unittest 四大组件
运维·前端·自动化
(((φ(◎ロ◎;)φ)))牵丝戏安26 分钟前
根据输入的数据渲染柱形图
前端·css·css3·js
wuyijysx37 分钟前
JavaScript grammar
前端·javascript
溪饱鱼1 小时前
第6章: SEO与交互指标
服务器·前端·microsoft
咔_1 小时前
LinkedList详解(源码分析)
前端
逍遥德2 小时前
CSS可以继承的样式汇总
前端·css·ui
读心悦2 小时前
CSS3 选择器完全指南:从基础到高级的元素定位技术
前端·css·css3
_龙衣3 小时前
将 swagger 接口导入 apifox 查看及调试
前端·javascript·css·vue.js·css3
进取星辰4 小时前
25、Tailwind:魔法速记术——React 19 样式新思路
前端·react.js·前端框架