0

我正在使用 OpenLayers 3.20.0 开发一个 Web 应用程序,其图层来自 GeoServer,链接到 Oracle 数据源。该应用程序主要使用 ImageWMS 层,以及用于交互和编辑的 Vector 层。问题是地图非常慢,绘制了超过 30000 条折线,我想让这个过程更快:-)

所以我想知道最好的方法是什么。我找到了两种方法:

  • 在 ImageWMS 层中更改我的向量层,并仅在选择或编辑时手动加载所需的功能,但它要求我对我的代码进行一定量的修改
  • 使用 VectorTile 层而不是 Vector 层,我想它应该像 ImageWMS 和瓦片系统一样工作,以便仅根据地图视图加载数据(我好吗?)

我寻找了 VectorTile 的样本,但它们的数量并不多(大部分时间都是关于 OpenLayers 2),而且文档有点差。

关于层声明的最大未知数是关于 VectorTile 源。必须定义一个 URL,我在文档中发现我必须放置 {x}/{y}/{z} 参数,但究竟在哪里,以及如何构建这个 URL?(参见https://openlayers.org/en/latest/apidoc/module-ol_source_VectorTile-VectorTile.html,“url”选项)

作为示例,我当前的 Vector 源具有这样的 URL:/geoserver/ANF/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ANF:myLayer&outputFormat=application%2Fjson

所以要定义 VectorTile 源,我如何定义我的 URL,以及在 GeoServer 端我需要做什么才能以正确的方式配置我的层?我找到了这个资源:https ://docs.geoserver.org/latest/en/user/extensions/vectortiles/tutorial.html

我在 GeoServer 上唯一不是图像类型的矢量切片格式是“application/json;type=utfgrid”。当我像示例一样将 '@pbf/{z}/{x}/{-y}.pbf' 放在我的 URL 末尾时,我得到了错误,但我想这不是正确的方法。

任何帮助将不胜感激,让我更精确地了解如何使用 GeoServer 制作 VectorTile 图层和源,或以其他方式优化我创建的地图。

非常感谢。

编辑

在一些答案之后,我来到这个代码示例:

this._view = new ol.View({
    center: [74000, 96000],
    projection: 'EPSG:2169',
    zoom: 13,
    maxZoom: 24,
    minZoom: 11
});

this._map = new ol.Map(
    {
        view: this._view,
        controls: [
            new ol.control.Zoom(),
            new ol.control.ScaleLine()
        ]                
    });

let vectorSourceURL: string = `/geoserver/ANF/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ANF:myLayer&outputFormat=application%2Fjson`;

let source = new ol.source.VectorTile({
    format: new ol.format.GeoJSON({
        defaultDataProjection: 'EPSG:2169',
        geometryName: 'GEOLOC'
    }),
    tileUrlFunction: function (tileCoord, pixelRatio, projection) {
        return vectorSourceURL + '&bbox=' + source.getTileGrid().getTileCoordExtent(tileCoord).join(',') + ',EPSG:2169';
    },
    tileGrid: ol.tilegrid.createXYZ(),
    projection: 'EPSG:2169'
});

let layer = new ol.layer.VectorTile({
    source: source,
    renderOrder: null
});

layer.set('name', 'myLayer');
layer.set('title', 'myLayer');

此代码属于以下错误:

错误类型错误:无法在 ol.renderer.canvas.VectorTileLayer.drawTileImage (ol-debug.js:29886) 的 ol.renderer.canvas.VectorTileLayer.createReplayGroup_ (ol-debug.js:29814) 处读取 null 的属性“getUnits” ol.renderer.canvas.VectorTileLayer.ol.renderer.canvas.TileLayer.prepareFrame (ol-debug.js:26557) 在 ol.renderer.canvas.Map.renderFrame (ol-debug.js:30302) 在 ol.Map。 ol.Map 的 renderFrame_ (ol-debug.js:42107)。(ol-debug.js:41013) 在 ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421) 在 Object.onInvokeTask (core.js:3815) 在ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420) 在 Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)

看来问题现在来自 EPSG:2169。EPSG:3857 的示例效果很好(请参阅答案)。

我错过了什么吗?

非常感谢 !

4

2 回答 2

0

矢量切片不需要是 .pbf 或使用 XYZ url。这是 OpenLayers WFS 示例,重新设计以使用 WFS url 作为矢量切片的源。当缩小以覆盖整个加拿大时,它似乎比原始示例更具响应性。

  var vectorSource = new ol.source.VectorTile({
    format: new ol.format.GeoJSON(),
    tileUrlFunction: function(tileCoord, pixelRatio, projection) {
      return 'https://ahocevar.com/geoserver/wfs?service=WFS&' +
          'version=1.1.0&request=GetFeature&typename=osm:water_areas&' +
          'outputFormat=application/json&srsname=EPSG:3857&' +
          'bbox=' + vectorSource.getTileGrid().getTileCoordExtent(tileCoord).join(',') + ',EPSG:3857';
    },
    tileGrid: ol.tilegrid.createXYZ()
  });

  var vector = new ol.layer.VectorTile({
    source: vectorSource,
    style: new ol.style.Style({
      stroke: new ol.style.Stroke({
        color: 'rgba(0, 0, 255, 1.0)',
        width: 2
      })
    })
  });

  var raster = new ol.layer.Tile({
    source: new ol.source.OSM()
  });

  var map = new ol.Map({
    layers: [raster, vector],
    target: document.getElementById('map'),
    view: new ol.View({
      center: [-8908887.277395891, 5381918.072437216],
      maxZoom: 19,
      zoom: 12
    })
  });
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/3.20.0/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/3.20.0/ol.js"></script>
<div id="map"></div>

使用带有基于 proj4 的投影的代码似乎确实存在问题,但它应该使用 tile load 函数工作

let viewProjection = ol.proj.get('EPSG:2169');

let format = new ol.format.GeoJSON({
        defaultDataProjection: viewProjection,
        featureProjection: viewProjection,
        geometryName: 'GEOLOC'
    });

let source = new ol.source.VectorTile({
    tileUrlFunction: function (tileCoord, pixelRatio, projection) {
        return vectorSourceURL + '&bbox=' + source.getTileGrid().getTileCoordExtent(tileCoord).join(',') + ',EPSG:2169';
    },
    tileLoadFunction: function (tile, url) {
        tile.setProjection(viewProjection);
        tile.setLoader(function() {
            var xhr = new XMLHttpRequest();
            xhr.onload = function() {
                tile.setFeatures(format.readFeatures(xhr.responseText));
            }
            xhr.open("GET", url, true);
            xhr.send();
        });
    },
    tileGrid: ol.tilegrid.createXYZ(),
    projection: viewProjection
});
于 2019-02-20T13:04:24.620 回答
0

加快应用程序速度的最简单方法是切换到使用 WMTS(或平铺 WMS)层。这样,您的应用程序可以利用浏览器缓存来仅请求它以前未见过的图块,并且服务器只需要渲染它们一次,因为它们也被缓存到磁盘中。

几乎可以肯定,您的编辑不需要所有 300K 特征,因此尝试将 WFS 过滤到仅请求区域的边界框会有所帮助。

最后,最大的胜利可能来自切换到像 PostGIS 这样的适当空间数据库。

于 2019-02-21T08:42:21.617 回答