Do not cache data from aborted tile loads

This also results in a simplified cache method that can more easily be
overridden for use with other storage providers.
This commit is contained in:
ahocevar
2012-10-12 14:06:08 +02:00
parent cf3ea0c7db
commit 6607bcc0bb
3 changed files with 48 additions and 29 deletions

View File

@@ -111,7 +111,7 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
addLayer: function(evt) { addLayer: function(evt) {
evt.layer.events.on({ evt.layer.events.on({
tileloadstart: this.makeSameOrigin, tileloadstart: this.makeSameOrigin,
tileloaded: this.cache, tileloaded: this.onTileloaded,
scope: this scope: this
}); });
}, },
@@ -128,7 +128,7 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
removeLayer: function(evt) { removeLayer: function(evt) {
evt.layer.events.un({ evt.layer.events.un({
tileloadstart: this.makeSameOrigin, tileloadstart: this.makeSameOrigin,
tileloaded: this.cache, tileloaded: this.onTileloaded,
scope: this scope: this
}); });
}, },
@@ -156,6 +156,22 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
} }
}, },
/**
* Method: onTileloaded
* Decides whether a tile can be cached and calls the cache method.
*
* Parameters:
* evt - {Event}
*/
onTileloaded: function(evt) {
if (this.active && !evt.aborted &&
evt.tile instanceof OpenLayers.Tile.Image &&
evt.tile.url.substr(0, 5) !== 'data:') {
this.cache({tile: evt.tile});
delete OpenLayers.Control.CacheWrite.urlMap[evt.tile.url];
}
},
/** /**
* Method: cache * Method: cache
* Adds a tile to the cache. When the cache is full, the "cachefull" event * Adds a tile to the cache. When the cache is full, the "cachefull" event
@@ -166,29 +182,25 @@ OpenLayers.Control.CacheWrite = OpenLayers.Class(OpenLayers.Control, {
* <OpenLayers.Tile.Image> with the data to add to the cache * <OpenLayers.Tile.Image> with the data to add to the cache
*/ */
cache: function(obj) { cache: function(obj) {
if (this.active && window.localStorage) { if (window.localStorage) {
var tile = obj.tile; var tile = obj.tile;
if (tile instanceof OpenLayers.Tile.Image && try {
tile.url.substr(0, 5) !== 'data:') { var canvasContext = tile.getCanvasContext();
try { if (canvasContext) {
var canvasContext = tile.getCanvasContext(); var urlMap = OpenLayers.Control.CacheWrite.urlMap;
if (canvasContext) { var url = urlMap[tile.url] || tile.url;
var urlMap = OpenLayers.Control.CacheWrite.urlMap; window.localStorage.setItem(
var url = urlMap[tile.url] || tile.url; "olCache_" + url,
window.localStorage.setItem( canvasContext.canvas.toDataURL(this.imageFormat)
"olCache_" + url, );
canvasContext.canvas.toDataURL(this.imageFormat) }
); } catch(e) {
delete urlMap[tile.url]; // local storage full or CORS violation
} var reason = e.name || e.message;
} catch(e) { if (reason && this.quotaRegEx.test(reason)) {
// local storage full or CORS violation this.events.triggerEvent("cachefull", {tile: tile});
var reason = e.name || e.message; } else {
if (reason && this.quotaRegEx.test(reason)) { OpenLayers.Console.error(e.toString());
this.events.triggerEvent("cachefull", {tile: tile});
} else {
OpenLayers.Console.error(e.toString());
}
} }
} }
} }

View File

@@ -262,8 +262,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* loaded, as a means of progress update to listeners. * loaded, as a means of progress update to listeners.
* listeners can access 'numLoadingTiles' if they wish to keep * listeners can access 'numLoadingTiles' if they wish to keep
* track of the loading progress. Listeners are called with an object * track of the loading progress. Listeners are called with an object
* with a tile property as first argument, making the loded tile * with a 'tile' property as first argument, making the loded tile
* available to the listener. * available to the listener, and an 'aborted' property, which will be
* true when loading was aborted and no tile data is available.
* tileerror - Triggered before the tileloaded event (i.e. when the tile is * tileerror - Triggered before the tileloaded event (i.e. when the tile is
* still hidden) if a tile failed to load. Listeners receive an object * still hidden) if a tile failed to load. Listeners receive an object
* as first argument, which has a tile property that references the * as first argument, which has a tile property that references the
@@ -1090,9 +1091,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.numLoadingTiles++; this.numLoadingTiles++;
}; };
tile.onLoadEnd = function() { tile.onLoadEnd = function(evt) {
this.numLoadingTiles--; this.numLoadingTiles--;
this.events.triggerEvent("tileloaded", {tile: tile}); this.events.triggerEvent("tileloaded", {
tile: tile,
aborted: evt.type === "unload"
});
//if that was the last tile, then trigger a 'loadend' on the layer //if that was the last tile, then trigger a 'loadend' on the layer
if (this.tileQueue.length === 0 && this.numLoadingTiles === 0) { if (this.tileQueue.length === 0 && this.numLoadingTiles === 0) {
this.loading = false; this.loading = false;

View File

@@ -40,7 +40,7 @@
return; return;
} }
t.plan(3); t.plan(4);
OpenLayers.Control.CacheWrite.clearCache(); OpenLayers.Control.CacheWrite.clearCache();
var length = window.localStorage.length; var length = window.localStorage.length;
@@ -69,6 +69,9 @@
var content = canvasContext ? canvasContext.canvas.toDataURL("image/png") : null; var content = canvasContext ? canvasContext.canvas.toDataURL("image/png") : null;
t.eq(window.localStorage.getItem("olCache_"+url), content, "localStorage contains correct image data"); t.eq(window.localStorage.getItem("olCache_"+url), content, "localStorage contains correct image data");
layer.events.triggerEvent('tileloaded', {aborted: true, tile: layer.grid[1][1]});
t.eq(window.localStorage.length, length + (canvasContext ? tiles-1 : 0), "tile aborted during load not cached");
var key = Math.random(); var key = Math.random();
window.localStorage.setItem(key, "bar"); window.localStorage.setItem(key, "bar");
OpenLayers.Control.CacheWrite.clearCache(); OpenLayers.Control.CacheWrite.clearCache();