Configure maps with TileManger instances (and not the other way around)

This resolves issues with destroying caches on window unload, and makes
cache sharing among maps less confusing to configure.
This commit is contained in:
ahocevar
2012-11-30 10:14:08 -06:00
parent 9609bb1449
commit 781f2ac73d
5 changed files with 146 additions and 121 deletions

View File

@@ -21,26 +21,17 @@
* <moveDelay> are the configuration options to control this behavior.
*
* Caching avoids setting the src on image elements for images that have already
* been used. A TileManager instance can have a private cache (when configured
* with a <cacheSize>), or share a cache with other instances, in which case the
* cache size can be controlled by adjusting <OpenLayers.TileManager.cacheSize>.
* been used. Several maps can share a TileManager instance, in which case each
* map gets its own tile queue, but all maps share the same tile cache.
*/
OpenLayers.TileManager = OpenLayers.Class({
/**
* APIProperty: map
* {<OpenLayers.Map>} The map to manage tiles on.
*/
map: null,
/**
* APIProperty: cacheSize
* {Number} Number of image elements to keep referenced in this instance's
* private cache for fast reuse. If not set, this instance will use the
* shared cache. To configure the shared cache size, set
* <OpenLayers.TileManager.cacheSize>.
* cache for fast reuse. Default is 512.
*/
cacheSize: null,
cacheSize: 512,
/**
* APIProperty: moveDelay
@@ -56,32 +47,37 @@ OpenLayers.TileManager = OpenLayers.Class({
*/
zoomDelay: 200,
/**
* Property: maps
* {Array(<OpenLayers.Map>)} The maps to manage tiles on.
*/
maps: null,
/**
* Property: tileQueueId
* {Number} The id of the <drawTilesFromQueue> animation.
* {Object} The ids of the <drawTilesFromQueue> loop, keyed by map id.
*/
tileQueueId: null,
/**
* Property: tileQueue
* {Array(<OpenLayers.Tile>)} Tiles queued for drawing.
* {Object(Array(<OpenLayers.Tile>))} Tiles queued for drawing, keyed by
* map id.
*/
tileQueue: null,
/**
* Property: tileCache
* {Object} Cached image elements, keyed by URL. This is shared among all
* TileManager instances, unless <cacheSize> is set on the instance.
* {Object} Cached image elements, keyed by URL.
*/
tileCache: {},
tileCache: null,
/**
* Property: tileCacheIndex
* {Array<String>} URLs of cached tiles; first entry is least recently
* used. This is shared among all TileManager instances, unless
* <cacheSize> is set on the instance.
* {Array<String>} URLs of cached tiles. First entry in each array is the
* least recently used.
*/
tileCacheIndex: [],
tileCacheIndex: null,
/**
* Constructor: OpenLayers.TileManager
@@ -89,46 +85,84 @@ OpenLayers.TileManager = OpenLayers.Class({
*
* Parameters:
* options - {Object} Configuration for this instance.
*
* Required options:
* map - {<OpenLayers.Map>} The map to manage tiles on.
*/
initialize: function(options) {
OpenLayers.Util.extend(this, options);
this.tileQueue = [];
if (this.cacheSize == null) {
this.cacheSize = OpenLayers.TileManager.cacheSize;
} else {
this.tileCache = {};
this.tileCacheIndex = [];
this.maps = [];
this.tileQueueId = {};
this.tileQueue = {};
this.tileCache = {};
this.tileCacheIndex = [];
},
/**
* Method: addMap
* Binds this instance to a map
*
* Parameters:
* map - {<OpenLayers.Map>}
*/
addMap: function(map) {
if (this._destroyed) {
return;
}
var map = this.map;
this.maps.push(map);
this.tileQueue[map.id] = [];
for (var i=0, ii=map.layers.length; i<ii; ++i) {
this.addLayer({layer: map.layers[i]});
}
this.map.events.on({
map.events.on({
move: this.move,
zoomend: this.zoomEnd,
addlayer: this.addLayer,
removelayer: this.removeLayer,
preremovelayer: this.removeLayer,
scope: this
});
},
removeMap: function(map) {
if (this._destroyed) {
return;
}
window.clearTimeout(this.tileQueueId[map.id]);
if (map.layers) {
for (var i=0, ii=map.layers.length; i<ii; ++i) {
this.removeLayer({layer: map.layers[i]});
}
}
if (map.events) {
map.events.un({
move: this.move,
zoomend: this.zoomEnd,
addlayer: this.addLayer,
preremovelayer: this.removeLayer,
scope: this
});
}
delete this.tileQueue[map.id];
delete this.tileQueueId[map.id];
},
/**
* Method: move
* Handles the map's move event
*
* Parameters:
* evt - {Object} Listener argument
*/
move: function() {
this.updateTimeout(this.moveDelay);
move: function(evt) {
this.updateTimeout(evt.object, this.moveDelay);
},
/**
* Method: zoomEnd
* Handles the map's zoomEnd event
*
* Parameters:
* evt - {Object} Listener argument
*/
zoomEnd: function() {
this.updateTimeout(this.zoomDelay);
zoomEnd: function(evt) {
this.updateTimeout(evt.object, this.zoomDelay);
},
/**
@@ -160,8 +194,8 @@ OpenLayers.TileManager = OpenLayers.Class({
},
/**
* Method: addLayer
* Handles the map's removelayer event
* Method: removeLayer
* Handles the map's preremovelayer event
*
* Parameters:
* evt - {Object} The listener argument
@@ -197,14 +231,16 @@ OpenLayers.TileManager = OpenLayers.Class({
* Applies the <moveDelay> or <zoomDelay> to the <drawTilesFromQueue> loop.
*
* Parameters:
* map - {<OpenLayers.Map>} The map to update the timeout for
* delay - {Number} The delay to apply
*/
updateTimeout: function(delay) {
window.clearTimeout(this.tileQueueId);
if (this.tileQueue.length) {
this.tileQueueId = window.setTimeout(
OpenLayers.Function.bind(this.drawTilesFromQueue, this),
delay
updateTimeout: function(map, delay) {
window.clearTimeout(this.tileQueueId[map.id]);
if (this.tileQueue[map.id].length) {
this.tileQueueId[map.id] = window.setTimeout(
OpenLayers.Function.bind(function() {
this.drawTilesFromQueue(map);
}, this), delay
);
}
},
@@ -234,7 +270,8 @@ OpenLayers.TileManager = OpenLayers.Class({
* evt - {Object} The listener argument
*/
unloadTile: function(evt) {
evt.object.events.un({
var tile = evt.object;
tile.events.un({
beforedraw: this.queueTileDraw,
loadstart: this.manageTileCache,
reload: this.manageTileCache,
@@ -242,7 +279,7 @@ OpenLayers.TileManager = OpenLayers.Class({
unload: this.unloadTile,
scope: this
});
OpenLayers.Util.removeItem(this.tileQueue, evt.object);
OpenLayers.Util.removeItem(this.tileQueue[tile.layer.map.id], tile);
},
/**
@@ -260,8 +297,9 @@ OpenLayers.TileManager = OpenLayers.Class({
if (layer.url && (layer.async ||
!this.tileCache[layer.getURL(tile.bounds)])) {
// add to queue only if not in queue already
if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) {
this.tileQueue.push(tile);
var tileQueue = this.tileQueue[layer.map.id];
if (!~OpenLayers.Util.indexOf(tileQueue, tile)) {
tileQueue.push(tile);
}
queued = true;
}
@@ -272,9 +310,10 @@ OpenLayers.TileManager = OpenLayers.Class({
* Method: drawTilesFromQueue
* Draws tiles from the tileQueue, and unqueues the tiles
*/
drawTilesFromQueue: function() {
while (this.tileQueue.length) {
this.tileQueue.shift().draw(true);
drawTilesFromQueue: function(map) {
var tileQueue = this.tileQueue[map.id];
while (tileQueue.length) {
tileQueue.shift().draw(true);
}
},
@@ -288,7 +327,7 @@ OpenLayers.TileManager = OpenLayers.Class({
manageTileCache: function(evt) {
var tile = evt.object;
var img = this.tileCache[tile.url];
// only use images from the cache that are not on a layer already
// only use image from cache if it is not on a layer already
if (img && (!img.parentNode ||
OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer'))) {
tile.imgDiv = img;
@@ -331,43 +370,24 @@ OpenLayers.TileManager = OpenLayers.Class({
*/
clearTileQueue: function(evt) {
var layer = evt.object;
for (var i=this.tileQueue.length-1; i>=0; --i) {
if (this.tileQueue[i].layer === layer) {
this.tileQueue.splice(i, 1);
var tileQueue = this.tileQueue[layer.map.id];
for (var i=tileQueue.length-1; i>=0; --i) {
if (tileQueue.layer === layer) {
tileQueue.splice(i, 1);
}
}
},
destroy: function() {
window.clearTimeout(this.tileQueueId);
var map = this.map;
if (map.layers) {
for (var i=0, ii=map.layers.length; i<ii; ++i) {
this.removeLayer({layer: map.layers[i]});
}
for (var i=this.maps.length-1; i>=0; --i) {
this.removeMap(this.maps[i]);
}
if (map.events) {
map.events.un({
move: this.move,
zoomend: this.zoomEnd,
addlayer: this.addLayer,
removelayer: this.removeLayer,
scope: this
});
}
this.map = null;
this.maps = null;
this.tileQueue = null;
if (this.tileCache !== OpenLayers.TileManager.prototype.tileCache) {
this.tileCache = null;
this.tileCacheIndex = null;
}
this.tileQueueId = null;
this.tileCache = null;
this.tileCacheIndex = null;
this._destroyed = true;
}
});
/**
* APIProperty: OpenLayers.TileManager.cacheSize
* {Number} Number of image elements to keep referenced in the shared cache
* for fast reuse. Default is 512.
*/
OpenLayers.TileManager.cacheSize = 512;
});