From 950b53f6dcdf245a610ce3bfbc6650c88775d16a Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Tue, 21 May 2013 12:02:40 +0200 Subject: [PATCH 1/2] Clean up attribution control Do not use map.getLayers() anymore, but get layers from frameState.layersArray. --- src/ol/control/attributioncontrol.js | 109 ++++++++++----------------- 1 file changed, 38 insertions(+), 71 deletions(-) diff --git a/src/ol/control/attributioncontrol.js b/src/ol/control/attributioncontrol.js index 701cf77095..539c2dde15 100644 --- a/src/ol/control/attributioncontrol.js +++ b/src/ol/control/attributioncontrol.js @@ -3,17 +3,14 @@ goog.provide('ol.control.Attribution'); goog.require('goog.array'); -goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.object'); goog.require('goog.style'); goog.require('ol.Attribution'); goog.require('ol.FrameState'); -goog.require('ol.TileRange'); goog.require('ol.control.Control'); goog.require('ol.css'); -goog.require('ol.source.Source'); @@ -67,33 +64,33 @@ goog.inherits(ol.control.Attribution, ol.control.Control); /** - * @param {?Object.>} usedTiles Used - * tiles. - * @param {Object.} sources Sources. + * @param {?ol.FrameState} frameState Frame state. * @return {Object.} Attributions. */ ol.control.Attribution.prototype.getTileSourceAttributions = - function(usedTiles, sources) { + function(frameState) { /** @type {Object.} */ var attributions = {}; - var i, ii, tileRanges, tileSource, tileSourceAttribution, - tileSourceAttributionKey, tileSourceAttributions, tileSourceKey, z; - for (tileSourceKey in usedTiles) { - goog.asserts.assert(tileSourceKey in sources); - tileSource = sources[tileSourceKey]; - tileSourceAttributions = tileSource.getAttributions(); - if (goog.isNull(tileSourceAttributions)) { - continue; - } - tileRanges = usedTiles[tileSourceKey]; - for (i = 0, ii = tileSourceAttributions.length; i < ii; ++i) { - tileSourceAttribution = tileSourceAttributions[i]; - tileSourceAttributionKey = goog.getUid(tileSourceAttribution).toString(); - if (tileSourceAttributionKey in attributions) { + var i, ii, j, jj, tileRanges, tileSource, tileSourceAttribution, + tileSourceAttributionKey, tileSourceAttributions, tileSourceKey; + var layers = frameState.layersArray; + for (i = 0, ii = layers.length; i < ii; i++) { + tileSource = layers[i].getSource(); + tileSourceKey = goog.getUid(tileSource).toString(); + if (tileSourceKey in frameState.usedTiles) { + tileSourceAttributions = tileSource.getAttributions(); + if (goog.isNull(tileSourceAttributions)) { continue; } - if (tileSourceAttribution.intersectsAnyTileRange(tileRanges)) { - attributions[tileSourceAttributionKey] = tileSourceAttribution; + tileRanges = frameState.usedTiles[tileSourceKey]; + for (j = 0, jj = tileSourceAttributions.length; j < jj; j++) { + tileSourceAttribution = tileSourceAttributions[j]; + tileSourceAttributionKey = + goog.getUid(tileSourceAttribution).toString(); + if (!(tileSourceAttributionKey in attributions) && + tileSourceAttribution.intersectsAnyTileRange(tileRanges)) { + attributions[tileSourceAttributionKey] = tileSourceAttribution; + } } } } @@ -123,64 +120,34 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) { return; } - var map = this.getMap(); - - /** @type {Object.} */ - var attributionsToRemove = {}; - /** @type {Object.} */ - var sources = {}; - var layers = map.getLayers(); - if (goog.isDef(layers)) { - layers.forEach(function(layer) { - var source = layer.getSource(); - sources[goog.getUid(source).toString()] = source; - var attributions = source.getAttributions(); - if (!goog.isNull(attributions)) { - var attribution, i, ii; - for (i = 0, ii = attributions.length; i < ii; ++i) { - attribution = attributions[i]; - attributionKey = goog.getUid(attribution).toString(); - attributionsToRemove[attributionKey] = true; - } - } - }); - } - /** @type {Object.} */ var attributions = goog.object.clone(frameState.attributions); - var tileSourceAttributions = this.getTileSourceAttributions( - frameState.usedTiles, sources); - goog.object.extend(attributions, tileSourceAttributions); + goog.object.extend(attributions, this.getTileSourceAttributions(frameState)); - /** @type {Array.} */ - var attributionKeys = - goog.array.map(goog.object.getKeys(attributions), Number); - goog.array.sort(attributionKeys); - var i, ii, attributionElement, attributionKey; - for (i = 0, ii = attributionKeys.length; i < ii; ++i) { - attributionKey = attributionKeys[i].toString(); - if (attributionKey in this.attributionElements_) { + var attributionElement, attributionKey; + for (attributionKey in this.attributionElements_) { + if (attributionKey in attributions) { if (!this.attributionElementRenderedVisible_[attributionKey]) { goog.style.showElement(this.attributionElements_[attributionKey], true); this.attributionElementRenderedVisible_[attributionKey] = true; } - } else { - attributionElement = goog.dom.createElement(goog.dom.TagName.LI); - attributionElement.innerHTML = attributions[attributionKey].getHTML(); - goog.dom.appendChild(this.ulElement_, attributionElement); - this.attributionElements_[attributionKey] = attributionElement; - this.attributionElementRenderedVisible_[attributionKey] = true; + delete attributions[attributionKey]; } - delete attributionsToRemove[attributionKey]; + else { + goog.dom.removeNode(this.attributionElements_[attributionKey]); + delete this.attributionElements_[attributionKey]; + delete this.attributionElementRenderedVisible_[attributionKey]; + } + } + for (attributionKey in attributions) { + attributionElement = goog.dom.createElement(goog.dom.TagName.LI); + attributionElement.innerHTML = attributions[attributionKey].getHTML(); + goog.dom.appendChild(this.ulElement_, attributionElement); + this.attributionElements_[attributionKey] = attributionElement; + this.attributionElementRenderedVisible_[attributionKey] = true; } - for (attributionKey in attributionsToRemove) { - goog.dom.removeNode(this.attributionElements_[attributionKey]); - delete this.attributionElements_[attributionKey]; - delete this.attributionElementRenderedVisible_[attributionKey]; - } - - var renderVisible = !goog.array.isEmpty(attributionKeys); + var renderVisible = !goog.object.isEmpty(this.attributionElements_); if (this.renderedVisible_ != renderVisible) { goog.style.showElement(this.element, renderVisible); this.renderedVisible_ = renderVisible; From 6b904573a09e95b2d5a8b277e68c0e242be6e465 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Tue, 21 May 2013 12:05:48 +0200 Subject: [PATCH 2/2] Hide attribution instead of DOM removal The reasons are: - It minimizes DOM updates (most changes to the attribution are just toggling visibility, not the more expensive creation, insertion and removal of DOM elements) - The order of attributions remains stable as layer visibilities are toggled and the user interacts with the map --- src/ol/control/attributioncontrol.js | 82 +++++++++++++++++++--------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/src/ol/control/attributioncontrol.js b/src/ol/control/attributioncontrol.js index 539c2dde15..ac21544e6e 100644 --- a/src/ol/control/attributioncontrol.js +++ b/src/ol/control/attributioncontrol.js @@ -65,36 +65,44 @@ goog.inherits(ol.control.Attribution, ol.control.Control); /** * @param {?ol.FrameState} frameState Frame state. - * @return {Object.} Attributions. + * @return {Array.>} Attributions. */ -ol.control.Attribution.prototype.getTileSourceAttributions = +ol.control.Attribution.prototype.getSourceAttributions = function(frameState) { - /** @type {Object.} */ - var attributions = {}; - var i, ii, j, jj, tileRanges, tileSource, tileSourceAttribution, - tileSourceAttributionKey, tileSourceAttributions, tileSourceKey; + var i, ii, j, jj, tileRanges, source, sourceAttribution, + sourceAttributionKey, sourceAttributions, sourceKey; var layers = frameState.layersArray; + /** @type {Object.} */ + var attributions = goog.object.clone(frameState.attributions); + /** @type {Object.} */ + var hiddenAttributions = {}; for (i = 0, ii = layers.length; i < ii; i++) { - tileSource = layers[i].getSource(); - tileSourceKey = goog.getUid(tileSource).toString(); - if (tileSourceKey in frameState.usedTiles) { - tileSourceAttributions = tileSource.getAttributions(); - if (goog.isNull(tileSourceAttributions)) { + source = layers[i].getSource(); + sourceKey = goog.getUid(source).toString(); + sourceAttributions = source.getAttributions(); + if (goog.isNull(sourceAttributions)) { + continue; + } + for (j = 0, jj = sourceAttributions.length; j < jj; j++) { + sourceAttribution = sourceAttributions[j]; + sourceAttributionKey = goog.getUid(sourceAttribution).toString(); + if (sourceAttributionKey in attributions) { continue; } - tileRanges = frameState.usedTiles[tileSourceKey]; - for (j = 0, jj = tileSourceAttributions.length; j < jj; j++) { - tileSourceAttribution = tileSourceAttributions[j]; - tileSourceAttributionKey = - goog.getUid(tileSourceAttribution).toString(); - if (!(tileSourceAttributionKey in attributions) && - tileSourceAttribution.intersectsAnyTileRange(tileRanges)) { - attributions[tileSourceAttributionKey] = tileSourceAttribution; + tileRanges = frameState.usedTiles[sourceKey]; + if (goog.isDef(tileRanges) && + sourceAttribution.intersectsAnyTileRange(tileRanges)) { + if (sourceAttributionKey in hiddenAttributions) { + delete hiddenAttributions[sourceAttributionKey]; } + attributions[sourceAttributionKey] = sourceAttribution; + } + else { + hiddenAttributions[sourceAttributionKey] = sourceAttribution; } } } - return attributions; + return [attributions, hiddenAttributions]; }; @@ -120,18 +128,28 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) { return; } + var attributions = this.getSourceAttributions(frameState); /** @type {Object.} */ - var attributions = goog.object.clone(frameState.attributions); - goog.object.extend(attributions, this.getTileSourceAttributions(frameState)); + var visibleAttributions = attributions[0]; + /** @type {Object.} */ + var hiddenAttributions = attributions[1]; var attributionElement, attributionKey; for (attributionKey in this.attributionElements_) { - if (attributionKey in attributions) { + if (attributionKey in visibleAttributions) { if (!this.attributionElementRenderedVisible_[attributionKey]) { goog.style.showElement(this.attributionElements_[attributionKey], true); this.attributionElementRenderedVisible_[attributionKey] = true; } - delete attributions[attributionKey]; + delete visibleAttributions[attributionKey]; + } + else if (attributionKey in hiddenAttributions) { + if (this.attributionElementRenderedVisible_[attributionKey]) { + goog.style.showElement( + this.attributionElements_[attributionKey], false); + delete this.attributionElementRenderedVisible_[attributionKey]; + } + delete hiddenAttributions[attributionKey]; } else { goog.dom.removeNode(this.attributionElements_[attributionKey]); @@ -139,15 +157,25 @@ ol.control.Attribution.prototype.updateElement_ = function(frameState) { delete this.attributionElementRenderedVisible_[attributionKey]; } } - for (attributionKey in attributions) { + for (attributionKey in visibleAttributions) { attributionElement = goog.dom.createElement(goog.dom.TagName.LI); - attributionElement.innerHTML = attributions[attributionKey].getHTML(); + attributionElement.innerHTML = + visibleAttributions[attributionKey].getHTML(); goog.dom.appendChild(this.ulElement_, attributionElement); this.attributionElements_[attributionKey] = attributionElement; this.attributionElementRenderedVisible_[attributionKey] = true; } + for (attributionKey in hiddenAttributions) { + attributionElement = goog.dom.createElement(goog.dom.TagName.LI); + attributionElement.innerHTML = + hiddenAttributions[attributionKey].getHTML(); + goog.style.showElement(attributionElement, false); + goog.dom.appendChild(this.ulElement_, attributionElement); + this.attributionElements_[attributionKey] = attributionElement; + } - var renderVisible = !goog.object.isEmpty(this.attributionElements_); + var renderVisible = + !goog.object.isEmpty(this.attributionElementRenderedVisible_); if (this.renderedVisible_ != renderVisible) { goog.style.showElement(this.element, renderVisible); this.renderedVisible_ = renderVisible;