diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index 1374457df6..216625d560 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -158,8 +158,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = tileState = tile.getState(); if (tileState == ol.TileState.IDLE) { - goog.events.listenOnce(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); + this.listenToTileChange(tile); this.updateWantedTiles(frameState.wantedTiles, tileSource, tileCoord); tileCenter = tileGrid.getTileCoordCenter(tileCoord); frameState.tileQueue.enqueue(tile, tileSourceKey, tileCenter); diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index afe7463db1..da2dd226a8 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -116,8 +116,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = tileState = tile.getState(); if (tileState == ol.TileState.IDLE) { - goog.events.listenOnce(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); + this.listenToTileChange(tile); this.updateWantedTiles(frameState.wantedTiles, tileSource, tileCoord); tileCenter = tileGrid.getTileCoordCenter(tileCoord); frameState.tileQueue.enqueue(tile, tileSourceKey, tileCenter); diff --git a/src/ol/renderer/layerrenderer.js b/src/ol/renderer/layerrenderer.js index 6a6f1d4aff..736afc0605 100644 --- a/src/ol/renderer/layerrenderer.js +++ b/src/ol/renderer/layerrenderer.js @@ -40,6 +40,12 @@ ol.renderer.Layer = function(mapRenderer, layer) { */ this.layer_ = layer; + /** + * @protected + * @type {Object.} + */ + this.observedTileKeys = {}; + goog.events.listen(this.layer_, ol.Object.getChangedEventType(ol.layer.LayerProperty.BRIGHTNESS), this.handleLayerBrightnessChange, false, this); @@ -167,13 +173,29 @@ ol.renderer.Layer.prototype.handleLayerVisibleChange = function() { /** * Handle changes in tile state. * @param {goog.events.Event} event Tile change event. - * @protected + * @private */ -ol.renderer.Layer.prototype.handleTileChange = function(event) { +ol.renderer.Layer.prototype.handleTileChange_ = function(event) { var tile = /** @type {ol.Tile} */ (event.target); if (tile.getState() === ol.TileState.LOADED) { this.getMap().requestRenderFrame(); } + delete this.observedTileKeys[tile.getKey()]; +}; + + +/** + * Listen once to titileKey, le change event. + * @param {ol.Tile} tile Tile. + * @protected + */ +ol.renderer.Layer.prototype.listenToTileChange = function(tile) { + var tileKey = tile.getKey(); + if (!(tileKey in this.observedTileKeys)) { + this.observedTileKeys[tileKey] = true; + goog.events.listenOnce(tile, goog.events.EventType.CHANGE, + this.handleTileChange_, false, this); + } }; diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index 4059509e0a..0058746bab 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -391,8 +391,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = tileState = tile.getState(); if (tileState == ol.TileState.IDLE) { - goog.events.listenOnce(tile, goog.events.EventType.CHANGE, - this.handleTileChange, false, this); + this.listenToTileChange(tile); this.updateWantedTiles(frameState.wantedTiles, tileSource, tileCoord); tileCenter = tileGrid.getTileCoordCenter(tileCoord); frameState.tileQueue.enqueue(tile, tileSourceKey, tileCenter); diff --git a/src/ol/tile.js b/src/ol/tile.js index c9cf6bed73..6b8956352b 100644 --- a/src/ol/tile.js +++ b/src/ol/tile.js @@ -1,3 +1,5 @@ +// FIXME should inQueue be private? + goog.provide('ol.Tile'); goog.provide('ol.TileState'); @@ -28,6 +30,13 @@ ol.Tile = function(tileCoord) { goog.base(this); + /** + * A count incremented each time the tile is inQueue in a tile queue, + * and decremented each time the tile is dequeued from a tile queue. + * @type {number} + */ + this.inQueue = 0; + /** * @type {ol.TileCoord} */ diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index c5788df972..7e20822308 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -89,6 +89,8 @@ ol.TileQueue.prototype.dequeue_ = function() { } var tileKey = tile.getKey(); delete this.queuedTileKeys_[tileKey]; + tile.inQueue--; + goog.asserts.assert(tile.inQueue >= 0); return tile; }; @@ -110,6 +112,8 @@ ol.TileQueue.prototype.enqueue = function(tile, tileSourceKey, tileCenter) { this.heap_.push([priority, tile, tileSourceKey, tileCenter]); this.queuedTileKeys_[tileKey] = true; this.siftDown_(0, this.heap_.length - 1); + tile.inQueue++; + goog.asserts.assert(tile.inQueue > 0); } } }; @@ -246,6 +250,11 @@ ol.TileQueue.prototype.reprioritize = function() { if (priority == ol.TileQueue.DROP) { tileKey = tile.getKey(); delete this.queuedTileKeys_[tileKey]; + tile.inQueue--; + goog.asserts.assert(tile.inQueue >= 0); + if (tile.inQueue === 0) { + goog.events.removeAll(tile); + } } else { node[0] = priority; heap[n++] = node; diff --git a/test/spec/ol/tilequeue.test.js b/test/spec/ol/tilequeue.test.js index 3ca38a2981..57db2b2f8c 100644 --- a/test/spec/ol/tilequeue.test.js +++ b/test/spec/ol/tilequeue.test.js @@ -21,13 +21,20 @@ describe('ol.TileQueue', function() { } function addRandomPriorityTiles(tq, num) { + var tiles = []; var i, tile, priority; for (i = 0; i < num; i++) { tile = new ol.Tile(); + tile.toDrop = (i % 2 === 0) ? true : false; + goog.events.listen(tile, goog.events.EventType.CHANGE, + goog.nullFunction); priority = Math.floor(Math.random() * 100); tq.heap_.push([priority, tile, '', new ol.Coordinate(0, 0)]); tq.queuedTileKeys_[tile.getKey()] = true; + tile.inQueue++; + tiles.push(tile); } + return tiles; } describe('heapify', function() { @@ -45,16 +52,15 @@ describe('ol.TileQueue', function() { it('does reprioritize the array', function() { var tq = new ol.TileQueue(function() {}); - addRandomPriorityTiles(tq, 100); + var tiles = addRandomPriorityTiles(tq, 100); tq.heapify_(); // now reprioritize, changing the priority of 50 tiles and removing the // rest - var i = 0; - tq.tilePriorityFunction_ = function() { - if ((i++) % 2 === 0) { + tq.tilePriorityFunction_ = function(tile) { + if (tile.toDrop) { return ol.TileQueue.DROP; } return Math.floor(Math.random() * 100); @@ -64,10 +70,23 @@ describe('ol.TileQueue', function() { expect(tq.heap_.length).toEqual(50); expect(isHeap(tq)).toBeTruthy(); + var i, tile; + for (i = 0; i < tiles.length; ++i) { + tile = tiles[i]; + var hasListener = goog.events.hasListener(tile); + if (tile.toDrop) { + expect(hasListener).toBeFalsy(); + } else { + expect(hasListener).toBeTruthy(); + } + } + }); }); }); +goog.require('goog.events'); +goog.require('goog.events.EventType'); goog.require('ol.Coordinate'); goog.require('ol.Tile'); goog.require('ol.TileQueue');