[OpenLayers-Users] ESRI vector tiles

Daniel Urda daniel.urda.ct at gmail.com
Tue Aug 4 08:37:22 PDT 2020


Thanks, I was looking in OL internals when this could be done with public
API. Your code was almost right, I only had to recalculate extent used to
read features to account for the larger tile. I will need to investigate
how this affects z-ordering with complex styles, but this works for the
moment.

Is there any reason why the loader should be synchronous?

Here's an async TS version that worked for me, if somebody else needs it:

const recursivelyFetchTile = (url, projection, tileGrid, tileUrl, center,
curLevel) => new Promise((resolve, reject) => {
            fetch(url).then((response) => {
                if (response.status !== 200) {
                    if (curLevel > tileGrid.getMinZoom()) {
                        const ntileCoord =
tileGrid.getTileCoordForCoordAndZ(center, curLevel - 1 );
                        resolve(recursivelyFetchTile(tileUrl(ntileCoord,
devicePixelRatio, projection),
                            projection, tileGrid,  tileUrl,  center,
 curLevel - 1));
                    }
                    else
                        reject('NONE');
                }
                else
                    resolve(response.arrayBuffer().then((data) => [ data,

tileGrid.getTileCoordExtent(tileGrid.getTileCoordForCoordAndZ(
                                center, curLevel))
                        ]));
            })
        });

tileLoadFunction: (tile, url) => {
                (tile as VectorTile).setLoader((extent, resolution,
projection) => {
                    const tileGrid = vtSource.getTileGrid();
                    const tileCoord = tile.getTileCoord();
                    const zoomLevel = tileCoord[0];
                    const center =
getCenter(tileGrid.getTileCoordExtent(tile.getTileCoord()));
                    const tileUrl = vtSource.getTileUrlFunction();
                    const format = (tile as VectorTile).getFormat()

                    recursivelyFetchTile(url, projection, tileGrid,
tileUrl, center, zoomLevel)
                        .then(([data, extent]) => {

                            const features = format.readFeatures(data, {
                                extent: extent,
                                featureProjection: projection
                            });
                            (tile as VectorTile).setFeatures(features as
Feature[]);
                        }).catch((reason) => {
                            console.log('rejected', reason);
                            (tile as VectorTile).setFeatures([]);
                        })
                });

            }

Regards,
Daniel Urda

On Tue, Aug 4, 2020 at 5:01 PM Andreas Hocevar <andreas.hocevar at gmail.com>
wrote:

> The easiest way to achieve this is to configure a custom tileLoadFunction
> for the VectorTile source. That function, when it receives a 404, has to
> request the tile for the next lower zoom, until it receives a 200, and call
> `setFeatures` with the result. Something like this (untested):
>
> import {getCenter} from 'ol/extent';
> import MVT from 'ol/format/MVT';
>
> const source = new VectorTileSource({
> format: new MVT(),
> url: 'https://my.tiles/{z}/{x}/{y}.pbf',
> tileLoadFunction(tile, url) {
> tile.setLoader(async (extent, resolution, projection) => {
> let response = await fetch(url);
> let status = response.status;
> let tileCoord = tile.tileCoord;
> const tileGrid = source.getTileGrid();
> while (status !== 200 && tileCoord[0] > tileGrid.getMinZoom()) {
> const z = tileCoord[0];
> tileCoord = tileGrid.getTileCoordForCoordAndZ(
> getCenter(tileGrid.getTileCoordExtent(tileCoord)), z - 1
> );
> response = await fetch(source.getTileUrlFunction()(tileCoord,
> devicePixelRatio, projection));
> }
> const data = await response.arrayBuffer();
> const format = tile.getFormat()
> const features = format.readFeatures(data, {
> extent: extent,
> featureProjection: projection
> });
> tile.setFeatures(features);
> });
> }
> });
>
> I hope this helps.
>
> Andreas.
>
> On Tue, Aug 4, 2020 at 2:45 PM Daniel Urda <daniel.urda.ct at gmail.com>
> wrote:
>
>> Hello,
>>
>> I am resending this since the mail requiring confirmation of registration
>> to the mailing list went to my spam folder. Sorry if this results in a
>> duplicate mail.
>>
>> I am trying to consume a vector tiles as provide by an ArcGIS Enterprise
>> Server. I successfully managed to hijack the MapboxVector layer in order to
>> display the tiles in OpenLayers (fortunately style description is more or
>> less compatible with MapboxVector).
>> The issue is that ESRI Vector Tile Services randomly decide to drop lower
>> level tiles. Thus, if ESRI somehow decides that for a certain area level
>> X+1 does not provide significantly more information than level X, tiles on
>> level X+1 are not generated  (requests result in 404) and the client is
>> expected to display the data on level X. ArcGIS JS does have a mechanism to
>> make sure it never gets 404 (making use of
>> https://developers.arcgis.com/rest/services-reference/tile-map.htm ),
>> however it seems to me that implementing that in OL would need significant
>> effort with low benefits. Setting maxZoom on the vector tile is not really
>> helpful, since better zoom levels may exist in some regions (detecting the
>> max level that has tiles for all areas is cumbersome, but doable using the
>> API in the provided link).
>> Therefore, I was thinking I could somehow convince OL to render the tile
>> at best available resolution when it gets 404s at better resolution. Any
>> hint to where exactly in the code I could do that?
>>
>> Thanks,
>> Daniel Urda
>> _______________________________________________
>> Users mailing list
>> Users at lists.osgeo.org
>> https://lists.osgeo.org/mailman/listinfo/openlayers-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/openlayers-users/attachments/20200804/bf27dedf/attachment-0001.html>


More information about the Users mailing list