leaflet結合PostGIS動態渲染矢量瓦片(附源碼下載)


前言

leaflet 入門開發系列環境知識點了解:

內容概覽

leaflet結合PostGIS動態渲染矢量瓦片
源代碼demo下載

效果圖如下:

具體實現思路:
根據前端地圖請求的地圖當前級別以及行列號zxy(http://localhost:5000/tiles/quanguospot/spot/14/13345/7097),
后台接口python根據前端地圖傳值過來的zxy,動態計算地圖當前級別z行列號對應的地圖范圍extent(lonmin,latmin,lonmax,latmax),然后結合postgis動態生成矢量瓦片返回前端地圖渲染可視化。

postgis-stMvt

python 后台連接postgis 返回矢量切片

使用

  • 在tileOline.py中配置自己的postgis連接參數
Dbpool = psycopg2.pool.SimpleConnectionPool(

1,

2000,

dbname='postgis_31_sample',

user='postgres',

host='localhost',

password='postgres',

port='5432')

  • 根據ZXY計算對應地圖范圍Extent
import math

 def tile2lat(ytile, zoom):

n = 2.0 ** zoom

lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))

lat_deg = math.degrees(lat_rad)

return lat_deg

def tile2lon(xtile, zoom):

n = 2.0 ** zoom

lon_deg = xtile / n * 360.0 - 180.0

return lon_deg

def getLon(xtile, zoom):

a = []

a.append(tile2lon(xtile, zoom))

a.append(tile2lon(xtile+1, zoom)) 

return a

def getLat(ytile, zoom):

a = []

a.append(tile2lat(ytile, zoom))

a.append(tile2lat(ytile+1, zoom)) 

return a

lons = Util.getLon(x, z)

lats = Util.getLat(y, z)

lonmin = str(lons[0])

lonmax = str(lons[1])

latmin = str(lats[1])

latmax = str(lats[0])

 

  • 重要的查詢語句
// 傳 source-layer 和 tableName參數動態獲取

 query = "WITH mvtgeom AS(SELECT ST_AsMVTGeom(geom,ST_MakeEnvelope(%s,%s,%s,%s,4326),4096,64,true) AS geom FROM public." + tableName + \

" t where t.geom IS NOT NULL AND ST_Intersects(geom, ST_MakeEnvelope(%s,%s,%s,%s,4326))) SELECT ST_AsMVT(mvtgeom.*,'" + \sourceLayer + "') FROM mvtgeom ;"

  • postgis重要函數說明
( 1) ST_AsMVTGeom:將一個圖層中位於參數box2d范圍內的一個幾何圖形的所有坐標轉換為MapBox VectorTile坐標空間里的坐標。

 ST_AsMVTGeom的官方文檔API:http://postgis.net/docs/manual-3.0/ST_AsMVTGeom.html

函數各個參數的含義:

geom —— 被轉換的幾何圖形信息。

bounds —— 某個矢量切片的范圍對應的空間參考坐標系中的幾何矩形框(沒有緩沖區)。

extent —— 是按規范定義的矢量切片坐標空間中的某個矢量切片的范圍。如果為NULL,則默認為4096(邊長為4096個單位的正方形)。

buffer —— 矢量坐標空間中緩沖區的距離,位於該緩沖區的幾何圖形部位根據clip_geom參數被裁剪或保留。如果為NULL,則默認為256。

clip_geom —— 用於選擇位於緩沖區的幾何圖形部位是被裁剪還是原樣保留。如果為NULL,則默認為true。

注意:從3.0版本開始,可以在配置時選擇Wagyu庫來裁剪和驗證MVT多邊形。Wagyu庫比默認的GEOS庫更快且能產生更正確的結果,但是它可能會丟棄小的多邊形。

(2) ST_AsMVT:ST_AsMVT聚合函數用於將基於MapBox VectorTile坐標空間的幾何圖形轉換為MapBox VectorTile二進制矢量切片。

PostGIS生成MVT矢量切片的步驟是:

