先上效果:

缘起

使用微信小程序做地图相关功能的时候,有个需求是需要接入自己发布的地图服务。查看微信小程序地图组件文档,发现它对地图相关的支持很少,只有一些基础功能,比如添加点、线、面、气泡和一些常规的地图事件监听,并没有添加地图服务相关的支持。

不过有了需求,也要想办法解决呀。

图层查询

既然小程序不能直接添加地图服务,那就把图层数据查出来,然后通过添加点线面方式添加到地图,具体要怎么实现呢?

首先想到的是通过图层查询接口把所有数据查出来。

但是既然数据是按图层发布的,一般数据量都比较大,把所有数据查询出来,一次性添加过多的数据到地图,地图组件会受不了从而变的卡顿,另外微信小程序单次setData()的数据不能超过1024kB,因此这种方案就不可取了。

矢量瓦片

既然一次性请求数据量太大,是不是可以分批次请求呢?于是就想到了矢量瓦片。

矢量瓦片对于做GIS的人来说,大家都很熟悉了,这也是目前各种GIS产品对大数据量地图展示所采用的主要方式。

但是,我们如何让不支持添加外部图层的小程序地图组件支持矢量瓦片呢?

查看地图组件相关文档,会看到其中有个regionchange事件,该事件是在地图视野改变,也就是拖动、缩放地图时触发,它会返回当前中心点、缩放级别、地图范围等信息。

获取瓦片

接下来就是如何根据这些参数获取到矢量瓦片了。

假设,地图切图的原点是(originX,originY),地图的瓦片大小是tileSize,地图屏幕上1像素代表的实际距离是resolution。计算坐标点(x,y)所在的瓦片的行列号的公式是:

col = floor((x0 - x)/( tileSize*resolution))
row = floor((y0 - y)/( tileSize*resolution))

这个公式应该不难理解,简单点说就是,先算出一个瓦片所包含的实际长度LtileSize,然后再算出此时屏幕上的地理坐标点离瓦片切图的起始点间的实际距离LrealSize,然后用实际距离除以一个瓦片的实际长度,即可得此时的瓦片行列号:LrealSize/LtileSize

具体代码如下:

getTileXY: function (lon, lat, level) {
let originX = -180; //坐标系原点的x的值,
let originY = 90; //坐标系原点的y的值
//根据你自己对应的切片方案改,这个就是其分辨率resolution
let resolution = [1.40625, 0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625,
0.010986328125, 0.0054931640625, 0.00274658203125, 0.001373291015625, 0.0006866455078125, 0.0003433227539062,
0.0001716613769531, 0.0000858306884766, 0.0000429153442383, 0.0000214576721191, 0.0000107288360596,
0.0000053644180298, 0.0000026822090149, 0.0000013411045074, 0.0000006705522537, 0.0000003352761269
] let tileSize = 256 //这个值表示的是每张切片的大小,一般都是256
let coef = resolution[level] * tileSize;
let x = Math.floor((lon - originX) / coef); // 向下取整,丢弃小数部分
let y = Math.floor((originY - lat) / coef); // 向下取整,丢弃小数部分
let tmsY = Math.pow(2, (level - 1)) - y - 1;
return {
x: x,
y: y,
z: level - 1,
tmsY: tmsY
}
},

这里可以看到我返回的数据中有一个y值,还有一个tmsY,这是因为WMTSTMS两种方式调用切片时,传入的y值是不同的,不过两者之间是有可以转换的,也就是tmsY = Math.pow(2, (level - 1)) - y - 1WMTS用的是这里返回的y,TMS用的是这里返回 的tmsY

参考链接:

WebGIS前端地图显示之根据地理范围换算出瓦片行列号的原理(核心)

Slippy_map_tilenames

TMS和WMTS大概对比

接下来我们只需根据当前地图可视范围的最大、最小坐标以及地图层级,即可获取包含当前地图可视范围的瓦片的编号。

由于微信小程序地图组件使用的是国测局加密坐标,而我发布的地图服务数据为wgs84坐标,因此这里在获取切片编号时需要用坐标转换方法将国测局坐标转成wgs84坐标,坐标纠偏方法可参考leaflet中如何优雅的解决百度、高德地图的偏移问题

