头图

First effect:

origin

When using the WeChat applet to do map-related functions, there is a requirement that you need to access the map service published by yourself. Check the WeChat applet map component document, found that it has very little map-related support, only some basic functions, such as adding points, lines, areas, bubbles and some regular map event monitoring, and does not add map service-related support .

But when there is a demand, we must find a way to solve it.

Layer query

Since the applet cannot directly add map services, find out the layer data and add it to the map by adding points, lines and polygons. How do you implement it?

The first thing that comes to mind is to find out all the data through the layer query interface.

But since the data is published by layer, the amount of data is generally relatively large. If you query all the data and add too much data to the map at one time, the map component will not be able to bear it and it will become stuck. In addition, the WeChat applet is single-time The data of setData() 1024kB , so this scheme is not advisable.

Vector tiles

Since the amount of data requested at one time is too large, can it be requested in batches? So I thought of vector tiles.
Vector tiles are familiar to people who GIS GIS products to display large data maps.
But how do we make the small program map component that does not support adding external layers support vector tiles?

Checking the relevant documents of the map component, you will see that there is a regionchange event, which is triggered when the view of the map changes, that is, when the map is dragged or zoomed. It will return the current center point, zoom level, map range and other information.

Get tiles

The next step is how to obtain vector tiles based on these parameters.

Suppose that the origin of the map cut is (originX,originY) , the tile size of the tileSize , and the actual distance represented by 1 pixel on the map screen is resolution . The formula for calculating the row and column number of the tile where the coordinate point (x,y)

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

This formula should not be difficult to understand. To put it simply, first calculate the actual length LtileSize LrealSize between the geographic coordinate point on the screen and the starting point of the tile cut, and then Divide the actual distance by the actual length of a tile to get the tile row and column number at this time: LrealSize/LtileSize .

The specific code is as follows:

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
  }
},

Here you can see that there is a y value in the data I returned, and there is also a tmsY . This is because WMTS and TMS , the incoming y value is different, but there is a conversion between the two. tmsY = Math.pow(2, (level - 1)) - y - 1 , that is, WMTS uses the y returned here, and TMS uses the tmsY returned here.

Reference link:

WebGIS front-end map display, the principle of converting tile row and column number according to geographic range (core)

Slippy_map_tilenames

TMS and WMTS roughly compare

Next, we only need to obtain the number of the tile that contains the current viewable area of the map according to the maximum and minimum coordinates of the current viewable area of the map and the map level.

Since the map component of the WeChat applet uses the encrypted coordinates of the National Bureau of Survey and Measurement, and the map service data I released is the wgs84 , the coordinate conversion method needs to be used to obtain the slice number to convert the coordinates of the National Bureau of Survey to wgs84 coordinates. For the method, please refer to leaflet how to elegantly solve the offset problem of Baidu and Gaode maps .

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)
    }
  }
},

Then pass in the request address and the x, y, and z parameters wx.request geojson format data corresponding to the vector slice

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)
    }
  })
},
Note that here I am using geoserver . I found a problem during the call. In the data returned by one of the point layer tiles, each tile always has a lot of duplicate data. After inspection and testing, it is found that this is due to The style used when publishing this layer (point layer) is 40x88 , which causes a lot of pixel values to be buffered outward when cutting the image. Therefore, if geoserver publishes the layer It is used for vector slicing calls. It is best to set the point layer style to one pixel size pixel point, which can effectively reduce tile data redundancy

adding data

Finally, add points, lines and polygons to the map component of the WeChat applet to add the obtained slice data to the map.

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
  })
},

There is a problem

At this point, the addition of vector tile data to the WeChat applet has been completed, which can basically meet the needs of browsing external vector layers, but there are still some shortcomings here.

  1. Need to publish geojson format vector tile layer
  2. The layer will flash when the map is dragged. This is caused by the applet re-drawing the point, line and surface layer on the map
  3. When the small scale tile returns a large amount of data, there may be a stutter phenomenon (can be optimized by limiting the minimum scale)
  4. The layer map effect is limited by the point, line and surface style of the mini program map

Although this solution has some problems, it is still desirable in view of the limitations of the WeChat applet map component and the need to add layers in time.

Summarize

  1. The WeChat applet map component does not support adding external layer services
  2. By publishing the geojson format vector tile service, and then obtaining the geojson format tile data according to the current visible range
  3. regionchange event of the applet map component to monitor the drag and zoom of the map, you can get the current center point, zoom level, and map range
  4. According to the zoom level and map range, the tile number of the current visible range can be obtained
  5. Request tile data, add the tile data to the map by adding points, lines and planes to the map component of the WeChat applet

Code address

Code address: http://gisarmory.xyz/blog/index.html?source=WechatVectorTile


Original address: http://gisarmory.xyz/blog/index.html?blog=WechatVectorTile

Welcome to follow " GIS Weapons Library "

This article uses the Creative Commons Attribution-Non-Commercial Use-Same Method Sharing 4.0 International License Agreement for licensing. Welcome to reprint, use, and republish, but be sure to keep the article's signature "GIS Weapon Library" (including link: http://gisarmory.xyz/blog/ ), and it must not be used for commercial purposes. The same license is issued.


GIS兵器库
64 声望15 粉丝