New TileManager

This removes all tile queueing/loading specific code from Layer.Grid
and creates a new class that manages tile loading and caching.
This commit is contained in:
ahocevar
2012-11-29 14:52:53 -06:00
parent 2ee362a79b
commit 80fa251649
16 changed files with 499 additions and 311 deletions

View File

@@ -113,14 +113,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/
numLoadingTiles: 0,
/**
* APIProperty: tileLoadingDelay
* {Integer} Number of milliseconds before we shift and load
* tiles when panning. Ignored if <OpenLayers.Animation.isNative> is
* true. Default is 85.
*/
tileLoadingDelay: 85,
/**
* Property: serverResolutions
* {Array(Number}} This property is documented in subclasses as
@@ -128,32 +120,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/
serverResolutions: null,
/**
* Property: moveTimerId
* {Number} The id of the <deferMoveGriddedTiles> timer.
*/
moveTimerId: null,
/**
* Property: deferMoveGriddedTiles
* {Function} A function that defers execution of <moveGriddedTiles> by
* <tileLoadingDelay>. If <OpenLayers.Animation.isNative> is true, this
* is null and unused.
*/
deferMoveGriddedTiles: null,
/**
* Property: tileQueueId
* {Number} The id of the <drawTilesFromQueue> animation.
*/
tileQueueId: null,
/**
* Property: tileQueue
* {Array(<OpenLayers.Tile>)} Tiles queued for drawing.
*/
tileQueue: null,
/**
* Property: loading
* {Boolean} Indicates if tiles are being loaded.
@@ -241,26 +207,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
*/
className: null,
/**
* Property: tileCache
* {Object} Cached image elements, keyed by URL.
*/
tileCache: null,
/**
* Property: tileCacheIndex
* {Array<String>} URLs of cached tiles; first entry is least recently
* used.
*/
tileCacheIndex: null,
/**
* APIProperty: tileCacheSize
* {Number} Number of image elements to keep referenced for fast reuse.
* Default is 128 per layer.
*/
tileCacheSize: 128,
/**
* Register a listener for a particular event with the following syntax:
* (code)
@@ -275,6 +221,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* element - {DOMElement} A reference to layer.events.element.
*
* Supported event types:
* addtile - Triggered when a tile is added to this layer. Listeners receive
* an object as first argument, which has a tile property that
* references the tile that has been added.
* tileloadstart - Triggered when a tile starts loading. Listeners receive
* an object as first argument, which has a tile property that
* references the tile that starts loading.
@@ -289,6 +238,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* still hidden) if a tile failed to load. Listeners receive an object
* as first argument, which has a tile property that references the
* tile that could not be loaded.
* retile - Triggered when the layer recreates its tile grid.
*/
/**
@@ -342,13 +292,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
'olLayerGrid';
}
if (!OpenLayers.Animation.isNative) {
this.deferMoveGriddedTiles = OpenLayers.Function.bind(function() {
this.moveGriddedTiles(true);
this.moveTimerId = null;
}, this);
}
this.rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1;
},
@@ -375,7 +318,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
window.clearTimeout(this.moveTimerId);
this.moveTimerId = null;
}
this.clearTileQueue();
if(this.backBufferTimerId !== null) {
window.clearTimeout(this.backBufferTimerId);
this.backBufferTimerId = null;
@@ -392,7 +334,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.grid = null;
this.tileSize = null;
this.tileCache = null;
OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
},
@@ -402,7 +343,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* destroy() on each of them to kill circular references
*/
clearGrid:function() {
this.clearTileQueue();
if (this.grid) {
for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
var row = this.grid[iRow];
@@ -450,8 +390,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
// same for backbuffer and tile queue
obj.backBuffer = null;
obj.backBufferTimerId = null;
obj.tileQueue = [];
obj.tileQueueId = null;
obj.loading = false;
obj.moveTimerId = null;
@@ -599,92 +537,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
return data;
},
/**
* Method: queueTileDraw
* Adds a tile to the animation queue that will draw it.
*
* Parameters:
* evt - {Object} Listener argument of the tile's beforedraw event
*/
queueTileDraw: function(evt) {
var tile = evt.object;
var queued = false;
if (this.async || !this.url ||
!this.tileCache[this.getURL(tile.bounds)]) {
// queue only if not in tileCache already
if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) {
// add to queue only if not in queue already
this.tileQueue.push(tile);
}
queued = true;
if (!this.tileQueueId) {
this.tileQueueId = OpenLayers.Animation.start(
OpenLayers.Function.bind(this.drawTilesFromQueue, this),
null, this.div
);
}
}
return !queued;
},
/**
* Method: drawTilesFromQueue
* Draws tiles from the tileQueue, and unqueues the tiles
*/
drawTilesFromQueue: function() {
var numUrls = OpenLayers.Util.isArray(this.url) ? this.url.length : 1;
//TODO instead of using 2 * urls, we could keep track of the hosts used
// by all grid layers, and use a number that just saturates the number
// of parallel requests the browser can send
while (this.numLoadingTiles < 2 * numUrls) {
if (this.tileQueue.length === 0) {
this.clearTileQueue();
break;
}
this.tileQueue.shift().draw(true);
}
},
/**
* Method: manageTileCache
* Adds, updates, removes and fetches cache entries.
*
* Parameters:
* evt - {Object} Listener argument of the tile's loadstart event
*/
manageTileCache: function(evt) {
var tile = evt.object;
if (this.tileCache[tile.url]) {
tile.imgDiv = this.tileCache[tile.url];
OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url);
this.tileCacheIndex.push(tile.url);
tile.positionTile();
this.div.appendChild(tile.imgDiv);
} else {
tile.events.register('loadend', this, function loadend() {
tile.events.unregister('loadend', this, loadend);
if (!this.tileCache[tile.url]) {
if (this.tileCacheIndex.length >= this.tileCacheSize) {
delete this.tileCache[this.tileCacheIndex[0]];
this.tileCacheIndex.shift();
}
this.tileCache[tile.url] = tile.imgDiv;
this.tileCacheIndex.push(tile.url);
}
});
}
},
/**
* Method: clearTileQueue
* Clears the animation queue
*/
clearTileQueue: function() {
window.clearInterval(this.tileQueueId);
this.tileQueueId = null;
this.tileQueue = [];
},
/**
* Method: destroyTile
*
@@ -843,10 +695,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.div.removeChild(this.backBuffer);
this.backBuffer = null;
this.backBufferResolution = null;
if(this.backBufferTimerId !== null) {
window.clearTimeout(this.backBufferTimerId);
this.backBufferTimerId = null;
}
}
},
@@ -914,7 +762,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* bounds - {<OpenLayers.Bounds>}
*/
initSingleTile: function(bounds) {
this.clearTileQueue();
this.events.triggerEvent("retile");
//determine new tile bounds
var center = bounds.getCenterLonLat();
@@ -1047,7 +895,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* bounds - {<OpenLayers.Bounds>}
*/
initGriddedTiles:function(bounds) {
this.clearTileQueue();
this.events.triggerEvent("retile");
// work out mininum number of rows and columns; this is the number of
// tiles required to cover the viewport plus at least one for panning
@@ -1126,8 +974,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
//shave off exceess rows and colums
this.removeExcessTiles(rowidx, colidx);
var resolution = this.getServerResolution(),
immediately = resolution === this.gridResolution;
var resolution = this.getServerResolution();
// store the resolution of the grid
this.gridResolution = resolution;
@@ -1136,7 +983,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
return a.distance - b.distance;
});
for (var i=0, ii=tileData.length; i<ii; ++i) {
tileData[i].tile.draw(immediately);
tileData[i].tile.draw();
}
},
@@ -1167,11 +1014,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var tile = new this.tileClass(
this, position, bounds, null, this.tileSize, this.tileOptions
);
tile.events.on({
beforedraw: this.queueTileDraw,
loadstart: this.manageTileCache,
scope: this
});
this.events.triggerEvent("addtile", {tile: tile});
return tile;
},
@@ -1202,7 +1045,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
aborted: evt.type === "unload"
});
//if that was the last tile, then trigger a 'loadend' on the layer
if (this.tileQueue.length === 0 && this.numLoadingTiles === 0) {
if (this.numLoadingTiles === 0) {
this.loading = false;
this.events.triggerEvent("loadend");
if(this.backBuffer) {
@@ -1255,21 +1098,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* Method: moveGriddedTiles
*
* Parameter:
* deferred - {Boolean} true if this is a deferred call that should not
* be delayed.
*/
moveGriddedTiles: function(deferred) {
if (!deferred && !OpenLayers.Animation.isNative) {
if (this.moveTimerId != null) {
window.clearTimeout(this.moveTimerId);
}
this.moveTimerId = window.setTimeout(
this.deferMoveGriddedTiles, this.tileLoadingDelay
);
return;
}
moveGriddedTiles: function() {
var buffer = this.buffer + 1;
while(true) {
var tlTile = this.grid[0][0];