getXYZList: function (region, level) {
// 坐标转换
var newsouthwest = appcoord.gcj02_To_gps84(region.southwest.longitude, region.southwest.latitude);
var northeastwest = appcoord.gcj02_To_gps84(region.northeast.longitude, region.northeast.latitude);
// 获取瓦片编号
var xyzInfo1 = this.getTileXY(newsouthwest.lng, northeastwest.lat, level)
var xyzInfo2 = this.getTileXY(northeastwest.lng, newsouthwest.lat, level)
var z = level - 1
for (var x = xyzInfo1.x; x <= xyzInfo2.x; x++) {
for (var y = xyzInfo1.y; y <= xyzInfo2.y; y++) {
this.getGeoJson(x, y, z)
}
}
},

然后通过wx.request传入请求地址以及x、y、z参数,即可获取到对应矢量切片的geojson格式数据

getGeoJson: function (x, y, z) {
const v = this
wx.request({
url: "http://127.0.0.1:7000/geoserver/gwc/service/wmts/rest/test:test/EPSG:4326/EPSG:4326:" +
z + "/" + y + "/" + x + "?format=application/json;type=geojson",
method: 'get',
success(res) {
var tileId = 'tile-' + x + '-' + y + '-' + z
tileData[tileId] = {
tileId: tileId,
features: []
}
if(res.statusCode === 200){
tileData[tileId].features = res.data.features
}
v.addFeatures(tileId)
}
})
},

注意,这里我是用geoserver发布的矢量瓦片,在调用过程中发现个问题,其中一个点图层瓦片返回的数据中,各个瓦片总有很多重复数据,经检查测试发现,这是由于发布该图层(点图层)时使用的样式为一张大小为40x88的图片点样,这就导致切图时整体向外缓冲了不少的像素值,所以,如果geoserver发布的图层是用于矢量切片调用,最好将点图层样式设置为一个像素大小的像素点,这样可以有效减少瓦片数据冗余

添加数据

最后再通过微信小程序地图组件中添加点线面的方法把获取切片数据添加到地图即可

addFeatures: function (tileId) {
var polylines = this.data.polylines
var markers = this.data.markers
tileData[tileId].features.forEach(feature => {
if (feature.geometry.type === 'LineString') {
polylines.push(this.getPolyline(feature.geometry.coordinates, tileId))
} else if (feature.geometry.type === 'Point') {
markers.push(this.getMarker(feature.geometry.coordinates, tileId))
}
});
this.setData({
polylines: polylines,
markers: markers
})
},

存在问题

至此,微信小程序添加矢量瓦片数据已经完成,基本能满足浏览外部矢量图层的需求,但是,这里还是有一些不足的地方

  1. 需要发布geojson格式矢量瓦片图层
  2. 地图拖动时图层会闪一下,这是小程序重新往地图上绘制点线面图层引起的
  3. 在小比例尺瓦片返回数据量较大时可能会有卡顿现象(可以通过限定最小比例尺优化)
  4. 图层配图效果受小程序地图点线面样式限制

虽然该解决方案存在一些问题,但是鉴于微信小程序地图组件的限制,并且确时又有添加图层的需求,此方案还是可取的。

总结

  1. 微信小程序地图组件不支持添加外部图层服务
  2. 通过发布geojson格式矢量瓦片服务,然后按当前可视范围获取geojson格式瓦片数据
  3. 通过小程序地图组件的regionchange事件监听地图拖动、缩放,可以获取到当前中心点、缩放级别、地图范围
  4. 根据缩放级别、地图范围可以获取到当前可视范围的瓦片编号
  5. 请求瓦片数据,通过微信小程序地图组件中添加点线面的方法把切片数据添加到地图

代码地址

代码地址:http://gisarmory.xyz/blog/index.html?source=WechatVectorTile


原文地址:http://gisarmory.xyz/blog/index.html?blog=WechatVectorTile

欢迎关注《GIS兵器库

