• 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源码见小专栏文章尾部小专栏

    文章尾部提供源代码下载,对本专栏感兴趣的话,可以关注一波

    GIS之家作品店铺:GIS之家作品店铺
    GIS之家源码咨询:GIS之家webgis入门开发系列demo源代码咨询
  • 相关阅读:
    【转帖】Explorer参数详解
    获取html页面时如何选择合适的Encoding
    不要在wpf窗口类的构造函数中抛异常
    把FlvDownloader重构了一下
    VK Cup 2012 Qualification Round 1 A. Next Round
    迎接2012新赛季——HDOJ系列热身赛(2) Problem A HDU 4161 Iterated Difference
    青蛙过河~~~~
    VK Cup 2012 Qualification Round 1 D. Ice Sculptures
    HDU 1006 Tick and Tick
    ACM参赛总结
  • 原文地址:https://www.cnblogs.com/giserhome/p/14847269.html
Copyright © 2020-2023  润新知