地图瓦片/ Leaflet/自定义图层WMSLayer,小程序都不能用?来试试这个方法
发布于 1 年前 作者 nayao 2083 次浏览 来自 分享

需求

最近项目甲方想把PC端的地图线路绘制在手机上,并且还要在小程序上,听得我心里一惊,那么多线,那么多点符号,我该如何画啊,小程序最大setData也有1M的限制。但是需求来了就得想办法解决。

寻找方法

1、小程序方法polyline+marker(适用普通的点位渲染)

  • 小程序文档翻了翻,发现map组件文档有个 “聚合能力” 我似乎看见了新大陆,觉得肯定可以满足,经过一番研究,还是不能满足,因为这种方法只能用polyline来画线,而点或符号用marker来画,这种方法数据要处理大多了,因为我的项目线多,符号也多还不同形状的符号,PC端的显示是使用瓦片来渲染,没有分那么多符号和点位,这个方法以失败告终。有兴趣可以看下这个博客写的内容和我这里讲的差不多:微信小程序添加外部地图服务数据

2、自定义图层WMSLayer

  • 上面方法不行,于是我找了gis,跟他讨论了我这个需求,看看有没有办法可以满足我的需求,他们就给我推荐了自定义图层WMSLayer,他说PC端就是用这种方式实现,导入一份数据就可以了。我就说好的,我自己回去研究了一番,发现是需要引入GL的包,但是小程序不支持dom操作,和普通web页面还是有区别,于是我就放弃了该方法。

3、Leaflet插件

  • 这个方法也是gis那边介绍的一个插件库,我寻找了很多遍,发现没有支持小程序的插件库,只是支持web网页开发,还是无法使用到小程序中。传送门leaflet地址

4、小程序个性化图层

我使用的方法

  • 思来索去既然瓦片是图,那能不能让gis那边直接返回一张图片呢?我这边就贴图就行?因为小程序刚好有个自定义图片图层可以跟着地图变大变小
  • 感觉这个方法挺好的,联想了加入是一张张瓦片我也可以对准位置贴上去,连在一起就是我想要的效果了。于是找了gis那边的同事,发现他们有这种方法可以获取图片。addGroundOverlay文档地址

思路

  • 先看下addGroundOverlay的参数

    单独一个参数抽出来

  • 由图可见,有一个很重要的参数bounds这个参数,这个参数就是获取地图的对角点,用来确定当前地图视野范围,有了这个参数,我们就叫gis那边生成一张图片,然后粘贴到我们小程序的地图上面就完成了渲染。这里需要注意几点:

    • gis那边生成的图片需要几个参数,

      • a、需要对角点即bounds一样的参数,可以通过小程序提供的MapContext.getRegion获取当前地图的视野范围
      • b、需要获取你当前手机全屏屏幕宽高(windowWidth这个),用这个宽高传给gis那边生成图片的宽高
      • c、使用地图map组件提供的方法bindregionchange来监听,当前缩放或者中心点移动,然后去请求最新视野的图片粘贴上去
      • d、这里有个不好的问题就是用MapContext.updateGroundOverlay方法,更新上一张的贴图会出现闪动问题(即更新最新的图片会发生显示原来图片位置、然后隐藏才显示最新的图片位置),为了解决这个问题,我使用了每次变动位置请求最新图片,都用增加方法MapContext.addGroundOverlay去添加贴图到地图,然后把旧的贴图全部删除,为了效果看起来像懒加载,等加载完最新的图片在去删除旧的图片,这样就不会出现闪动的问题
        核心代码如下:
onReady: function (options) {
   this.MapContext = wx.createMapContext('mapId', this)
   this.getSystemInfo = wx.getSystemInfo().then(res => {
     this.getSystemInfo = res
   })
   this.indexId = 1
 },
 bindregionchange: function (e) {
   if (e.type === 'end') {
     const northeast = e.detail.region.northeast
     const southwest = e.detail.region.southwest
     if (mapTimer) clearTimeout(mapTimer)
     mapTimer = setTimeout(()=> {
       this.updataMap(southwest, northeast)
     }, 100)
   }
 },
 updataMap(southwest, northeast) {
   const northeast1 = {
     longitude: CoordTransformUtil.GCJ02ToWGS84(northeast.longitude, northeast.latitude)[0],
     latitude: CoordTransformUtil.GCJ02ToWGS84(northeast.longitude, northeast.latitude)[1]
   }
   const southwest1 = {
     longitude: CoordTransformUtil.GCJ02ToWGS84(southwest.longitude, southwest.latitude)[0],
     latitude: CoordTransformUtil.GCJ02ToWGS84(southwest.longitude, southwest.latitude)[1]
   }
   overlayId.push(this.indexId)
   this.indexId = this.indexId + 1
   this.MapContext.addGroundOverlay({
     id: this.indexId,
     src: `https://xxx/export?bbox=${northeast1.longitude},${northeast1.latitude},${southwest1.longitude},${southwest1.latitude}&bboxSR=4490&layers=&layerDefs=&size=${this.getSystemInfo.windowWidth},${this.getSystemInfo.windowHeight}`,
     bounds: {
       southwest: southwest,
       northeast: northeast
     },
     success: async (res) => {
       // 由于使用updata图层会出现每次闪图渲染问题,所以每次获取图层都是新增的,故这里需要把每次渲染的图层删除,只留最后一次
       if (mapTimer2) clearTimeout(mapTimer2)
       mapTimer2 = setTimeout(async() => {
         await Promise.all(overlayId.map(async (item) => {
           await this.MapContext.removeGroundOverlay({ id: item });
           overlayId = overlayId.filter(fil => fil != item)
         }));
       }, 500)
     },
     fail: (err) => {
       console.error(err, 'fail...addGroundOverlay')
     }
   })
 }

总结

抱歉了,其实我这是不讲武德,把技术点给gis那边处理了,我这边只需要把他们处理好的图片粘贴上去就好了,经过验证该方法确实可行的哦

解决问题才是王道
代码片段:https://developers.weixin.qq.com/s/taAR41mz7GHT

1 回复

leaflet没有微信小程序版本,那就帮它搞个https://gitee.com/zz2022com/DTPlugin.git😄

回到顶部