First up effect:
origin
When using wechat applet for map related functions, there is a need to access the published map service. View wechat applet Map components It is found that it has little support for map related functions, only some basic functions, such as adding points, lines, surfaces, bubbles and some conventional map event monitoring, and no support for map services.
However, if there is a demand, we should also find a way to solve it.
Layer query
Since the applet cannot directly add map services, find out the layer data, and then add it to the map by adding points, lines and surfaces. How to implement it?
The first thought is to find out all the data through the layer query interface.
However, since the data is published by layer, the amount of data is generally large. Query all the data and add too much data to the map at one time, and the map component will become stuck. In addition, the data of wechat applet setData() cannot exceed 1024kB at a single time, so this scheme is not desirable.
Vector tile
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 GIS people, which is also the main way for large data map display of various GIS products.
However, how can we make the applet map component that does not support adding external layers support vector tiles?
When you view the documents related to the map component, you will see a regionchange event. This event is triggered when the map view changes, that is, when you drag and zoom the map. 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 according to these parameters.
Suppose that the origin of the map cut is (originX,originY), the tile size of the map is tile size, and the actual distance represented by 1 pixel on the map screen is resolution. The formula for calculating the row and column number of tiles where the coordinate point (x,y) is located is:
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 contained in a tile, then calculate the actual distance LrealSize between the geographic coordinate point on the screen and the starting point of the tile cut-off diagram, and then divide the actual distance by the actual length of a tile to obtain the tile row and column number at this time: LrealSize/LtileSize.
The specific codes are as follows:
getTileXY: function (lon, lat, level) { let originX = -180; //The value of x at the origin of the coordinate system, let originY = 90; //The value of y at the origin of the coordinate system //According to your corresponding slicing scheme, this is its resolution 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 //This value represents the size of each slice, usually 256 let coef = resolution[level] * tileSize; let x = Math.floor((lon - originX) / coef); // Round down and discard the decimal part let y = Math.floor((originY - lat) / coef); // Round down and discard the decimal part let tmsY = Math.pow(2, (level - 1)) - y - 1; return { x: x, y: y, z: level - 1, tmsY: tmsY } },
Here, I can see that there is a y value and a tmsY in the returned data. This is because when WMTS and TMS call slices, the incoming y value is different, but they can be converted, that is, tmsY = Math.pow(2, (level - 1)) - y - 1. WMTS uses the Y returned here and TMS uses the tmsY returned here.
Reference link:
Approximate comparison between TMS and WMTS
Next, we only need to obtain the number of tiles containing the current map viewing range according to the maximum and minimum coordinates of the current map viewing range and the map level.
Since the wechat applet map component uses the encrypted coordinates of the National Survey Bureau, and the map service data I released is wgs84 coordinates, it is necessary to use the coordinate conversion method to convert the coordinates of the National Survey Bureau into wgs84 coordinates when obtaining the slice number. The coordinate correction method can be referred to How to gracefully solve the offset problem of Baidu and Gaode maps in leaflet.
getXYZList: function (region, level) { // coordinate transformation var newsouthwest = appcoord.gcj02_To_gps84(region.southwest.longitude, region.southwest.latitude); var northeastwest = appcoord.gcj02_To_gps84(region.northeast.longitude, region.northeast.latitude); // Get Tile Number 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, the geo JSON format data of the corresponding vector slice can be obtained by passing in the request address and x, y and z parameters through wx.request
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 I use geoserver to publish vector tiles here. During the calling process, I found a problem. In the data returned by a point layer tile, each tile always has a lot of duplicate data. After inspection and test, it is found that this is because the style used when publishing the layer (point layer) is a 40x88 picture point sample, This causes a lot of pixel values to be buffered outward during image cutting. Therefore, if the layer published by geoserver is used for vector slice call, it is best to set the point layer style to a pixel of pixel size, which can effectively reduce tile data redundancy
Add data
Finally, the obtained slice data can be added to the map by adding points, lines and surfaces to the map component of wechat applet
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 }) },
Existing problems
So far, adding vector tile data to wechat applet has been completed, which can basically meet the needs of browsing external vector layers. However, there are still some deficiencies here
- You need to publish vector tile layers in geojson format
- When dragging the map, the layer will flash, which is caused by the applet redrawing the point, line and surface layer on the map
- When the amount of data returned by small-scale tiles is large, there may be Caton phenomenon (which can be optimized by limiting the minimum scale)
- The effect of layer matching is limited by the point, line and surface style of applet map
Although there are some problems with this solution, it is still desirable in view of the limitations of wechat applet map components and the need to add layers.
summary
- The wechat applet map component does not support adding external layer services
- By publishing the geojson format vector tile service, and then obtain the geojson format tile data according to the current visual range
- Monitor map dragging and zooming through the regionchange event of the applet map component to obtain the current center point, zoom level and map range
- The tile number of the current visual range can be obtained according to the zoom level and map range
- Request tile data and add slice data to the map by adding points, lines and surfaces in the map component of 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 pay attention< GIS weapon warehouse>
This article adopts Knowledge sharing Attribution - non-commercial use - sharing in the same way 4.0 international license agreement Permission. You are welcome to reprint, use and republish, but be sure to keep the signed GIS weapon Library (including link: http://gisarmory.xyz/blog/ ), shall not be used for commercial purposes, and the works modified based on this article must be distributed under the same license.
Discussion]( https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh )Permission. You are welcome to reprint, use and republish, but be sure to keep the signed GIS weapon Library (including link: http://gisarmory.xyz/blog/ ), shall not be used for commercial purposes, and the works modified based on this article must be distributed under the same license.