Reputation: 73
I am working on animating an OpenLayers map with multiple layers over a period of time. I would like to precache ol.layer.tile tiles to have smooth transitions between the dates. Any suggestions on how to precache/preload these tiles?
Upvotes: 4
Views: 1314
Reputation: 73
Solution that gets around cache-preventing headers.
var i = 0;
var renderer = new ol.renderer.canvas.TileLayer(layer);
var tileSource = layer.getSource();
var datePromise = new Promise(function(resolve, reject) {
tileGrid.forEachTileCoord(extent, currentZ, function(tileCoord) {
tile = tileSource.getTile(tileCoord[0], tileCoord[1], tileCoord[2], pixelRatio, projection);
tile.load();
var loader = function(e) {
if(e.type === 'tileloadend') {
--i;
if(i === 0) {
resolve();
}
} else {
reject(new Error('No response at this URL'));
}
/* remove listeners */
this.un('tileloadend', loader);
this.un('tileloaderror', loader);
};
tileSource.on('tileloadend', loader);
tileSource.on('tileloaderror', loader);
++i;
});
});
Upvotes: 2
Reputation: 5647
You'll want to rely on your browser cache here. And it requires that your server sends proper cache headers, so the browser does not re-fetch the images with every request. With these prerequisites in mind, proceed as follows:
Call ol.source.TileImage#getTileUrlFunction
on your source so you can compute the urls of the tiles you want to cache.
Call ol.source.TileImage#getTileGrid
on your source so you can get the tile coordinates for the extent and zoom level you want to cache
Call ol.tilegrid.TileGrid#forEachTileCoord
with a function that computes the url for each tile and sets it as src on an image object. When doing so, keep track of the number of loading tiles so you know when you're done.
Repeat the above for all dimensions, after making the respective dimension changes to your source.
In the end, your code for preloading a single dimension could look something like this:
var loadingCount = 0;
var myTileUrlFunction = mySource.getTileUrlFunction();
var myTileGrid = mySource.getTileGrid();
myTileGrid.forEachTileCoord(myExtent, myZoom, function(tileCoord) {
var url = myTileUrlFunction.call(mySource, tileCoord, ol.has.DEVICE_PIXEL_RATIO, myProjection);
var img = new Image();
img.onload = function() {
--loadingCount;
if (loadingCount == 0) {
// ready to animate
}
}
++loadingCount;
img.src = url;
}
Upvotes: 5