本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名《GIS兵器库》(包含链接:  http://gisarmory.xyz/blog/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

微信小程序添加外部地图服务数据的更多相关文章

  1. 微信小程序-基于高德地图API实现天气组件(动态效果)

    微信小程序-基于高德地图API实现天气组件(动态效果) ​ 在社区翻腾了许久,没有找到合适的天气插件.迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用.现在分享到互联网社区中,帮助后续有 ...

  2. 微信小程序添加悬浮在线客服会话按钮

    微信为小程序提供客服消息能力,小程序用户可以方便快捷地与小程序服务提供方进行沟通,并且已经做成了组件的形式,直接就可以调用.客服会话按钮,用于在页面上显示一个客服会话按钮,用户点击该按钮后会进入客服会 ...

  3. 微信小程序个人/企业开放服务类目一览表

    微信小程序个人/企业开放服务类目一览表   微信小程序个人开放服务类目表 服务类目 类目分类一 类目分类二 引导描述 出行与交通 代驾 / / 生活服务 家政.丽人.摄影/扩印.婚庆服务.环保回收/废 ...

  4. 图解微信小程序---添加tabBar底部菜单,添加已做好轮播图操作

    图解微信小程序---添加tabBar底部菜单,添加已做好轮播图操作 什么是tabBar? 顶部或者底部tab栏如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以 ...

  5. 为苹果ATS和微信小程序搭建 Nginx + HTTPS 服务

    昨天测试开发微信小程序,才发现微信也要求用HTTPS加密数据,想来是由于之前苹果的ATS审核政策的缘故吧,微信想在苹果上开放小程序必然也只能要求开发者必须使用HTTPS了,于是在服务器上测试安装Ngi ...

  6. 微信-小程序-开发文档-服务端-模板消息:templateMessage.getTemplateList

    ylbtech-微信-小程序-开发文档-服务端-模板消息:templateMessage.getTemplateList 1.返回顶部 1. templateMessage.getTemplateLi ...

  7. 微信-小程序-开发文档-服务端-模板消息:templateMessage.getTemplateLibraryById

    ylbtech-微信-小程序-开发文档-服务端-模板消息:templateMessage.getTemplateLibraryById 1.返回顶部 1. templateMessage.getTem ...

  8. 微信-小程序-开发文档-服务端-模板消息:templateMessage.addTemplate

    ylbtech-微信-小程序-开发文档-服务端-模板消息:templateMessage.addTemplate 1.返回顶部 1. templateMessage.addTemplate 本接口应在 ...

  9. 微信小程序腾讯地图SDK使用方法

    一.本篇文章主要知识点有以下几种: 1.授权当前位置 2.map组件的使用 3.腾讯地图逆地址解析 4.坐标系的转化 二.效果如下: 三.WXML代码 <map id="map&quo ...

随机推荐

  1. 痞子衡嵌入式:MCUXpresso IDE下将应用程序RW段分散链接的几种方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下将应用程序RW段分散链接的几种方法. 早期的 MCU 芯片,一般都会嵌入内部 Flash 和 RAM,并且 ...

  2. Python - 3.8 新特性之仅位置参数 & 仅关键字参数

    前置知识 Python 函数:https://www.cnblogs.com/poloyy/p/15092393.html 什么是仅限位置形参 仅限位置形参是 Python 3.8 才有的新特性 新增 ...

  3. Jenkins(6)- 新建用户

    如果想从头学起Jenkins的话,可以看看这一系列的文章哦 https://www.cnblogs.com/poloyy/category/1645399.html 进入用户管理 点击新建用户 填写新 ...

  4. Gitlab - 安装的社区版 Gitlab-ce,解决访问网页报502-Whoops, GitLab is taking too much time to respond的问题

    问题背景 在自己虚拟机(centos7)上装了 Gitlab-ce,就是社区版的 Gitlab,版本是 13.0+ 问题描述 浏览器访问 Gitlab 网站,报 502 问题翻译 502-Whoops ...

  5. container of()函数简介

    在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义 ...

  6. 八、Abp vNext 基础篇丨标签聚合功能

    介绍 本章节先来把上一章漏掉的上传文件处理下,然后实现Tag功能. 上传文件 上传文件其实不含在任何一个聚合中,它属于一个独立的辅助性功能,先把抽象接口定义一下,在Bcvp.Blog.Core.App ...

  7. C# 下载远程http文件到本地

    System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();   ...

  8. js简单化技巧

    1.交换两个变量而没有第三个 let x = 1;let y = 2;[x, y] = [y, x];console.log(x, y); 输出: 2 1 2.将数字转换为字符串 const num  ...

  9. Java面向对象系列(5)- 构造器详解

    构造器: 和类名相同 没有返回值 作用: new本质在调用构造器 初始化对象的值 注意点: 定义了有参构造之后,如果想要使用有参构造,必须显示的定义一个无参构造 IDEA快捷键: Alt + Inse ...

  10. Jmeter扩展组件开发(7) - 自定义java请求的开发

    CODE package com.demo;import org.apache.jmeter.config.Arguments;import org.apache.jmeter.protocol.ja ...