Search code examples
openlayersgeoserverogc

OpenLayers very poor performance when WMTS getCapabilities TileMatrixSet does not list low zoom level TileMatrix's


Running OL version 6.4.3

I am interacting with a WMTS service which has a TileMatrixSet like this:

<TileMatrixSet>
  <ows:Title>GoogleMapsCompatible</ows:Title>
  <ows:Abstract>GoogleMapsCompatible EPSG:3857</ows:Abstract>
  <ows:Identifier>GoogleMapsCompatible</ows:Identifier>
  <ows:SupportedCRS>urn:ogc:def:crs:EPSG::3857</ows:SupportedCRS>

It then lists TileMatrix's that correspond to zoom level 11 though 18.

Example:

<TileMatrix>
  <ows:Identifier>11</ows:Identifier>
  <ScaleDenominator>272989.38673277345</ScaleDenominator>
  <TopLeftCorner>-20037508.34278925 20037508.34278925</TopLeftCorner>
  <TileWidth>256</TileWidth>
  <TileHeight>256</TileHeight>
  <MatrixWidth>2048</MatrixWidth>
  <MatrixHeight>2048</MatrixHeight>
</TileMatrix>

Like I said, only 11 through 18 are listed like that so 0-10 are missing. That seems unusual. What openlayers appears to try to do when zoomed out between 0 and 10, is to fill the screen with tiles from zoom level 11. That is thousands of tiles when at zoom level 0. This is extremely taxing on the browser CPU. What is strange is that this heavy taxing occurs even if the ows:WGS84BoundingBox is defined in getCapabilities for the above service/layer. Perhaps openlayers is performing a little math on all those thousands of tiles, maybe to determine if that tile is within the bounding box. Openlayers does not perform a network request outside the ows:WGS84BoundingBox. If within, it requests at zoom level 11 and displays on the map as expected. The main issue here is CPU taxing. I'm not worried about over taxing the service with a lot of requests.

I am able to eliminate this problem by setting the minzoom property for the map layer to 11 using setMinZoom(). However, I don't know a great way to identify that the minzoom should be 11. In the TileMatrixSet, ows:Identifier is not guaranteed to equate to a zoom level. It's just a name I think. Should I use the scale denominator to do a little math?

That said, I also don't particularly want the data to disappear when zoomed below zoom level 11. Note, for the above service/layer, at zoom level 11, the data fits inside one 256x256 tile. I suppose I could subtract roughly 2 zoom levels to my liking: layer.setMinZoom(max(0,min_zoom_available-2)).

I believe one way to reproduce the large CPU taxing for yourself, take https://openlayers.org/en/latest/examples/wmts.html and modify lines 14-16 to be:

var resolutions = new Array(4);
var matrixIds = new Array(4);
for (var z = 10; z < 14; ++z) {

Then zoom out to lower zoom levels. This won't simulate the exact scenario because the Demographics/USA_Population_Density service in the example code is global. Maybe you could modify the extent somehow.

If the answer is that I need to push back on the service provider for not meeting a spec/standard, that is an acceptable answer. Especially if I can site such a standard. Or if there is a getCapabilities property the service provider could set that openlayers (or my app code) could read in order to set minzoom, I think that would also be an acceptable answer.


Solution

  • It would be easier to set maxResolution instead of minZoom

    If you use optionsFromCapabilities you can get the maxResolution used in the tile grid

            var source = new ol.source.WMTS(options);
            var layer = new ol.layer.Tile({
                source: source,
                maxResolution: options.tileGrid.getResolution(0)
            });
    

    multiply by 2 or 4 if you want to allow it to be exceeded by 1 or 2 extra zoom levels