From dde45696f7d292939134935d61cb75a4047e82d9 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Sat, 28 Jan 2012 16:12:29 +0100 Subject: [PATCH] Simplified tile queue; using the tile's beforedraw listener. Since draw is the only tile operation that we defer, the tile queue can be an array of tiles and queue handling can be simplified. We now use the beforedraw event to defer drawing, and remove all occurrences of a tile from the tile queue when we draw it. Instead of layers that want to defer tile drawing having to override the tile's draw method, layers can now abort drawing by returning false from a beforedraw listener, and later call draw(true) to draw the tile directly, without clearing it first. --- lib/OpenLayers/Layer/Grid.js | 106 +++++++++--------- lib/OpenLayers/Tile.js | 31 +++-- lib/OpenLayers/Tile/Image.js | 1 + tests/Layer/ArcGIS93Rest.html | 4 +- tests/Layer/Grid.html | 6 +- tests/Layer/MapServer.html | 4 +- tests/Layer/WMS.html | 4 +- tests/Layer/WrapDateLine.html | 4 +- tests/Tile/Image.html | 3 + tests/Tile/Image/IFrame.html | 3 + tests/deprecated/Layer/MapServer/Untiled.html | 4 +- 11 files changed, 93 insertions(+), 77 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 0355f2b7d4..4a8fdf79bc 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -105,16 +105,16 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { serverResolutions: null, /** - * Property: tileLoopId - * {Number} - The id of the animation. + * Property: tileQueueId + * {Number} - The id of the animation. */ - tileLoopId: null, + tileQueueId: null, /** - * Property: tileOperations - * {Array(Object)} Pending tile operations. + * Property: tileQueue + * {Array()} Tiles queued for drawing. */ - tileOperations: null, + tileQueue: null, /** * Property: backBuffer @@ -186,7 +186,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this, arguments); this.grid = []; - this.tileOperations = []; + this.tileQueue = []; }, /** @@ -197,7 +197,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * map - {} The map. */ removeMap: function(map) { - this.abortTileOperations(); + this.clearTileQueue(); if(this.backBufferTimerId !== null) { window.clearTimeout(this.backBufferTimerId); this.backBufferTimerId = null; @@ -223,7 +223,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * destroy() on each of them to kill circular references */ clearGrid:function() { - this.abortTileOperations(); + this.clearTileQueue(); if (this.grid) { for(var iRow=0, len=this.grid.length; iRow. + * + * Parameters: + * tile - {} The tile to remove from the queue */ - abortTileOperations: function() { - OpenLayers.Animation.stop(this.tileLoopId); - this.tileLoopId = null; - this.tileOperations = []; + unqueueTile: function(tile) { + for (var i=this.tileQueue.length-1; i>=0; --i) { + if (this.tileQueue[i].tile === tile) { + this.tileQueue.splice(i, 1); + } + } + }, + + /** + * Method: clearTileQueue + * Clears the animation queue + */ + clearTileQueue: function() { + OpenLayers.Animation.stop(this.tileQueueId); + this.tileQueueId = null; + this.tileQueue = []; }, /** @@ -422,11 +438,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * tile - {} */ destroyTile: function(tile) { - for (var i=this.tileOperations.length-1; i>=0; --i) { - if (this.tileOperations[i].scope === tile) { - this.tileOperations.splice(i, 1); - } - } + this.unqueueTile(tile); this.removeTileMonitoringHooks(tile); tile.destroy(); }, @@ -906,17 +918,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * {} The added OpenLayers.Tile */ addTile: function(bounds, position) { - var that = this; - var options = OpenLayers.Util.extend({ - draw: function() { - // clear immediately - this.clear(); - // draw in an animation frame - can be aborted - that.addTileOperation(that.tileClass.prototype.draw, this); - } - }, this.tileOptions); - return new this.tileClass(this, position, bounds, null, - this.tileSize, options); + var tile = new this.tileClass( + this, position, bounds, null, this.tileSize, this.tileOptions + ); + tile.events.register("beforedraw", this, this.queueTileDraw); + return tile; }, /** @@ -942,7 +948,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.numLoadingTiles--; this.events.triggerEvent("tileloaded"); //if that was the last tile, then trigger a 'loadend' on the layer - if (this.numLoadingTiles == 0) { + if (this.tileQueue.length === 0 && this.numLoadingTiles === 0) { this.events.triggerEvent("loadend"); if(this.backBuffer) { // the removal of the back buffer is delayed to prevent flash @@ -952,7 +958,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { 2500 ); } - } + } }; tile.events.register("loadend", this, tile.onLoadEnd); tile.events.register("unload", this, tile.onLoadEnd); diff --git a/lib/OpenLayers/Tile.js b/lib/OpenLayers/Tile.js index 81f6cb4e54..559e65d711 100644 --- a/lib/OpenLayers/Tile.js +++ b/lib/OpenLayers/Tile.js @@ -25,6 +25,10 @@ OpenLayers.Tile = OpenLayers.Class({ /** * Supported event types: + * - *beforedraw* Triggered before the tile is drawn. Used to defer + * drawing to an animation queue. To defer drawing, listeners need + * to return false, which will abort drawing. The queue handler needs + * to call (true) to actually draw the tile. * - *loadstart* Triggered when tile loading starts. * - *loadend* Triggered when tile loading ends. * - *reload* Triggered when an already loading tile is reloaded. @@ -83,7 +87,7 @@ OpenLayers.Tile = OpenLayers.Class({ * {Boolean} Is the tile loading? */ isLoading: false, - + /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. * there is no need for the base tile class to have a url. * @@ -149,15 +153,26 @@ OpenLayers.Tile = OpenLayers.Class({ * it should actually be re-drawn. This is an example implementation * that can be overridden by subclasses. The minimum thing to do here * is to call and return the result from . + * + * Parameters: + * deferred - {Boolean} When drawing was aborted by returning false from a + * *beforedraw* listener, the queue manager needs to pass true, so the + * tile will not be cleared and immediately be drawn. Otherwise, the + * tile will be cleared and a *beforedraw* event will be fired. * * Returns: * {Boolean} Whether or not the tile should actually be drawn. */ - draw: function() { - //clear tile's contents and mark as not drawn - this.clear(); - - return this.shouldDraw(); + draw: function(deferred) { + if (!deferred) { + //clear tile's contents and mark as not drawn + this.clear(); + } + var draw = this.shouldDraw(); + if (draw && !deferred) { + draw = this.events.triggerEvent("beforedraw") !== false; + } + return draw; }, /** @@ -228,10 +243,10 @@ OpenLayers.Tile = OpenLayers.Class({ /** * Method: clear * Clear the tile of any bounds/position-related data so that it can - * be reused in a new location. To be implemented by subclasses. + * be reused in a new location. */ clear: function(draw) { - // to be implemented by subclasses + // to be extended by subclasses }, CLASS_NAME: "OpenLayers.Tile" diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index d863d7dece..54e869a191 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -204,6 +204,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { * it can be reused in a new location. */ clear: function() { + OpenLayers.Tile.prototype.clear.apply(this, arguments); var img = this.imgDiv; if (img) { OpenLayers.Event.stopObservingElement(img); diff --git a/tests/Layer/ArcGIS93Rest.html b/tests/Layer/ArcGIS93Rest.html index b63d164dd7..0e11ad70fc 100644 --- a/tests/Layer/ArcGIS93Rest.html +++ b/tests/Layer/ArcGIS93Rest.html @@ -5,9 +5,7 @@