简体   繁体   English

Openlayers / GeoServer WFS缓存,切片或任何优化

[英]Openlayers/GeoServer WFS caching, tiles or any optimization

I'm developping a Web application using OpenLayers 3.20.0 with layers coming from GeoServer, linked to an Oracle data source. 我正在使用OpenLayers 3.20.0开发一个Web应用程序,并将来自GeoServer的图层链接到Oracle数据源。 This application is using mostly ImageWMS layer, and also a Vector layer for interaction and edition. 该应用程序主要使用ImageWMS层,还使用Vector层进行交互和编辑。 The issue is that the map is very slow with more than 30000 polylines drawn, and I would like to make the process faster :-) 问题是,绘制30000多条折线后,地图非常慢,我想使过程更快:-)

So I would like to know what is the best way to do. 所以我想知道什么是最好的方法。 I found two ways : 我发现了两种方法:

  • change my Vector layer in ImageWMS layer, and load manually needed features only on selection or edition, but it asks me a certain amount of modifications in my code 更改ImageWMS层中的Vector层,并仅在选择或编辑时加载手动所需的功能,但这要求我在代码中进行一定程度的修改
  • use VectorTile layer instead of Vector layer, I guess it should work like ImageWMS and a tile system so that data are loaded only according to the view of the map (Am i good ?) 使用VectorTile层而不是Vector层,我猜它应该像ImageWMS和图块系统一样工作,以便仅根据地图视图加载数据(很好吗?)

I looked for samples of VectorTile, but they are not very numerous (most of the time it's about OpenLayers 2), and the documentation is a little poor. 我寻找了VectorTile的样本,但是样本不是很多(大多数情况下是关于OpenLayers 2的),并且文档有点差。

The big unknown about the layer declaration is about the VectorTile source. 关于图层声明的最大未知数是关于VectorTile源的。 An URL must be defined, and I found in documentation that I have to put {x}/{y}/{z} parameters, but where exactly, and how is built this URL ? 必须定义一个URL,并且我在文档中发现必须放置{x} / {y} / {z}参数,但是该URL的确切位置和构建方式? (see https://openlayers.org/en/latest/apidoc/module-ol_source_VectorTile-VectorTile.html , the 'url' option) (请参见https://openlayers.org/en/latest/apidoc/module-ol_source_VectorTile-VectorTile.html ,“ url”选项)

As sample, my current Vector source has an URL like this : /geoserver/ANF/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ANF:myLayer&outputFormat=application%2Fjson 作为示例,我当前的Vector源具有以下URL:/geoserver/ANF/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ANF:myLayer&outputFormat=application%2Fjson

So to define VectorTile source, how do I define my URL, and what do have I to do on GeoServer side to configure my layer in the correct way ? 因此,要定义VectorTile源,如何定义我的URL,以及在GeoServer端做什么以正确的方式配置我的图层? I found this resource : https://docs.geoserver.org/latest/en/user/extensions/vectortiles/tutorial.html 我找到了这个资源: https : //docs.geoserver.org/latest/en/user/extensions/vectortiles/tutorial.html

The only vector tile format I have that is not image type on GeoServer is 'application/json;type=utfgrid'. 我在GeoServer上唯一没有图像类型的矢量平铺格式是'application / json; type = utfgrid'。 And when I put '@pbf/{z}/{x}/{-y}.pbf' at the end of my URL like the sample, I got errors, but I guess it's not the right way. 当我将“ @ pbf / {z} / {x} / {-y} .pbf”放在示例的URL末尾时,出现了错误,但我猜这不是正确的方法。

Any help would be greatly appreciated to give me more precision on how to make work a VectorTile layer and source with GeoServer, or another way to optimize the map I create. 我们将不胜感激任何帮助,以便为我提供有关如何使用GeoServer使VectorTile图层和源工作更加精确的方法,或者是优化我创建的地图的另一种方法。

Many thanks. 非常感谢。

EDIT 编辑

After some answers, I'm coming to this sample of code : 在得到一些答案之后,我将介绍以下代码示例:

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');

This code falls to the following error : 此代码属于以下错误:

ERROR TypeError: Cannot read property 'getUnits' of null at ol.renderer.canvas.VectorTileLayer.createReplayGroup_ (ol-debug.js:29814) at ol.renderer.canvas.VectorTileLayer.drawTileImage (ol-debug.js:29886) at ol.renderer.canvas.VectorTileLayer.ol.renderer.canvas.TileLayer.prepareFrame (ol-debug.js:26557) at ol.renderer.canvas.Map.renderFrame (ol-debug.js:30302) at ol.Map.renderFrame_ (ol-debug.js:42107) at ol.Map. 错误TypeError:无法读取ol.renderer.canvas.VectorTileLayer.drawTileImage(ol-debug.js:29886)处ol.renderer.canvas.VectorTileLayer.createReplayGroup_(ol-debug.js:29814)处为null的属性'getUnits' ol.Map上的ol.renderer.canvas.Map.renderFrame(ol-debug.js:30302)上的ol.renderer.canvas.VectorTileLayer.ol.renderer.canvas.TileLayer.prepareFrame(ol-debug.js:26557)位于ol.Map的renderFrame_(ol-debug.js:42107)。 (ol-debug.js:41013) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:3815) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188) (ol-debug.js:41013),位于Object.onInvokeTask(core.js:3815)处的ZoneDelegate.push ../ node_modules / zone.js / dist / zone.js.ZoneDelegate.invokeTask(zone.js:421)处Zone.push ../ node_modules / zone.js / dist / zone.js.Zone.runTask上的ZoneDelegate.push ../ node_modules / zone.js / dist / zone.js.ZoneDelegate.invokeTask(zone.js:420) (zone.js:188)

It appears that the issue comes now from EPSG:2169. 看来此问题现在来自EPSG:2169。 An sample with EPSG:3857 works well (see answers). EPSG:3857的示例效果很好(请参阅答案)。

Am I missing something ? 我想念什么吗?

Many thanks ! 非常感谢 !

The easiest way to speed up your application is to switch to using a WMTS (or tiled WMS) layer. 加快应用程序速度的最简单方法是切换到使用WMTS(或切片WMS)层。 This way your application can make use of the browser cache to only request tiles it hasn't seen before and the server need only render them once as they are cached to disk there too. 这样,您的应用程序就可以利用浏览器缓存来仅请求以前从未见过的切片,并且服务器也只需渲染一次,因为它们也被缓存到了磁盘中。

You almost certainly don't need all 300K features for your editing so trying to filter the WFS to just the bounding box of the requested area will help. 您几乎可以肯定不需要所有300K功能来进行编辑,因此尝试将WFS过滤为仅所请求区域的边界框将有所帮助。

Finally, the biggest win would probably come from switching to a proper spatial database like PostGIS. 最后,最大的成功可能来自切换到适当的空间数据库,例如PostGIS。

Vector tiles don't need to be .pbf or use XYZ urls. 矢量图块不必为.pbf或使用XYZ网址。 Here's the OpenLayers WFS example reworked to use the WFS url as the source for vector tiles. 这是经过重新设计的OpenLayers WFS示例,使用WFS url作为矢量切片的源。 When zoomed out to cover the whole of Canada it does seem more responsive than the original example. 当缩小以覆盖整个加拿大时,它似乎比原始示例更具响应性。

  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> 

There does seem to be a problem using that code with projections based on proj4 but it should work using a tile load function 将该代码与基于proj4的投影一起使用似乎确实存在问题,但它应该使用图块加载功能工作

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
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM