diff --git a/examples/mobile-base.js b/examples/mobile-base.js index d47ae3fd88..6d8c35b1d8 100644 --- a/examples/mobile-base.js +++ b/examples/mobile-base.js @@ -3,7 +3,7 @@ var apiKey = "AqTGBsziZHIJYYxgivLBf0hVdrAk9mWO5cQcb8Yux8sW5M8c8opEC2lZqKR1ZZXf"; // initialize map when page ready -var map, tileManager; +var map; var gg = new OpenLayers.Projection("EPSG:4326"); var sm = new OpenLayers.Projection("EPSG:900913"); @@ -42,6 +42,7 @@ var init = function (onSelectFeatureFunction) { theme: null, projection: sm, numZoomLevels: 18, + tileManager: new OpenLayers.TileManager(), controls: [ new OpenLayers.Control.Attribution(), new OpenLayers.Control.TouchNavigation({ @@ -85,7 +86,6 @@ var init = function (onSelectFeatureFunction) { center: new OpenLayers.LonLat(0, 0), zoom: 1 }); - tileManager = new OpenLayers.TileManager({map: map}); var style = { fillOpacity: 0.1, diff --git a/examples/mobile-wmts-vienna.js b/examples/mobile-wmts-vienna.js index f7b8a8116d..ab593e04ce 100644 --- a/examples/mobile-wmts-vienna.js +++ b/examples/mobile-wmts-vienna.js @@ -1,4 +1,4 @@ -var map, tileManager; +var map; (function() { // Set document language for css content @@ -99,6 +99,7 @@ var map, tileManager; maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34], maxResolution: 156543.0339, numZoomLevels: 20, + tileManager: new OpenLayers.TileManager(), controls: [ new OpenLayers.Control.Navigation({ mouseWheelOptions: { @@ -124,7 +125,6 @@ var map, tileManager; } } }); - tileManager = new OpenLayers.TileManager({map: map}); layerPanel.activateControl(mapButton); layerPanel.activateControl(labelButton); diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index ba7e7006fe..8077d73c70 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -579,6 +579,10 @@ OpenLayers.Map = OpenLayers.Class({ this, this.viewPortDiv, null, this.fallThrough, {includeXY: true} ); + + if (this.tileManager) { + this.tileManager.addMap(this); + } // the layerContainerDiv is the one that holds all the layers id = this.id + "_OpenLayers_Container"; @@ -778,6 +782,11 @@ OpenLayers.Map = OpenLayers.Class({ this.viewPortDiv.parentNode.removeChild(this.viewPortDiv); } this.viewPortDiv = null; + + if (this.tileManager) { + this.tileManager.removeMap(this); + this.tileManager = null; + } if(this.eventListeners) { this.events.un(this.eventListeners); diff --git a/lib/OpenLayers/TileManager.js b/lib/OpenLayers/TileManager.js index 8d75c0f499..c4c815683a 100644 --- a/lib/OpenLayers/TileManager.js +++ b/lib/OpenLayers/TileManager.js @@ -21,26 +21,17 @@ * 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 ), or share a cache with other instances, in which case the - * cache size can be controlled by adjusting . + * 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 - * {} 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 - * . + * 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()} The maps to manage tiles on. + */ + maps: null, + /** * Property: tileQueueId - * {Number} The id of the animation. + * {Object} The ids of the loop, keyed by map id. */ tileQueueId: null, /** * Property: tileQueue - * {Array()} Tiles queued for drawing. + * {Object(Array())} 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 is set on the instance. + * {Object} Cached image elements, keyed by URL. */ - tileCache: {}, + tileCache: null, /** * Property: tileCacheIndex - * {Array} URLs of cached tiles; first entry is least recently - * used. This is shared among all TileManager instances, unless - * is set on the instance. + * {Array} 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 - {} 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 - {} + */ + 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 or to the loop. * * Parameters: + * 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=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; \ No newline at end of file +}); \ No newline at end of file diff --git a/tests/TileManager.html b/tests/TileManager.html index f135f7bba8..802640e1f9 100644 --- a/tests/TileManager.html +++ b/tests/TileManager.html @@ -6,48 +6,48 @@ function test_initialize(t) { t.plan(4); - var map = new OpenLayers.Map('map'); + var tileManager = new OpenLayers.TileManager(); + var map = new OpenLayers.Map('map', { + tileManager: tileManager + }); var layer = new OpenLayers.Layer.WMS('WMS1', '../img/blank.gif'); map.addLayer(layer); - var tileManager = new OpenLayers.TileManager({map: map}); map.setCenter([16, 48], 9); - t.ok(tileManager.tileQueue.length, "Tiles queued from layer"); + t.ok(tileManager.tileQueue[map.id].length, "Tiles queued from layer"); map.removeLayer(layer); - t.eq(tileManager.tileQueue.length, 0, "Tiles unqueued when layer is removed"); + t.eq(tileManager.tileQueue[map.id].length, 0, "Tiles unqueued when layer is removed"); map.addLayer(new OpenLayers.Layer.WMS('WMS2', '../img/blank.gif')); map.zoomIn(); - t.ok(tileManager.tileQueue.length, "Tiles queued from added layer"); + t.ok(tileManager.tileQueue[map.id].length, "Tiles queued from added layer"); map.destroy(); - t.eq(tileManager.tileQueue.length, 0, "Tiles unqueued when map is destroyed"); - tileManager.destroy(); + t.eq(tileManager.tileQueue[map.id], undefined, "Tile queue removed when map was destroyed"); } function test_destroy(t) { t.plan(3); - var map = new OpenLayers.Map('map'); + var tileManager = new OpenLayers.TileManager(); + var map = new OpenLayers.Map('map', {tileManager: tileManager}); var layer = new OpenLayers.Layer.WMS('WMS', '../img/blank.gif'); map.addLayer(layer); map.setCenter([16, 48], 9); - var numTileListeners = (layer.grid[0][0].events.listeners.reload || []).length; - var numLayerListeners = (layer.events.listeners.retile || []).length; - var numMapListeners = (map.events.listeners.removelayer || []).length; - var tileManager = new OpenLayers.TileManager({map: map}); + var numTileListeners = layer.grid[0][0].events.listeners.reload.length; + var numLayerListeners = layer.events.listeners.retile.length; + var numMapListeners = map.events.listeners.preremovelayer.length; tileManager.destroy(); - t.eq(layer.grid[0][0].events.listeners.reload.length, numTileListeners, "no listener on tile after destroy"); - t.eq(layer.events.listeners.retile.length, numLayerListeners, "no listeners on layer after destroy"); - t.eq(map.events.listeners.removelayer.length, numMapListeners, "no listeners on map after destroy"); + t.eq(layer.grid[0][0].events.listeners.reload.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(map.events.listeners.preremovelayer.length, numMapListeners - 1, "no listeners on map after destroy"); map.destroy(); } function test_manageTileCache(t) { t.plan(9); - var map = new OpenLayers.Map('map'); var tileManager = new OpenLayers.TileManager({ - map: map, cacheSize: 12 }); + var map = new OpenLayers.Map('map', {tileManager: tileManager}); layer = new OpenLayers.Layer.WMS('WMS', '../img/blank.gif'); map.addLayer(layer); map.setCenter([16, 48], 9); @@ -79,19 +79,17 @@ function test_queueTileDraw(t) { t.plan(3); - var map = new OpenLayers.Map('map'); - var tileManager = new OpenLayers.TileManager({ - map: map - }); + var tileManager = new OpenLayers.TileManager(); + var map = new OpenLayers.Map('map', {tileManager: tileManager}); layer = new OpenLayers.Layer.WMS('WMS', '../img/blank.gif'); map.addLayer(layer); map.setCenter([0, 0], 3); - var queued = tileManager.tileQueue.length; - t.ok(tileManager.tileQueue.length, "Tiles queued for drawing"); + var queued = tileManager.tileQueue[map.id].length; + t.ok(tileManager.tileQueue[map.id].length, "Tiles queued for drawing"); map.zoomIn(); - t.eq(tileManager.tileQueue.length, queued, "Tile queue has same length after immediate zoom change"); + t.eq(tileManager.tileQueue[map.id].length, queued, "Tile queue has same length after immediate zoom change"); t.delay_call(1, function() { - t.eq(tileManager.tileQueue.length, 0, "Tiles from queue processed"); + t.eq(tileManager.tileQueue[map.id].length, 0, "Tiles from queue processed"); map.destroy(); }); } @@ -100,10 +98,8 @@ t.plan(3); - var map = new OpenLayers.Map('map'); - var tileManager = new OpenLayers.TileManager({ - map: map - }); + var tileManager = new OpenLayers.TileManager(); + var map = new OpenLayers.Map('map', {tileManager: tileManager}); layer = new OpenLayers.Layer.WMS('WMS', '../img/blank.gif'); layer.destroy = function() {}; //we're going to do funky things with the grid layer.applyBackBuffer = function() {}; // backbuffering isn't under test here @@ -111,11 +107,11 @@ map.setCenter([-10, 0], 5); map.moveTo([5, 0]); - t.ok(tileManager.tileQueue.length, "tile loading deferred after moveTo"); + t.ok(tileManager.tileQueue[map.id].length, "tile loading deferred after moveTo"); map.moveTo([0, 0]); - t.ok(tileManager.tileQueue.length, "deferred again after another moveTo"); + t.ok(tileManager.tileQueue[map.id].length, "deferred again after another moveTo"); t.delay_call(1, function() { - t.eq(tileManager.tileQueue.length, 0, "tiles loaded after moveDelay"); + t.eq(tileManager.tileQueue[map.id].length, 0, "tiles loaded after moveDelay"); }); }