使用ST_AsMVTGeom函數將幾何圖形的所有坐標轉換為MapBox VectorTile坐標空間里的坐標,這樣就將基於空間坐標系的幾何圖形轉換成了基於MVT坐標空間的幾何圖形。

使用ST_AsMVT函數將基於MVT坐標空間的幾何圖形轉換為MVT二進制矢量切片。

ST_AsMVT的官方文檔API:http://postgis.net/docs/manual-3.0/ST_AsMVT.html 

函數各個參數的含義:

row —— 至少具有一個geometry列的行數據。

name —— 圖層名字,默認為"default"。

extent —— 由MVT規范定義的屏幕空間(MVT坐標空間)中的矢量切片范圍。

geom_name —— row參數的行數據中geometry列的列名,默認是第一個geometry類型的列。

feature_id_name —— 行數據中要素ID列的列名。如果未指定或為NULL,則第一個有效數據類型(smallint, integer, bigint)的列將作為要素ID列,其他的列作為要素屬性列。

  • leaflet矢量瓦片插件前端加載代碼
var map = L.map('map',{renderer: L.canvas}).setView({ lat:23.56,lng:113.23 }, 14);

var positron = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {

opacity: 1

}).addTo(map);

//設置圖斑的樣式

var vectorTileStyling = {

spot:{

color: '#ffd700',

fillColor: '#e6d933',

fillOpacity: 0.1,

fill: true,

opacity: 1,

weight: 3,

dashArray: '5',

}

}

var pbfUrl = "http://localhost:5000/tiles/quanguospot/spot/{z}/{x}/{y}";

var mapboxVectorTileOptions = {

rendererFactory: L.canvas.tile, //L.canvas.tile L.svg.tile

maxZoom: 20,

minZoom: 5,

vectorTileLayerStyles: vectorTileStyling

};

var vectorGrid = L.vectorGrid.protobuf(pbfUrl, mapboxVectorTileOptions).addTo(map)

  • leaflet結合mapboxGL矢量瓦片前端加載代碼
var map = L.map('map', {maxZoom: 17}).setView([23.3759016568317, 113.22544097900392], 13);

map.createPane("tileLayerZIndex");

map.getPane("tileLayerZIndex").style.zIndex = 0;

var positron = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {

opacity: 1,

pane: "tileLayerZIndex",

}).addTo(map);

var blankStyle = {

version: 8,

name: "BlankMap",

sources: {},

layers: [

]

};

var gl = L.mapboxGL({

accessToken: 'pk.eyJ1IjoiZ2lzeGlhb3dlaTEyMyIsImEiOiJja25zcTk4b3cweXZlMndwZjEyNzF1dXM2In0.V5daL_pyIbuSRN8K2PI80Q',

style: blankStyle

}).addTo(map);

gl.getMapboxMap().on('load', function() {

gl.getMapboxMap().addSource('myspot',{

'type':'vector',

'tiles':['http://localhost:5000/tiles/quanguospot/spot/{z}/{x}/{y}']

});

gl.getMapboxMap().addLayer({

'id': 'spot',//隨意

'source': 'myspot',//和上面那個source保持一致

'source-layer':'spot',//圖層名稱。就是數據的名稱

'type': 'fill',

'paint': {

"fill-color": "#e6d933", //讀取數據里的properties下的value獲取顏色

'fill-opacity': 0.25,

//"fill-outline-color" :"#e6d933",

/*"line-dasharray":[2,4]*/

},

"maxzoom": 20,

"minzoom": 8,

});

gl.getMapboxMap().addLayer({

'id': 'spot_line',//隨意

'source': 'myspot',//和上面那個source保持一致

'source-layer':'spot',//圖層名稱。就是數據的名稱

'type': 'line',

'paint': {

"line-color": "#e6d933",

"line-width": 3,

"line-dasharray": [3,3]

},

"maxzoom": 20,

"minzoom": 8,

});});

完整demo源碼見小專欄文章尾部小專欄

文章尾部提供源代碼下載,對本專欄感興趣的話,可以關注一波


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM