GeoServer发布pbf矢量切片和WCS服务以及ArcGIS api for js调用

什么是矢量瓦片服务

矢量瓦片技术是WebGIS中一项重要的地图数据组织与可视化技术,它通过预切割和分层技术,将矢量数据以瓦片的形式高效传输并在客户端渲染。

矢量瓦片是一种将矢量地理数据按照金字塔模型切割成小块并进行高效组织、传输和渲染的技术。与传统栅格瓦片不同,矢量瓦片包含的是几何和属性信息而非预渲染图像,这使得它们具有以下核心特点:

对比于普通的WMTS瓦片技术:

特性 矢量瓦片 栅格瓦片
数据格式 几何+属性(MVT、GeoJSON等),显示为pbf格式 图片(PNG、JPEG等)
客户端渲染 需要WebGL/Canvas支持 直接显示图片
样式灵活性 高,可动态修改 低,样式固定
交互能力 强,支持要素级查询,pop弹框 弱,仅能获取像素信息
数据量 相对较小 相对较大
制作成本 前期处理复杂 相对简单

技术方案:

切片工具方案

  • GeoServer:通过GeoWebCache扩展支持矢量切片生成,支持多种数据源和输出格式
  • Tegola:开源Go语言编写的矢量切片服务器,支持PostGIS数据源和MVT格式
  • ArcGIS Enterprise:提供完整的矢量切片生产与发布能力

maputnik

拉取maputnik:

bath 复制代码
docker pull maputnik/editor
docker exec -it geoserver bash
sudo cp *.jar /usr/local/geoserver/WEB-INF/lib/

geoserver发布的WCS服务以及ArcGIS api for js调用

html 复制代码
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>GeoScene Maps SDK for JavaScript Tutorials: Display a map</title>
    <!-- @@Start(link) -->
    <style>
        html,
        body,
        #viewDiv {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
        }
    </style>

    <link rel="stylesheet" href="https://js.arcgis.com/4.29/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.29/"></script>

    <script>
        require(["esri/config", "esri/Map", "esri/views/MapView", "esri/layers/VectorTileLayer", "esri/layers/WebTileLayer", "esri/layers/WCSLayer"], function (geosceneConfig, Map, MapView, VectorTileLayer, WebTileLayer, WCSLayer) {
            const map = new Map({
                basemap: []
            });
            // 1. 创建天地图矢量底图图层 (球面墨卡托投影 vec_w)
            var tdtBaseLayer = new WebTileLayer({
                urlTemplate: "https://t{subDomain}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=key",
                subDomains: ["0", "1", "2", "3", "4", "5", "6", "7"], // 使用多个子域名提升加载效
                title: "天地图矢量底图"
            });

            // 2. 创建天地图矢量注记图层 (球面墨卡托投影 cva_w)
            var tdtAnnoLayer = new WebTileLayer({
                urlTemplate: "https://t{subDomain}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=key",
                subDomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
                title: "天地图矢量注记"
            });

            // 3. 将底图和注记添加到地图中
            map.add(tdtBaseLayer);
            map.add(tdtAnnoLayer);


            const view = new MapView({
                map: map,
                center: [111.4, 37.9],
                zoom: 4,
                container: "viewDiv"
            });

            var tileLyr = new VectorTileLayer({
                style: {
                    "version": 8,
                    "sources": {
                        "osm": {
                            // 修正后的瓦片URL模板
// 矢量切片服务的url类似于(可以参考getcapabilities):http://<ip地址>/geoserver/it.geosolutions/gwc/service/wmts/rest/<图层名称>/<样式(类似于xx:yy,可以省略)>/<EPSG的坐标系>/<EPSG的坐标系>:{z}/{y}/{x}?format=application/vnd.mapbox-vector-tile                            
                            "tiles": ["http://localhost:8000/geoserver/it.geosolutions/gwc/service/wmts/rest/nanchang_bridge/cite:testshiliang/EPSG:900913/EPSG:900913:{z}/{y}/{x}?format=application/vnd.mapbox-vector-tile"
                            ],
                            "type": "vector"
                        }
                    },
                    "layers": [
                        {
                            "id": "nanchang_bridge",
                            "type": "line",
                            "source": "osm", // 确保此处指向上面定义的source名称
                            "source-layer": "nanchang_bridge", // 替换为GeoServer中实际的图层名
                            "paint": {
                                "line-color": "#269746", // 使用line-color而不是fill-color
                                "line-width": 7
                            }
                        }
                    ]
                },
                title: 'mvt',
            });
            map.add(tileLyr);
            console.log(tileLyr);
            // 加载WCS并添加WCS的弹窗
            const wcsLayer = new WCSLayer({
                // 替换为您的 WCS 服务地址
                url: "http://localhost:8000/geoserver/wcs",
                // 可选:指定覆盖范围标识符,默认为第一个覆盖范围
                coverageId: "nurc:Img_Sample",
                // 版本一定是1.0.0
                version: "1.0.0",
            });

// 设置弹框
            function getAdditionalInfo(pixelValue) {
    if (!pixelValue || pixelValue === "无数据") return "";
    
    try {
        const rgb = pixelValue.split(',').map(val => parseInt(val.trim()));
        if (rgb.length >= 3) {
            return `
                <div style="margin-top: 15px; padding: 10px; background: #e8f4fd; border-radius: 4px; border-left: 4px solid #1890ff;">
                    <strong style="color: #1890ff;">RGB解析:</strong>
                    <div style="margin-top: 5px;">
                        <span style="color: #ff4d4f;">R: ${rgb[0]}</span>, 
                        <span style="color: #52c41a;">G: ${rgb[1]}</span>, 
                        <span style="color: #1890ff;">B: ${rgb[2]}</span>
                    </div>
                </div>
            `;
        }
    } catch (e) {
        console.warn("解析RGB值失败:", e);
    }
    
    return "";
}
            // 将图层添加到地图
            map.add(wcsLayer);
            view.whenLayerView(wcsLayer).then(layerView => {
                wcsLayer.popupTemplate = {
                    highlightEable: true,
                    title: wcsLayer.title,
                    content: (e) => {
                        // 从 graphic.attributes 中获取数据
                        const attributes = e.graphic.attributes;
                        const pixelValue = attributes["Raster.ServicePixelValue"] || "无数据";
                        const rawPixelValue = attributes["Raster.ServicePixelValue.Raw"] || "无数据";
                        const objectId = attributes.ObjectId || "未知";

                        // 解析RGB值
                        let rgbDisplay = "无法解析";
                        if (pixelValue && pixelValue !== "无数据") {
                            const rgbArray = pixelValue.split(',').map(val => val.trim());
                            if (rgbArray.length >= 3) {
                                rgbDisplay = `
                        <div style="display: flex; align-items: center; margin: 5px 0;">
                            <div style="width: 20px; height: 20px; background: rgb(${pixelValue}); border: 1px solid #ccc; margin-right: 10px;"></div>
                            <span>RGB(${pixelValue})</span>
                        </div>
                    `;
                            }
                        }

                        return `
                <div style="min-width: 200px; font-family: Arial, sans-serif;">
                    <h4 style="margin-bottom: 15px; color: #333;">像素详细信息</h4>
                    
                    <div style="margin-bottom: 10px;">
                        <strong style="color: #666;">对象ID:</strong>
                        <span style="float: right;">${objectId}</span>
                    </div>
                    
                    <div style="margin-bottom: 15px; padding: 10px; background: #f5f5f5; border-radius: 4px;">
                        <strong style="color: #666; display: block; margin-bottom: 8px;">颜色值:</strong>
                        ${rgbDisplay}
                    </div>
                    
                    <div style="margin-bottom: 10px;">
                        <strong style="color: #666;">服务像素值:</strong>
                        <div style="font-family: monospace; background: #f8f8f8; padding: 5px; margin-top: 5px; border-radius: 3px;">
                            ${pixelValue}
                        </div>
                    </div>
                    
                    <div style="margin-bottom: 10px;">
                        <strong style="color: #666;">原始像素值:</strong>
                        <div style="font-family: monospace; background: #f8f8f8; padding: 5px; margin-top: 5px; border-radius: 3px;">
                            ${rawPixelValue}
                        </div>
                    </div>
                    
                    ${getAdditionalInfo(pixelValue)}
                </div>
            `;
                    }
                };

            })
        });   
    </script>
</head>

<body>
    <div id="viewDiv"></div>

</body>

</html>
相关推荐
Dorian_Ov05 小时前
Mybatis操作postgresql的postgis的一些总结
前端·gis
GIS小小研究僧2 天前
GIS与农业 考公考编面试 几个参考题
arcgis·conda·gis·qgis·rs
GISBox8 天前
GISBox如何让GeoTIFF突破Imagery Provider加载限制?
react.js·json·gis
Dorian_Ov010 天前
GeoServer添加要素图层的SLD样式文件以及中文乱码相关解决方案
前端·gis
GIS学姐嘉欣11 天前
【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(5):智慧矿产
学习·gis·智慧城市·webgis
GIS学姐嘉欣12 天前
【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(6):武汉视界
gis·智慧城市·webgis
AndrewHZ12 天前
【图像处理基石】GIS图像处理入门:4个核心算法与Python实现(附完整代码)
图像处理·python·算法·计算机视觉·gis·cv·地理信息系统
GIS开发特训营13 天前
【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(6):武汉视界
gis·智慧城市·gis开发·webgis
WebGIS开发21 天前
新中地三维GIS开发智慧城市效果和应用场景
前端·人工智能·gis·智慧城市·webgis