diff --git a/src/ol/map.js b/src/ol/map.js index eb16d3c95b..f78e50f861 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -83,18 +83,6 @@ ol.ENABLE_DOM = true; ol.ENABLE_WEBGL = true; -/** - * @define {number} Maximum number of simultaneously loading tiles. - */ -ol.MAXIMUM_TILES_LOADING = 8; - - -/** - * @define {number} Maximum new tile loads per frame. - */ -ol.MAXIMUM_NEW_TILE_LOADS_PER_FRAME = 2; - - /** * @enum {string} */ @@ -304,7 +292,6 @@ ol.Map = function(options) { * @type {ol.TileQueue} */ this.tileQueue_ = new ol.TileQueue( - ol.MAXIMUM_TILES_LOADING, goog.bind(this.getTilePriority, this), goog.bind(this.handleTileChange_, this)); @@ -587,23 +574,38 @@ ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) { */ ol.Map.prototype.handlePostRender = function() { - // Limit the number of tile loads if animating or interacting. - var limit = (1 << 30) - 1; // a large enough integer var frameState = this.frameState_; - if (!goog.isNull(frameState)) { - var hints = frameState.viewHints; - if (hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING]) { - limit = ol.MAXIMUM_NEW_TILE_LOADS_PER_FRAME; + + // Manage the tile queue + // Image loads are expensive and a limited resource, so try to use them + // efficiently: + // * When the view is static we allow a large number of parallel tile loads + // to complete the frame as quickly as possible. + // * When animating or interacting, image loads can cause janks, so we reduce + // the maximum number of loads per frame and limit the number of parallel + // tile loads to remain reactive to view changes and to reduce the chance of + // loading tiles that will quickly disappear from view. + var tileQueue = this.tileQueue_; + if (!tileQueue.isEmpty()) { + var maxTotalLoading = 16; + var maxNewLoads = maxTotalLoading; + if (!goog.isNull(frameState)) { + var hints = frameState.viewHints; + if (hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING]) { + maxTotalLoading = 8; + maxNewLoads = 2; + } + } + if (tileQueue.getTilesLoading() < maxTotalLoading) { + tileQueue.reprioritize(); // FIXME only call if view has changed + tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads); } } - this.tileQueue_.reprioritize(); // FIXME only call if needed - this.tileQueue_.loadMoreTiles(limit); - var postRenderFunctions = this.postRenderFunctions_; var i; for (i = 0; i < postRenderFunctions.length; ++i) { - postRenderFunctions[i](this, this.frameState_); + postRenderFunctions[i](this, frameState); } postRenderFunctions.length = 0; }; diff --git a/src/ol/tilequeue.js b/src/ol/tilequeue.js index 94274ca6d7..197567c14c 100644 --- a/src/ol/tilequeue.js +++ b/src/ol/tilequeue.js @@ -1,6 +1,7 @@ goog.provide('ol.TilePriorityFunction'); goog.provide('ol.TileQueue'); +goog.require('goog.asserts'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('ol.Coordinate'); @@ -18,15 +19,12 @@ ol.TilePriorityFunction; /** * @constructor * @extends {ol.structs.PriorityQueue} - * @param {number} maxTilesLoading Maximum number of simultaneously loading - * tiles. * @param {ol.TilePriorityFunction} tilePriorityFunction * Tile priority function. * @param {Function} tileChangeCallback * Function called on each tile change event. */ -ol.TileQueue = - function(maxTilesLoading, tilePriorityFunction, tileChangeCallback) { +ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) { goog.base( this, @@ -51,12 +49,6 @@ ol.TileQueue = */ this.tileChangeCallback_ = tileChangeCallback; - /** - * @private - * @type {number} - */ - this.maxTilesLoading_ = maxTilesLoading; - /** * @private * @type {number} @@ -67,6 +59,14 @@ ol.TileQueue = goog.inherits(ol.TileQueue, ol.structs.PriorityQueue); +/** + * @return {number} Number of tiles loading. + */ +ol.TileQueue.prototype.getTilesLoading = function() { + return this.tilesLoading_; +}; + + /** * @protected */ @@ -77,18 +77,19 @@ ol.TileQueue.prototype.handleTileChange = function() { /** - * @param {number} limit Maximum number of new tiles to load. + * @param {number} maxTotalLoading Maximum number tiles to load simultaneously. + * @param {number} maxNewLoads Maximum number of new tiles to load. */ -ol.TileQueue.prototype.loadMoreTiles = function(limit) { - var tile; - while (limit > 0 && - !this.isEmpty() && - this.tilesLoading_ < this.maxTilesLoading_) { +ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) { + var newLoads = Math.min( + maxTotalLoading - this.getTilesLoading(), maxNewLoads, this.getCount()); + goog.asserts.assert(newLoads > 0); + var i, tile; + for (i = 0; i < newLoads; ++i) { tile = /** @type {ol.Tile} */ (this.dequeue()[0]); goog.events.listenOnce(tile, goog.events.EventType.CHANGE, this.handleTileChange, false, this); tile.load(); - ++this.tilesLoading_; - --limit; } + this.tilesLoading_ += newLoads; };