0

I am loading a lot of vector tile layers onto my OpenLayers (v.9) map and I'm trying to get restrict the extent of the tiles it tries to load in order to suppress 404 errors in the console, but I'm still getting a few.

I'm defining my VectorTileLayer like this:

 const vtSrc = createVectorTileSource(wrkspaceName, layerName, idField, featureType); const mvt = new VectorTileLayer({ opacity: 1, declutter: true, extent: vtSrc.getTileGrid().getExtent(), source: vtSrc, style: createStyleFunc(layerName, geomType, isAOI, fillColor), properties: { name: layerName, isAOI: isAOI }, zIndex: 1, }); 

For reference this is how I create the VectorTileSource:

export const createVectorTileSource = ( wrkspaceName: string, layerName: string, idField: string, featureType?: string ) => { const vts = new VectorTileSource({ url: 'https://mydomain.com/geoserver/gwc/service/tms/1.0.0/' + wrkspaceName + '%3A' + layerName + '@EPSG%3A' + '900913' + '@pbf/{z}/{x}/{-y}.pbf', format: new MVT({ featureClass: featureType == 'feature' ? Feature : RenderFeature, idProperty: idField, }), }); return vts; }; 

My OpenLayers map uses the default EPSG 3857 projection and my GeoServer layers are being served with EPSG 900913 tiles (tile size [512, 512]). When I print the tilegrid extent of this layer to the console, I get these coordinates:

[-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244] 

That compares to the whole 900913 gridset in GeoServer: 900913 Gridset bbox

I can confirm that by plotting the coordinates in bbox finder. Obviously, that's not the extent of my layer but rather the extent of the whole gridset. When I get the bbox of the layer out of GeoServer in lat/long, its bbox has these coordinates and this is the extent I would like to set the Vector Tile Layer too:

[-124.7556263784179, 24.51862984111434, -66.95402637841792, 49.385634455558026] 

In GeoServer, I can also get the bounds of the data in its native units (EPSG 900913 - m) and it returns these coordinates. When I plot this on bbox finder the result doesn't make much sense to me, but if I explicitly set the VectorTileLayer extent property to these values, the 404 errors go away and I know they're in the proper units for the OpenLayers map, unlike the lat/longs.

[-13887732.802041369, 2816733.970116345, -7453288.123004889, 6340550.623693095] 

Is the only way to limit the vector tile layer extent by explicitly hardcoding it for each layer when I create the vector tile source or can I derive it and set it using the layer itself?

3
  • I'd use a WMTS rather than the older TMS service - then you get the extent and tile row/col min/max values in the capabilities document Commented Oct 3, 2024 at 7:57
  • Thanks for the confirmation - that's the route I headed down shortly after I posted, but if I'm understanding right, you still have to make a request and parse the capabilities document and get the extent from it, correct? Commented Oct 3, 2024 at 14:26
  • of course, that is always where the information is - you don't know what layers to request with out reading the capabilities document Commented Oct 4, 2024 at 8:33

1 Answer 1

0

I figured out how out how to make a WMTS tile grid with the extent by using the Get Capabilities document, but because it is an async function, I cannot actually use this in my code due to how my layers are set up to be consumed in React. I create all my layers using generalized functions that live outside of React components. After creating an object that contains our list of layers, I import that into our MapContainer component to use when initializing the map, thus all the layers need to exist, including the vector tile source, before initializing the map. So, in the end I still had to hardcode the extents for now. In the future, my solution will be to make a table in our DB with the extents and other info I need so I can query it at application build time to build the layers instead of using a fetch() request for the Get Capabilities doc.

But, for completeness-sake, maybe this code will help someone down the line:

// CLASSES // import WMTSCapabilities from 'ol/format/WMTSCapabilities'; // FUNCTIONS // import { transformExtent } from 'ol/proj'; import { createFromCapabilitiesMatrixSet } from 'ol/tilegrid/WMTS'; // CONSTANTS // import { DEVICE_PIXEL_RATIO } from 'ol/has'; //My lazy types to make TypeScript stop complaining type WMTSCapabilitiesObj = { Contents: { Layer: WMTSCapabilitiesLayer[]; TileMatrixSet: { Identifier: string; SupportedCRS: string; TileMatrix: { [prop: string]: any }[]; }[]; }; OperationsMetadata: { [prop: string]: any; }; ServiceIdentification: { [prop: string]: any; }; ServiceProvider: { [prop: string]: any; }; version: string; }; type WMTSCapabilitiesLayer = { Format: string[]; Identifier: string; ResourceURL: { format: string; template: string; resourceType: string }[]; Style: { Identifier: string; isDefault: boolean; LegendURL: { format: string; href: string }[]; }[]; TileMatrixSetLink: { TileMatrixSet: string; TileMatrixSetLimits: { MaxTileCol: number; MaxTileRow: number; MinTileCol: number; MinTileRow: number; TileMatrix: string; }[]; }[]; Title: string; WGS84BoundingBox: number[]; }; export const createTileGrid = async (wrkspaceName: string, layerName: string) => { const wmts_parser = new WMTSCapabilities(); const response = await fetch( `https://mydomain.com/${wrkspaceName}/gwc/service/wmts?` + `service=WMTS` + `&version=1.0.0` + `&request=GetCapabilities` ); const docText = await response.text(); const capabilities: WMTSCapabilitiesObj = wmts_parser.read(docText); //Get the specific layer capabilities you want to create a tile grid for const lyrInfo: WMTSCapabilitiesLayer = capabilities.Contents.Layer.find( (lyr: WMTSCapabilitiesLayer) => lyr.Title == layerName ); //Get extent of layer and reproject it to EPSG 3857 coordinates const extent = transformExtent(lyrInfo.WGS84BoundingBox, 'EPSG:4326', 'EPSG:3857'); //Determine if using high resolution screen, then create tile grid //To be honest, I don't know if this is correct, but I *think* you //use the "x2" version of the projection for high DPI screens let matrixSet; if (DEVICE_PIXEL_RATIO > 1) { matrixSet = 'EPSG:900913x2'; } else { matrixSet = 'EPSG:900913'; } const tms = capabilities.Contents.TileMatrixSet.find( ({ Identifier }) => Identifier == matrixSet ); const tmsLimits = lyrInfo.TileMatrixSetLink.find( ({ TileMatrixSet }) => TileMatrixSet == matrixSet ); const tile_grid = createFromCapabilitiesMatrixSet(tms, extent, tmsLimits.TileMatrixSetLimits); return tile_grid; }; 

You could then continue this function, using the tile_grid to create your VectorTileSource and ultimately your VectorTileLayer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.