sober
sober

Reputation: 23

OpenLayers: no new attempts to load tile if custom tileLoadFunction fails

I‘m using a custom tileLoadFunction in order to retrieve my tiles via an XMLHttpRequest (the reason for this is that the builtin loader doesn‘t always send the session cookie along to the server).

The loader works, however, if (e.g due to a network problem) the request for a tile fails, OpenLayers will not call the loader again for this tile.

My question now, is there a way to let OpenLayers know that the tile was not loaded successfully?

Thanks, Simon

function getTile(tile, url) 
{
    var xhr = new XMLHttpRequest();
    xhr.responseType = "arraybuffer";
    xhr.open('GET', url);

    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 0)
        {
            tile.getImage().src = "";
            //console.log("error " + url)
        }
    };      

    xhr.onload = function () {
        var arrayBufferView = new Uint8Array(this.response);
        var blob = new Blob([arrayBufferView]);
        var urlCreator = window.URL || window.webkitURL;
        var imageUrl = urlCreator.createObjectURL(blob);
        tile.getImage().src = imageUrl;
    }

    xhr.send();
}

Upvotes: 1

Views: 1713

Answers (2)

JimmyB
JimmyB

Reputation: 68

Late answer, but in your error catching you can set the tile state and attach an error-checking function to the tile setState event as Chase Choi noted:

if (xhr.readyState === 4 && xhr.status === 0) {
    tile.getImage().src = "";
    tile.setState(3);  //sets state to ERROR 
}
layer.getSource()on.("tileloaderror", handleTileLoadError); //set a timeout and run getTile again

However, I have found that a better approach is to include a retry in your request and place a limit on iterations:

const retries = {};
function getTile(tile, URL) { 

    ...

    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 0) {
        retries[src] = (retries[src] || 0) + 1);
        if (retries[src] <= 3) {
            setTimeout(() => tile.load(), retries[src] * 1000);
        }
    }

    ...

}

Upvotes: 0

dube
dube

Reputation: 5019

the cache prevents the tile from being loaded again. But you can use a trick: just set the tile loader function again by calling setTileLoadFunction, it internally clears the cache.

setTileLoadFunction(getTile)

Upvotes: 1

Related Questions