New beforeload event and slightly changed loading sequence

Having the TileManager remove an image from the DOM, then setting the
cached image, and then having to position it felt a bit awkward. With the
new beforeload event, the setImage method and putting renderTile before
positionTile, providing the cached image feels way more natural.
This commit is contained in:
ahocevar
2012-12-18 01:21:11 +01:00
parent 64df7e3d04
commit a02e08ad2a
3 changed files with 38 additions and 17 deletions
+32 -2
View File
@@ -20,6 +20,23 @@
*/ */
OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
/**
* APIProperty: events
* {<OpenLayers.Events>} An events object that handles all
* events on the tile.
*
* Register a listener for a particular event with the following syntax:
* (code)
* tile.events.register(type, obj, listener);
* (end)
*
* Supported event types (in addition to the <OpenLayers.Tile> events):
* beforeload - Triggered before an image is prepared for loading, when the
* url for the image is known already. Listeners may call <setImage> on
* the tile instance. If they do so, that image will be used and no new
* one will be created.
*/
/** /**
* APIProperty: url * APIProperty: url
* {String} The URL of the image being requested. No default. Filled in by * {String} The URL of the image being requested. No default. Filled in by
@@ -164,8 +181,8 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
this.isLoading = true; this.isLoading = true;
this._loadEvent = "loadstart"; this._loadEvent = "loadstart";
} }
this.positionTile();
this.renderTile(); this.renderTile();
this.positionTile();
} else if (shouldDraw === false) { } else if (shouldDraw === false) {
this.unload(); this.unload();
} }
@@ -178,7 +195,6 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
* position it correctly, and set its url. * position it correctly, and set its url.
*/ */
renderTile: function() { renderTile: function() {
this.layer.div.appendChild(this.getTile());
if (this.layer.async) { if (this.layer.async) {
// Asynchronous image requests call the asynchronous getURL method // Asynchronous image requests call the asynchronous getURL method
// on the layer to fetch an image that covers 'this.bounds'. // on the layer to fetch an image that covers 'this.bounds'.
@@ -279,12 +295,26 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
return this.imgDiv; return this.imgDiv;
}, },
/**
* APIMethod: setImage
* Sets the image element or this tile. This method should only be called
* from beforeload listeners.
*
* Paramters
* img - {HTMLImageElement} The image to use for this tile.
*/
setImage: function(img) {
this.imgDiv = img;
},
/** /**
* Method: initImage * Method: initImage
* Creates the content for the frame on the tile. * Creates the content for the frame on the tile.
*/ */
initImage: function() { initImage: function() {
this.events.triggerEvent('beforeload');
this.layer.div.appendChild(this.getTile());
this.events.triggerEvent(this._loadEvent); this.events.triggerEvent(this._loadEvent);
var img = this.getImage(); var img = this.getImage();
if (this.url && img.getAttribute("src") == this.url) { if (this.url && img.getAttribute("src") == this.url) {
+4 -13
View File
@@ -255,8 +255,8 @@ OpenLayers.TileManager = OpenLayers.Class({
addTile: function(evt) { addTile: function(evt) {
evt.tile.events.on({ evt.tile.events.on({
beforedraw: this.queueTileDraw, beforedraw: this.queueTileDraw,
loadstart: this.manageTileCache, beforeload: this.manageTileCache,
reload: this.manageTileCache, loadend: this.addToCache,
unload: this.unloadTile, unload: this.unloadTile,
scope: this scope: this
}); });
@@ -273,8 +273,7 @@ OpenLayers.TileManager = OpenLayers.Class({
var tile = evt.object; var tile = evt.object;
tile.events.un({ tile.events.un({
beforedraw: this.queueTileDraw, beforedraw: this.queueTileDraw,
loadstart: this.manageTileCache, beforeload: this.manageTileCache,
reload: this.manageTileCache,
loadend: this.addToCache, loadend: this.addToCache,
unload: this.unloadTile, unload: this.unloadTile,
scope: this scope: this
@@ -330,16 +329,9 @@ OpenLayers.TileManager = OpenLayers.Class({
// only use image from cache if it is not on a layer already // only use image from cache if it is not on a layer already
if (img && (!img.parentNode || if (img && (!img.parentNode ||
OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer'))) { OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer'))) {
if (tile.imgDiv) { tile.setImage(img);
tile.layer.div.removeChild(tile.imgDiv);
}
tile.imgDiv = img;
OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url);
this.tileCacheIndex.push(tile.url); this.tileCacheIndex.push(tile.url);
tile.positionTile();
tile.layer.div.appendChild(tile.imgDiv);
} else if (evt.type === 'loadstart') {
tile.events.register('loadend', this, this.addToCache);
} }
}, },
@@ -351,7 +343,6 @@ OpenLayers.TileManager = OpenLayers.Class({
*/ */
addToCache: function(evt) { addToCache: function(evt) {
var tile = evt.object; var tile = evt.object;
tile.events.unregister('loadend', this, this.addToCache);
if (!this.tileCache[tile.url]) { if (!this.tileCache[tile.url]) {
if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) { if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) {
if (this.tileCacheIndex.length >= this.cacheSize) { if (this.tileCacheIndex.length >= this.cacheSize) {
+2 -2
View File
@@ -31,11 +31,11 @@
var layer = new OpenLayers.Layer.WMS('WMS', '../img/blank.gif'); var layer = new OpenLayers.Layer.WMS('WMS', '../img/blank.gif');
map.addLayer(layer); map.addLayer(layer);
map.setCenter([16, 48], 9); map.setCenter([16, 48], 9);
var numTileListeners = layer.grid[0][0].events.listeners.reload.length; var numTileListeners = layer.grid[0][0].events.listeners.beforeload.length;
var numLayerListeners = layer.events.listeners.retile.length; var numLayerListeners = layer.events.listeners.retile.length;
var numMapListeners = map.events.listeners.preremovelayer.length; var numMapListeners = map.events.listeners.preremovelayer.length;
tileManager.destroy(); tileManager.destroy();
t.eq(layer.grid[0][0].events.listeners.reload.length, numTileListeners - 1, "no listener on tile after destroy"); t.eq(layer.grid[0][0].events.listeners.beforeload.length, numTileListeners - 1, "no listener on tile after destroy");
t.eq(layer.events.listeners.retile.length, numLayerListeners - 1, "no listeners on layer after destroy"); t.eq(layer.events.listeners.retile.length, numLayerListeners - 1, "no listeners on layer after destroy");
t.eq(map.events.listeners.preremovelayer.length, numMapListeners - 1, "no listeners on map after destroy"); t.eq(map.events.listeners.preremovelayer.length, numMapListeners - 1, "no listeners on map after destroy");
map.destroy(); map.destroy();