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.
This commit is contained in:
@@ -105,16 +105,16 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
|
||||
serverResolutions: null,
|
||||
|
||||
/**
|
||||
* Property: tileLoopId
|
||||
* {Number} - The id of the <doTileOperation> animation.
|
||||
* Property: tileQueueId
|
||||
* {Number} - The id of the <drawTileFromQueue> animation.
|
||||
*/
|
||||
tileLoopId: null,
|
||||
tileQueueId: null,
|
||||
|
||||
/**
|
||||
* Property: tileOperations
|
||||
* {Array(Object)} Pending tile operations.
|
||||
* Property: tileQueue
|
||||
* {Array(<OpenLayers.Tile>)} 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 - {<OpenLayers.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<len; iRow++) {
|
||||
var row = this.grid[iRow];
|
||||
@@ -294,7 +294,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
|
||||
var forceReTile = !this.grid.length || zoomChanged;
|
||||
|
||||
if (forceReTile) {
|
||||
this.abortTileOperations();
|
||||
this.clearTileQueue();
|
||||
}
|
||||
|
||||
// total bounds of the tiles
|
||||
@@ -375,44 +375,60 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: addTileOperation
|
||||
* Adds a tile operation to the animation queue.
|
||||
* Method: queueTileDraw
|
||||
* Adds a tile to the animation queue that will draw it.
|
||||
*
|
||||
* Parameters:
|
||||
* fn - {Function} The function to execute
|
||||
* scope - {Object} The execution scope for the function
|
||||
* evt - {Object} Listener argument of the tile's beforedraw event
|
||||
*/
|
||||
addTileOperation: function(fn, scope) {
|
||||
this.tileOperations.push({fn: fn, scope: scope});
|
||||
if (!this.tileLoopId) {
|
||||
this.tileLoopId = OpenLayers.Animation.start(
|
||||
OpenLayers.Function.bind(this.doTileOperation, this),
|
||||
queueTileDraw: function(evt) {
|
||||
this.tileQueue.push(evt.object);
|
||||
if (!this.tileQueueId) {
|
||||
this.tileQueueId = OpenLayers.Animation.start(
|
||||
OpenLayers.Function.bind(this.drawTileFromQueue, this),
|
||||
null, this.div
|
||||
);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: doTileOperation
|
||||
* Executes the first tile operation from the animation queue.
|
||||
* Method: drawTileFromQueue
|
||||
* Draws the first tile from the tileQueue, and unqueues that tile
|
||||
*/
|
||||
doTileOperation: function() {
|
||||
if (this.tileOperations.length === 0) {
|
||||
this.abortTileOperations();
|
||||
drawTileFromQueue: function() {
|
||||
if (this.tileQueue.length === 0) {
|
||||
this.clearTileQueue();
|
||||
} else {
|
||||
var operation = this.tileOperations.shift();
|
||||
operation.fn.call(operation.scope);
|
||||
var tile = this.tileQueue.shift();
|
||||
this.unqueueTile(tile);
|
||||
tile.draw(true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: abortTileOperations
|
||||
* Stops the animation queue and removes all pending operations
|
||||
* Method: unqueueTile
|
||||
* Removes all occurrences of a tile from the <tileQueue>.
|
||||
*
|
||||
* Parameters:
|
||||
* tile - {<OpenLayers.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 - {<OpenLayers.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, {
|
||||
* {<OpenLayers.Tile>} 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);
|
||||
|
||||
@@ -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 <draw>(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 <clear> and return the result from <shouldDraw>.
|
||||
*
|
||||
* 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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user