From 41ccb4dfcdfaf4eb1f1964c27a35de275fd6d701 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 16 Jan 2013 11:48:22 +0100 Subject: [PATCH 01/29] Add ol.Rectangle.extend --- src/ol/rectangle.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ol/rectangle.js b/src/ol/rectangle.js index 2b8dbc3997..d15f1d7a18 100644 --- a/src/ol/rectangle.js +++ b/src/ol/rectangle.js @@ -41,6 +41,17 @@ ol.Rectangle = function(minX, minY, maxX, maxY) { }; +/** + * @param {ol.Rectangle} rectangle Rectangle. + */ +ol.Rectangle.prototype.extend = function(rectangle) { + this.minX = Math.min(this.minX, rectangle.minX); + this.minY = Math.min(this.minY, rectangle.minY); + this.maxX = Math.max(this.maxX, rectangle.maxX); + this.maxY = Math.max(this.maxY, rectangle.maxY); +}; + + /** * @return {ol.Coordinate} Center. */ From 9fbabc3696d657ef67ab46e356e2db28697f8b61 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 16 Jan 2013 16:34:31 +0100 Subject: [PATCH 02/29] Refactor attribution control --- src/ol/attribution.js | 50 +- src/ol/control/attributioncontrol.js | 506 +++++------------- src/ol/coveragearea.js | 55 -- src/ol/framestate.js | 2 + src/ol/map.js | 1 + src/ol/renderer/dom/domtilelayerrenderer.js | 15 + .../renderer/webgl/webgltilelayerrenderer.js | 15 + src/ol/source/bingmapssource.js | 28 +- src/ol/source/tilejsonsource.js | 28 +- src/ol/tilecoveragearea.js | 69 --- 10 files changed, 224 insertions(+), 545 deletions(-) delete mode 100644 src/ol/coveragearea.js delete mode 100644 src/ol/tilecoveragearea.js diff --git a/src/ol/attribution.js b/src/ol/attribution.js index acf59930e3..4b4c8886e2 100644 --- a/src/ol/attribution.js +++ b/src/ol/attribution.js @@ -1,17 +1,13 @@ goog.provide('ol.Attribution'); -goog.require('ol.CoverageArea'); -goog.require('ol.Projection'); - /** * @constructor * @param {string} html HTML. - * @param {Array.=} opt_coverageAreas Coverage areas. - * @param {ol.Projection=} opt_projection Projection. + * @param {Object.>=} opt_tileRanges Tile ranges. */ -ol.Attribution = function(html, opt_coverageAreas, opt_projection) { +ol.Attribution = function(html, opt_tileRanges) { /** * @private @@ -21,38 +17,40 @@ ol.Attribution = function(html, opt_coverageAreas, opt_projection) { /** * @private - * @type {Array.} + * @type {Object.>} */ - this.coverageAreas_ = opt_coverageAreas || null; + this.tileRanges_ = opt_tileRanges || null; - /** - * @private - * @type {ol.Projection} - */ - this.projection_ = opt_projection || null; - -}; - - -/** - * @return {Array.} Coverage areas. - */ -ol.Attribution.prototype.getCoverageAreas = function() { - return this.coverageAreas_; }; /** * @return {string} HTML. */ -ol.Attribution.prototype.getHtml = function() { +ol.Attribution.prototype.getHTML = function() { return this.html_; }; /** - * @return {ol.Projection} Projection. + * @param {Object.} tileRanges Tile ranges. + * @return {boolean} Intersects any tile range. */ -ol.Attribution.prototype.getProjection = function() { - return this.projection_; +ol.Attribution.prototype.intersectsAnyTileRange = function(tileRanges) { + if (goog.isNull(this.tileRanges_)) { + return true; + } + var i, tileRange, z; + for (z in tileRanges) { + if (!(z in this.tileRanges_)) { + continue; + } + tileRange = tileRanges[z]; + for (i = 0; i < this.tileRanges_[z].length; ++i) { + if (this.tileRanges_[z][i].intersects(tileRange)) { + return true; + } + } + } + return false; }; diff --git a/src/ol/control/attributioncontrol.js b/src/ol/control/attributioncontrol.js index 27f5a7f836..f7148722e8 100644 --- a/src/ol/control/attributioncontrol.js +++ b/src/ol/control/attributioncontrol.js @@ -1,24 +1,15 @@ -// FIXME handle rotation // FIXME handle date line wrap -// FIXME handle layer order -// FIXME check clean-up code -// FIXME works for View2D only goog.provide('ol.control.Attribution'); +goog.require('goog.array'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.events'); -goog.require('goog.events.EventType'); goog.require('goog.object'); goog.require('goog.style'); -goog.require('ol.Collection'); -goog.require('ol.CoverageArea'); -goog.require('ol.TileCoverageArea'); -goog.require('ol.View2D'); -goog.require('ol.View2DProperty'); +goog.require('ol.MapEventType'); goog.require('ol.control.Control'); -goog.require('ol.layer.Layer'); @@ -36,324 +27,50 @@ ol.control.Attribution = function(attributionOptions) { 'class': 'ol-attribution' }, this.ulElement_); - /** - * @private - * @type {Object.} - */ - this.layerVisibleChangeListenerKeys_ = {}; - - /** - * @private - * @type {Object.} - */ - this.attributionElements_ = {}; - - /** - * @private - * @type {Object.>} - */ - this.coverageAreass_ = {}; - - /** - * @private - * @type {Array.} - */ - this.mapListenerKeys_ = null; - - /** - * @private - * @type {Array.} - */ - this.layersListenerKeys_ = null; - - /** - * @private - * @type {Array.} - */ - this.viewListenerKeys_ = null; - goog.base(this, { element: element, map: attributionOptions.map, target: attributionOptions.target }); + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = true; + + /** + * @private + * @type {Object.} + */ + this.attributionElements_ = {}; + + /** + * @private + * @type {Object.} + */ + this.attributionElementRenderedVisible_ = {}; + + /** + * @private + * @type {Array.} + */ + this.listenerKeys_ = null; + }; goog.inherits(ol.control.Attribution, ol.control.Control); /** - * @param {ol.layer.Layer} layer Layer. - * @protected + * @param {ol.MapEvent} mapEvent Map event. */ -ol.control.Attribution.prototype.addLayer = function(layer) { - - var layerKey = goog.getUid(layer); - - this.layerVisibleChangeListenerKeys_[layerKey] = goog.events.listen( - layer, ol.Object.getChangedEventType(ol.layer.LayerProperty.VISIBLE), - this.handleLayerVisibleChanged, false, this); - - if (layer.getSource().isReady()) { - this.createAttributionElementsForLayer_(layer); +ol.control.Attribution.prototype.handleMapPostrender = function(mapEvent) { + var frameState = mapEvent.frameState; + if (goog.isNull(frameState)) { + this.updateElement_(null); } else { - goog.events.listenOnce(layer, goog.events.EventType.LOAD, - this.handleLayerLoad, false, this); + this.updateElement_(frameState.tileUsage); } - -}; - - -/** - * @param {ol.layer.Layer} layer Layer. - * @private - */ -ol.control.Attribution.prototype.createAttributionElementsForLayer_ = - function(layer) { - - var source = layer.getSource(); - var attributions = source.getAttributions(); - if (goog.isNull(attributions)) { - return; - } - - var map = this.getMap(); - var mapIsDef = map.isDef(); - var layerVisible = layer.getVisible(); - - var attributionVisibilities; - if (mapIsDef && layerVisible) { - var mapSize = /** @type {ol.Size} */ (map.getSize()); - // FIXME works for View2D only - var view = map.getView(); - goog.asserts.assert(view instanceof ol.View2D); - var mapExtent = view.getExtent(mapSize); - var mapProjection = /** @type {ol.Projection} */ (view.getProjection()); - var mapResolution = /** @type {number} */ (view.getResolution()); - attributionVisibilities = this.getLayerAttributionVisiblities_( - layer, mapExtent, mapResolution, mapProjection); - } else { - attributionVisibilities = null; - } - - goog.array.forEach(attributions, function(attribution) { - - var attributionKey = goog.getUid(attribution); - - var attributionElement = goog.dom.createElement(goog.dom.TagName.LI); - attributionElement.innerHTML = attribution.getHtml(); - - if (!mapIsDef || - !layerVisible || - goog.isNull(attributionVisibilities) || - !attributionVisibilities[attributionKey]) { - if (goog.style.isElementShown(attributionElement)) { - goog.style.showElement(attributionElement, false); - } - } - - goog.dom.appendChild(this.ulElement_, attributionElement); - - this.attributionElements_[attributionKey] = attributionElement; - - }, this); - -}; - - -/** - * @param {ol.layer.Layer} layer Layer. - * @param {ol.Extent} mapExtent View extent. - * @param {number} mapResolution View resolution. - * @param {ol.Projection} mapProjection Map projection. - * @return {Object.} Attribution visibilities. - * @private - */ -ol.control.Attribution.prototype.getLayerAttributionVisiblities_ = - function(layer, mapExtent, mapResolution, mapProjection) { - - var source = layer.getSource(); - var attributions = source.getAttributions(); - - if (goog.isNull(attributions)) { - return null; - } - - var mapZ; - if (source instanceof ol.source.TileSource) { - var tileSource = /** @type {ol.source.TileSource} */ (source); - var tileGrid = tileSource.getTileGrid(); - mapZ = tileGrid.getZForResolution(mapResolution); - } - - var attributionVisibilities = {}; - goog.array.forEach(attributions, function(attribution) { - - var attributionKey = goog.getUid(attribution); - - var attributionVisible = true; - - var coverageAreas; - if (attributionKey in this.coverageAreass_) { - coverageAreas = this.coverageAreass_[attributionKey]; - } else { - var attributionProjection = attribution.getProjection(); - coverageAreas = attribution.getCoverageAreas(); - if (!goog.isNull(coverageAreas) && - !ol.Projection.equivalent(attributionProjection, mapProjection)) { - var transformFn = ol.Projection.getTransform( - attributionProjection, mapProjection); - if (transformFn !== ol.Projection.cloneTransform) { - coverageAreas = goog.array.map(coverageAreas, function(coverageArea) { - return coverageArea.transform(transformFn); - }); - } - } - this.coverageAreass_[attributionKey] = coverageAreas; - } - - if (!goog.isNull(coverageAreas)) { - if (source instanceof ol.source.TileSource) { - attributionVisible = goog.array.some( - coverageAreas, - function(coverageArea, index) { - return coverageArea.intersectsExtentAndZ(mapExtent, mapZ); - }); - } else { - attributionVisible = goog.array.some( - coverageAreas, - function(coverageArea) { - return coverageArea.intersectsExtentAndResolution( - mapExtent, mapResolution); - }); - } - } - - attributionVisibilities[attributionKey] = attributionVisible; - - }, this); - - return attributionVisibilities; - -}; - - -/** - * @param {goog.events.Event} event Event. - */ -ol.control.Attribution.prototype.handleLayerLoad = function(event) { - var layer = /** @type {ol.layer.Layer} */ (event.target); - this.createAttributionElementsForLayer_(layer); -}; - - -/** - * @param {goog.events.Event} event Event. - * @protected - */ -ol.control.Attribution.prototype.handleLayerVisibleChanged = function(event) { - var layer = /** @type {ol.layer.Layer} */ (event.target); - this.updateLayerAttributionsVisibility_(layer); - -}; - - -/** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @protected - */ -ol.control.Attribution.prototype.handleLayersAdd = function(collectionEvent) { - var layer = /** @type {ol.layer.Layer} */ (collectionEvent.elem); - this.addLayer(layer); -}; - - -/** - * @param {ol.CollectionEvent} collectionEvent Collection event. - * @protected - */ -ol.control.Attribution.prototype.handleLayersRemove = - function(collectionEvent) { - var layer = /** @type {ol.layer.Layer} */ (collectionEvent.elem); - this.removeLayer(layer); -}; - - -/** - * @protected - */ -ol.control.Attribution.prototype.handleMapViewChanged = function() { - if (!goog.isNull(this.viewListenerKeys_)) { - goog.array.forEach(this.viewListenerKeys_, goog.events.unlistenByKey); - this.viewListenerKeys_ = null; - } - var map = this.getMap(); - goog.asserts.assert(!goog.isNull(map)); - var view = map.getView(); - if (!goog.isNull(view)) { - // FIXME works for View2D only - goog.asserts.assert(view instanceof ol.View2D); - this.viewListenerKeys_ = [ - goog.events.listen( - view, ol.Object.getChangedEventType(ol.View2DProperty.CENTER), - this.updateAttributions, false, this), - goog.events.listen( - view, ol.Object.getChangedEventType(ol.View2DProperty.RESOLUTION), - this.updateAttributions, false, this) - ]; - } -}; - - -/** - * @protected - */ -ol.control.Attribution.prototype.handleMapLayersChanged = function() { - if (!goog.isNull(this.layersListenerKeys_)) { - goog.array.forEach(this.layersListenerKeys_, goog.events.unlistenByKey); - this.layersListenerKeys_ = null; - } - goog.object.forEach(this.attributionElements_, function(attributionElement) { - goog.dom.removeNode(attributionElement); - }, this); - this.attributionElements_ = {}; - this.coverageAreass_ = {}; - var map = this.getMap(); - var layers = map.getLayers(); - if (goog.isDefAndNotNull(layers)) { - layers.forEach(this.addLayer, this); - this.layersListenerKeys_ = [ - goog.events.listen(layers, ol.CollectionEventType.ADD, - this.handleLayersAdd, false, this), - goog.events.listen(layers, ol.CollectionEventType.REMOVE, - this.handleLayersRemove, false, this) - ]; - } -}; - - -/** - * @param {ol.layer.Layer} layer Layer. - * @protected - */ -ol.control.Attribution.prototype.removeLayer = function(layer) { - - var layerKey = goog.getUid(layer); - - goog.events.unlistenByKey(this.layerVisibleChangeListenerKeys_[layerKey]); - delete this.layerVisibleChangeListenerKeys_[layerKey]; - - goog.array.forEach( - layer.getSource().getAttributions(), - function(attribution) { - var attributionKey = goog.getUid(attribution); - delete this.coverageAreass_[attributionKey]; - var attributionElement = this.attributionElements_[attributionKey]; - goog.dom.removeNode(attributionElement); - delete this.attributionElements_[attributionKey]; - }, - this); - }; @@ -361,79 +78,116 @@ ol.control.Attribution.prototype.removeLayer = function(layer) { * @inheritDoc */ ol.control.Attribution.prototype.setMap = function(map) { - if (!goog.isNull(this.mapListenerKeys_)) { - goog.array.forEach(this.mapListenerKeys_, goog.events.unlistenByKey); + if (!goog.isNull(this.listenerKeys_)) { + goog.array.forEach(this.listenerKeys_, goog.events.unlistenByKey); + this.listenerKeys_ = null; } - this.mapListenerKeys_ = null; goog.base(this, 'setMap', map); if (!goog.isNull(map)) { - this.mapListenerKeys_ = [ - goog.events.listen( - map, ol.Object.getChangedEventType(ol.MapProperty.LAYERS), - this.handleMapLayersChanged, false, this), - goog.events.listen( - map, ol.Object.getChangedEventType(ol.MapProperty.SIZE), - this.updateAttributions, false, this), - goog.events.listen( - map, ol.Object.getChangedEventType(ol.MapProperty.VIEW), - this.updateAttributions, false, this) + this.listenerKeys_ = [ + goog.events.listen(map, ol.MapEventType.POSTRENDER, + this.handleMapPostrender, false, this) ]; - this.handleMapViewChanged(); - this.handleMapLayersChanged(); } }; /** - * @protected - */ -ol.control.Attribution.prototype.updateAttributions = function() { - - var map = this.getMap(); - var layers = map.getLayers(); - layers.forEach(function(layer) { - this.updateLayerAttributionsVisibility_(layer); - }, this); - -}; - - -/** - * @param {ol.layer.Layer} layer Layer. * @private + * @param {?Object.>} tileUsage Tile + * usage. */ -ol.control.Attribution.prototype.updateLayerAttributionsVisibility_ = - function(layer) { +ol.control.Attribution.prototype.updateElement_ = function(tileUsage) { + + if (goog.isNull(tileUsage)) { + if (this.renderedVisible_) { + goog.style.showElement(this.element, false); + this.renderedVisible_ = false; + } + return; + } + var map = this.getMap(); - if (map.isDef() && layer.getVisible()) { - var mapSize = /** @type {ol.Size} */ (map.getSize()); - var view = map.getView(); - // FIXME works for View2D only - goog.asserts.assert(view instanceof ol.View2D); - var mapExtent = view.getExtent(mapSize); - var mapProjection = /** @type {ol.Projection} */ (view.getProjection()); - var mapResolution = /** @type {number} */ (view.getResolution()); - var attributionVisibilities = this.getLayerAttributionVisiblities_( - layer, mapExtent, mapResolution, mapProjection); - goog.object.forEach( - attributionVisibilities, - function(attributionVisible, attributionKey) { - var attributionElement = this.attributionElements_[attributionKey]; - if (goog.style.isElementShown(attributionElement) != - attributionVisible) { - goog.style.showElement(attributionElement, attributionVisible); - } - }, - this); - } else { - var source = layer.getSource(); - var attributions = source.getAttributions(); - if (!goog.isNull(attributions)) { - goog.array.forEach(attributions, function(attribution) { - var attributionKey = goog.getUid(attribution); - var attributionElement = this.attributionElements_[attributionKey]; - goog.style.showElement(attributionElement, false); - }, this); + + /** @type {Object.} */ + var attributionsToRemove = {}; + /** @type {Object.} */ + var tileSources = {}; + var layers = map.getLayers(); + if (goog.isDef(layers)) { + layers.forEach(function(layer) { + var source = layer.getSource(); + if (source instanceof ol.source.TileSource) { + tileSources[goog.getUid(source).toString()] = source; + } + var attributions = source.getAttributions(); + if (!goog.isNull(attributions)) { + var attribution, i; + for (i = 0; i < attributions.length; ++i) { + attribution = attributions[i]; + attributionKey = goog.getUid(attribution).toString(); + attributionsToRemove[attributionKey] = true; + } + } + }); + } + + /** @type {Object.} */ + var attributions = {}; + var i, tileRanges, tileSource, tileSourceAttribution, + tileSourceAttributionKey, tileSourceAttributions, tileSourceKey, z; + for (tileSourceKey in tileUsage) { + goog.asserts.assert(tileSourceKey in tileSources); + tileSource = tileSources[tileSourceKey]; + tileSourceAttributions = tileSource.getAttributions(); + if (goog.isNull(tileSourceAttributions)) { + continue; + } + tileRanges = tileUsage[tileSourceKey]; + for (i = 0; i < tileSourceAttributions.length; ++i) { + tileSourceAttribution = tileSourceAttributions[i]; + tileSourceAttributionKey = goog.getUid(tileSourceAttribution).toString(); + if (tileSourceAttributionKey in attributions) { + continue; + } + if (tileSourceAttribution.intersectsAnyTileRange(tileRanges)) { + attributions[tileSourceAttributionKey] = tileSourceAttribution; + } } } + + /** @type {Array.} */ + var attributionKeys = + goog.array.map(goog.object.getKeys(attributions), Number); + goog.array.sort(attributionKeys); + var attributionElement, attributionKey; + for (i = 0; i < attributionKeys.length; ++i) { + attributionKey = attributionKeys[i].toString(); + if (attributionKey in this.attributionElements_) { + 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 attributionsToRemove[attributionKey]; + } + + for (attributionKey in attributionsToRemove) { + goog.dom.removeNode(this.attributionElements_[attributionKey]); + delete this.attributionElements_[attributionKey]; + delete this.attributionElementRenderedVisible_[attributionKey]; + } + + var renderVisible = !goog.array.isEmpty(attributionKeys); + if (this.renderedVisible_ != renderVisible) { + goog.style.showElement(this.element, renderVisible); + this.renderedVisible_ = renderVisible; + } + }; diff --git a/src/ol/coveragearea.js b/src/ol/coveragearea.js deleted file mode 100644 index 55fe982796..0000000000 --- a/src/ol/coveragearea.js +++ /dev/null @@ -1,55 +0,0 @@ -goog.provide('ol.CoverageArea'); - -goog.require('ol.Extent'); - - - -/** - * Represents a rectangular area. - * - * @constructor - * @param {ol.Extent} extent Extent. - */ -ol.CoverageArea = function(extent) { - - /** - * @type {ol.Extent} - */ - this.extent = extent; - -}; - - -/** - * @param {ol.Extent} extent Extent. - * @return {boolean} Intersects. - */ -ol.CoverageArea.prototype.intersectsExtent = function(extent) { - return this.extent.intersects(extent); -}; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} resolution Resolution. - * @return {boolean} Intersects. - */ -ol.CoverageArea.prototype.intersectsExtentAndResolution = goog.abstractMethod; - - -/** - * @param {ol.Extent} extent Extent. - * @param {number} z Z. - * @return {boolean} Intersects. - */ -ol.CoverageArea.prototype.intersectsExtentAndZ = goog.abstractMethod; - - -/** - * @param {ol.TransformFunction} transformFn Transform. - * @return {ol.CoverageArea} Transformed coverage area. - */ -ol.CoverageArea.prototype.transform = function(transformFn) { - var extent = this.extent.transform(transformFn); - return new ol.CoverageArea(extent); -}; diff --git a/src/ol/framestate.js b/src/ol/framestate.js index d84f4de831..574fefe20f 100644 --- a/src/ol/framestate.js +++ b/src/ol/framestate.js @@ -10,6 +10,7 @@ goog.require('ol.Coordinate'); goog.require('ol.Extent'); goog.require('ol.Size'); goog.require('ol.TileQueue'); +goog.require('ol.TileRange'); goog.require('ol.View2DState'); goog.require('ol.layer.LayerState'); @@ -25,6 +26,7 @@ goog.require('ol.layer.LayerState'); * postRenderFunctions: Array., * size: ol.Size, * tileQueue: ol.TileQueue, + * tileUsage: Object.>, * time: number, * view2DState: ol.View2DState, * viewHints: Array.}} diff --git a/src/ol/map.js b/src/ol/map.js index f82253eeaf..383529adeb 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -617,6 +617,7 @@ ol.Map.prototype.renderFrame_ = function(time) { postRenderFunctions: [], size: size, tileQueue: this.tileQueue_, + tileUsage: {}, view2DState: view2DState, viewHints: viewHints, time: time diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index cdbfb92305..f80ca05e04 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -89,6 +89,21 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = var tileRange = tileGrid.getTileRangeForExtentAndResolution( frameState.extent, tileResolution); + // FIXME should also consider interim tiles + var tileUsage = frameState.tileUsage; + var tileSourceKey = goog.getUid(tileSource).toString(); + var zKey = z.toString(); + if (tileSourceKey in tileUsage) { + if (z in tileUsage[tileSourceKey]) { + tileUsage[tileSourceKey][zKey].extend(tileRange); + } else { + tileUsage[tileSourceKey][zKey] = tileRange; + } + } else { + tileUsage[tileSourceKey] = {}; + tileUsage[tileSourceKey][zKey] = tileRange; + } + /** @type {Object.>} */ var tilesToDrawByZ = {}; tilesToDrawByZ[z] = {}; diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index 43f83838fd..e9ddb277b3 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -276,6 +276,21 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = var tileRange = tileGrid.getTileRangeForExtentAndResolution( frameState.extent, tileResolution); + // FIXME should also consider interim tiles + var tileUsage = frameState.tileUsage; + var tileSourceKey = goog.getUid(tileSource).toString(); + var zKey = z.toString(); + if (tileSourceKey in tileUsage) { + if (z in tileUsage[tileSourceKey]) { + tileUsage[tileSourceKey][zKey].extend(tileRange); + } else { + tileUsage[tileSourceKey][zKey] = tileRange; + } + } else { + tileUsage[tileSourceKey] = {}; + tileUsage[tileSourceKey][zKey] = tileRange; + } + var framebufferExtent; if (!goog.isNull(this.renderedTileRange_) && diff --git a/src/ol/source/bingmapssource.js b/src/ol/source/bingmapssource.js index 7693cb81d9..a700ba09d2 100644 --- a/src/ol/source/bingmapssource.js +++ b/src/ol/source/bingmapssource.js @@ -5,7 +5,7 @@ goog.require('goog.Uri'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.net.Jsonp'); -goog.require('ol.TileCoverageArea'); +goog.require('ol.TileRange'); goog.require('ol.source.ImageTileSource'); goog.require('ol.tilegrid.XYZ'); @@ -118,21 +118,35 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse = }; }))); - var projection = ol.Projection.getFromCode('EPSG:4326'); + var transform = ol.Projection.getTransform( + ol.Projection.getFromCode('EPSG:4326'), this.getProjection()); var attributions = goog.array.map( resource.imageryProviders, function(imageryProvider) { var html = imageryProvider.attribution; - var coverageAreas = goog.array.map( + /** @type {Object.>} */ + var tileRanges = {}; + goog.array.forEach( imageryProvider.coverageAreas, function(coverageArea) { - var bbox = coverageArea.bbox; - var extent = new ol.Extent(bbox[1], bbox[0], bbox[3], bbox[2]); var minZ = coverageArea.zoomMin; var maxZ = coverageArea.zoomMax; - return new ol.TileCoverageArea(tileGrid, extent, minZ, maxZ); + var bbox = coverageArea.bbox; + var epsg4326Extent = + new ol.Extent(bbox[1], bbox[0], bbox[3], bbox[2]); + var extent = epsg4326Extent.transform(transform); + var tileRange, z, zKey; + for (z = minZ; z <= maxZ; ++z) { + zKey = z.toString(); + tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); + if (zKey in tileRanges) { + tileRanges[zKey].push(tileRange); + } else { + tileRanges[zKey] = [tileRange]; + } + } }); - return new ol.Attribution(html, coverageAreas, projection); + return new ol.Attribution(html, tileRanges); }); this.setAttributions(attributions); diff --git a/src/ol/source/tilejsonsource.js b/src/ol/source/tilejsonsource.js index 81eacaf7a4..af306b0d26 100644 --- a/src/ol/source/tilejsonsource.js +++ b/src/ol/source/tilejsonsource.js @@ -14,7 +14,6 @@ goog.require('goog.events.EventType'); goog.require('goog.net.jsloader'); goog.require('goog.string'); goog.require('ol.Projection'); -goog.require('ol.TileCoverageArea'); goog.require('ol.TileUrlFunction'); goog.require('ol.source.ImageTileSource'); goog.require('ol.tilegrid.XYZ'); @@ -98,17 +97,17 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function() { if (goog.isDef(tileJSON.scheme)) { goog.asserts.assert(tileJSON.scheme == 'xyz'); } - var minzoom = tileJSON.minzoom || 0; - goog.asserts.assert(minzoom === 0); // FIXME - var maxzoom = tileJSON.maxzoom || 22; + var minZoom = tileJSON.minzoom || 0; + goog.asserts.assert(minZoom === 0); // FIXME + var maxZoom = tileJSON.maxzoom || 22; var tileGrid = new ol.tilegrid.XYZ({ - maxZoom: maxzoom + maxZoom: maxZoom }); this.tileGrid = tileGrid; this.tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform( function(tileCoord) { - if (tileCoord.z < minzoom || maxzoom < tileCoord.z) { + if (tileCoord.z < minZoom || maxZoom < tileCoord.z) { return null; } var n = 1 << tileCoord.z; @@ -129,13 +128,18 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function() { ol.TileUrlFunction.createFromTemplates(tileJSON.tiles)); if (goog.isDef(tileJSON.attribution)) { - var coverageAreas = [ - new ol.TileCoverageArea(tileGrid, epsg4326Extent, minzoom, maxzoom) - ]; - var coverageAreaProjection = epsg4326Projection; + var attributionExtent = goog.isNull(extent) ? + epsg4326Projection.getExtent() : extent; + /** @type {Object.>} */ + var tileRanges = {}; + var z, zKey; + for (z = minZoom; z <= maxZoom; ++z) { + zKey = z.toString(); + tileRanges[zKey] = + [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)]; + } this.setAttributions([ - new ol.Attribution( - tileJSON.attribution, coverageAreas, coverageAreaProjection) + new ol.Attribution(tileJSON.attribution, tileRanges) ]); } diff --git a/src/ol/tilecoveragearea.js b/src/ol/tilecoveragearea.js deleted file mode 100644 index f09e1d1797..0000000000 --- a/src/ol/tilecoveragearea.js +++ /dev/null @@ -1,69 +0,0 @@ -goog.provide('ol.TileCoverageArea'); - -goog.require('ol.CoverageArea'); -goog.require('ol.Extent'); -goog.require('ol.tilegrid.TileGrid'); - - - -/** - * @constructor - * @extends {ol.CoverageArea} - * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. - * @param {ol.Extent} extent Extent. - * @param {number} minZ Minimum Z. - * @param {number} maxZ Maximum Z. - */ -ol.TileCoverageArea = function(tileGrid, extent, minZ, maxZ) { - - goog.base(this, extent); - - /** - * @private - * @type {ol.tilegrid.TileGrid} - */ - this.tileGrid_ = tileGrid; - - /** - * @private - * @type {number} - */ - this.minZ_ = minZ; - - /** - * @private - * @type {number} - */ - this.maxZ_ = maxZ; - -}; -goog.inherits(ol.TileCoverageArea, ol.CoverageArea); - - -/** - * @inheritDoc - */ -ol.TileCoverageArea.prototype.intersectsExtentAndResolution = - function(extent, resolution) { - var z = this.tileGrid_.getZForResolution(resolution); - return this.intersectsExtentAndZ(extent, z); -}; - - -/** - * @inheritDoc - */ -ol.TileCoverageArea.prototype.intersectsExtentAndZ = function(extent, z) { - return this.minZ_ <= z && z <= this.maxZ_ && this.intersectsExtent(extent); -}; - - -/** - * @param {ol.TransformFunction} transformFn Transform. - * @return {ol.TileCoverageArea} Transformed tile coverage area. - */ -ol.TileCoverageArea.prototype.transform = function(transformFn) { - var extent = this.extent.transform(transformFn); - return new ol.TileCoverageArea( - this.tileGrid_, extent, this.minZ_, this.maxZ_); -}; From 1278ccb942acc9e09cd3c23f342634de80e57f8d Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 16 Jan 2013 17:10:32 +0100 Subject: [PATCH 03/29] Add default tile size @define, refs #114, fixes #120 --- src/ol/tilegrid/tilegrid.js | 21 +++++++++++++++++---- src/ol/tilegrid/xyztilegrid.js | 5 +++-- src/ol/view2d.js | 5 +++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/ol/tilegrid/tilegrid.js b/src/ol/tilegrid/tilegrid.js index 8c0f0a1e5d..6edd839fa9 100644 --- a/src/ol/tilegrid/tilegrid.js +++ b/src/ol/tilegrid/tilegrid.js @@ -14,6 +14,12 @@ goog.require('ol.TileRange'); goog.require('ol.array'); +/** + * @define {number} Default tile size. + */ +ol.DEFAULT_TILE_SIZE = 256; + + /** * @typedef {{extent: (ol.Extent|undefined), * origin: (ol.Coordinate|undefined), @@ -75,7 +81,8 @@ ol.tilegrid.TileGrid = function(tileGridOptions) { * @type {ol.Size} */ this.tileSize_ = goog.isDef(tileGridOptions.tileSize) ? - tileGridOptions.tileSize : new ol.Size(256, 256); + tileGridOptions.tileSize : + new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE); }; @@ -321,21 +328,27 @@ ol.tilegrid.TileGrid.prototype.getZForResolution = function(resolution) { /** * @param {ol.Projection} projection Projection. * @param {number=} opt_maxZoom Maximum zoom level (optional). Default is 18. + * @param {ol.Size=} opt_tileSize Tile size. * @return {ol.tilegrid.TileGrid} TileGrid instance. */ -ol.tilegrid.createForProjection = function(projection, opt_maxZoom) { +ol.tilegrid.createForProjection = + function(projection, opt_maxZoom, opt_tileSize) { var projectionExtent = projection.getExtent(); var size = Math.max( projectionExtent.maxX - projectionExtent.minX, projectionExtent.maxY - projectionExtent.minY); var maxZoom = goog.isDef(opt_maxZoom) ? opt_maxZoom : 18; + var tileSize = goog.isDef(opt_tileSize) ? + opt_tileSize : new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE); var resolutions = new Array(maxZoom + 1); + goog.asserts.assert(tileSize.width == tileSize.height); for (var z = 0, zz = resolutions.length; z < zz; ++z) { - resolutions[z] = size / (256 << z); + resolutions[z] = size / (tileSize.width << z); } return new ol.tilegrid.TileGrid({ origin: projectionExtent.getTopLeft(), - resolutions: resolutions + resolutions: resolutions, + tileSize: tileSize }); }; diff --git a/src/ol/tilegrid/xyztilegrid.js b/src/ol/tilegrid/xyztilegrid.js index a150e90e78..aa30336997 100644 --- a/src/ol/tilegrid/xyztilegrid.js +++ b/src/ol/tilegrid/xyztilegrid.js @@ -25,7 +25,8 @@ ol.tilegrid.XYZ = function(xyzOptions) { var resolutions = new Array(xyzOptions.maxZoom + 1); var z; for (z = 0; z <= xyzOptions.maxZoom; ++z) { - resolutions[z] = ol.Projection.EPSG_3857_HALF_SIZE / (128 << z); + resolutions[z] = + 2 * ol.Projection.EPSG_3857_HALF_SIZE / (ol.DEFAULT_TILE_SIZE << z); } goog.base(this, { @@ -33,7 +34,7 @@ ol.tilegrid.XYZ = function(xyzOptions) { origin: new ol.Coordinate(-ol.Projection.EPSG_3857_HALF_SIZE, ol.Projection.EPSG_3857_HALF_SIZE), resolutions: resolutions, - tileSize: new ol.Size(256, 256) + tileSize: new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE) }); }; diff --git a/src/ol/view2d.js b/src/ol/view2d.js index d9e256b881..e7cad27ed3 100644 --- a/src/ol/view2d.js +++ b/src/ol/view2d.js @@ -52,7 +52,8 @@ ol.View2D = function(opt_view2DOptions) { var size = Math.max( projectionExtent.maxX - projectionExtent.minX, projectionExtent.maxY - projectionExtent.minY); - values[ol.View2DProperty.RESOLUTION] = size / (256 << view2DOptions.zoom); + values[ol.View2DProperty.RESOLUTION] = + size / (ol.DEFAULT_TILE_SIZE << view2DOptions.zoom); } values[ol.View2DProperty.ROTATION] = view2DOptions.rotation; this.setValues(values); @@ -329,7 +330,7 @@ ol.View2D.createConstraints_ = function(view2DOptions) { view2DOptions.projection, 'EPSG:3857').getExtent(); maxResolution = Math.max( projectionExtent.maxX - projectionExtent.minX, - projectionExtent.maxY - projectionExtent.minY) / 256; + projectionExtent.maxY - projectionExtent.minY) / ol.DEFAULT_TILE_SIZE; // number of steps we want between two data resolutions var numSteps = 4; numZoomLevels = 29 * numSteps; From b880ab80ee5c3175572fa0f54b04ce98593e5eb9 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 11:51:38 +0100 Subject: [PATCH 04/29] Factor out updateTileUsage --- src/ol/renderer/dom/domtilelayerrenderer.js | 17 ++---------- src/ol/renderer/layerrenderer.js | 26 +++++++++++++++++++ .../renderer/webgl/webgltilelayerrenderer.js | 18 ++----------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index f80ca05e04..58a55295f7 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -89,21 +89,6 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = var tileRange = tileGrid.getTileRangeForExtentAndResolution( frameState.extent, tileResolution); - // FIXME should also consider interim tiles - var tileUsage = frameState.tileUsage; - var tileSourceKey = goog.getUid(tileSource).toString(); - var zKey = z.toString(); - if (tileSourceKey in tileUsage) { - if (z in tileUsage[tileSourceKey]) { - tileUsage[tileSourceKey][zKey].extend(tileRange); - } else { - tileUsage[tileSourceKey][zKey] = tileRange; - } - } else { - tileUsage[tileSourceKey] = {}; - tileUsage[tileSourceKey][zKey] = tileRange; - } - /** @type {Object.>} */ var tilesToDrawByZ = {}; tilesToDrawByZ[z] = {}; @@ -251,6 +236,8 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = frameState.animate = true; } + this.updateTileUsage(frameState.tileUsage, tileSource, z, tileRange); + }; diff --git a/src/ol/renderer/layerrenderer.js b/src/ol/renderer/layerrenderer.js index b2078f4c94..b2003467ab 100644 --- a/src/ol/renderer/layerrenderer.js +++ b/src/ol/renderer/layerrenderer.js @@ -3,6 +3,7 @@ goog.provide('ol.renderer.Layer'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('ol.Object'); +goog.require('ol.TileRange'); goog.require('ol.layer.Layer'); goog.require('ol.layer.LayerProperty'); @@ -125,3 +126,28 @@ ol.renderer.Layer.prototype.handleLayerSaturationChange = goog.nullFunction; * @protected */ ol.renderer.Layer.prototype.handleLayerVisibleChange = goog.nullFunction; + + +/** + * @protected + * @param {Object.>} tileUsage Tile usage. + * @param {ol.source.Source} source Source. + * @param {number} z Z. + * @param {ol.TileRange} tileRange Tile range. + */ +ol.renderer.Layer.prototype.updateTileUsage = + function(tileUsage, source, z, tileRange) { + // FIXME should we use tilesToDrawByZ instead? + var sourceKey = goog.getUid(source).toString(); + var zKey = z.toString(); + if (sourceKey in tileUsage) { + if (z in tileUsage[sourceKey]) { + tileUsage[sourceKey][zKey].extend(tileRange); + } else { + tileUsage[sourceKey][zKey] = tileRange; + } + } else { + tileUsage[sourceKey] = {}; + tileUsage[sourceKey][zKey] = tileRange; + } +}; diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index e9ddb277b3..de1f18e1e2 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -276,23 +276,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = var tileRange = tileGrid.getTileRangeForExtentAndResolution( frameState.extent, tileResolution); - // FIXME should also consider interim tiles - var tileUsage = frameState.tileUsage; - var tileSourceKey = goog.getUid(tileSource).toString(); - var zKey = z.toString(); - if (tileSourceKey in tileUsage) { - if (z in tileUsage[tileSourceKey]) { - tileUsage[tileSourceKey][zKey].extend(tileRange); - } else { - tileUsage[tileSourceKey][zKey] = tileRange; - } - } else { - tileUsage[tileSourceKey] = {}; - tileUsage[tileSourceKey][zKey] = tileRange; - } - var framebufferExtent; - if (!goog.isNull(this.renderedTileRange_) && this.renderedTileRange_.equals(tileRange)) { framebufferExtent = this.renderedFramebufferExtent_; @@ -475,6 +459,8 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = } + this.updateTileUsage(frameState.tileUsage, tileSource, z, tileRange); + goog.vec.Mat4.makeIdentity(this.matrix_); goog.vec.Mat4.translate(this.matrix_, (view2DState.center.x - framebufferExtent.minX) / From c56e1f8b921db336683ca56686c2345505565665 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 12:12:09 +0100 Subject: [PATCH 05/29] Ensure DOM element is removed when layer is removed --- src/ol/renderer/dom/domlayerrenderer.js | 9 +++++++++ src/ol/renderer/dom/dommaprenderer.js | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ol/renderer/dom/domlayerrenderer.js b/src/ol/renderer/dom/domlayerrenderer.js index d8ff224761..261c24948f 100644 --- a/src/ol/renderer/dom/domlayerrenderer.js +++ b/src/ol/renderer/dom/domlayerrenderer.js @@ -29,6 +29,15 @@ ol.renderer.dom.Layer = function(mapRenderer, layer, target) { goog.inherits(ol.renderer.dom.Layer, ol.renderer.Layer); +/** + * @inheritDoc + */ +ol.renderer.dom.Layer.prototype.disposeInternal = function() { + goog.dom.removeNode(this.target); + goog.base(this, 'disposeInternal'); +}; + + /** * @return {!Element} Target. */ diff --git a/src/ol/renderer/dom/dommaprenderer.js b/src/ol/renderer/dom/dommaprenderer.js index befec3767c..a92323e1aa 100644 --- a/src/ol/renderer/dom/dommaprenderer.js +++ b/src/ol/renderer/dom/dommaprenderer.js @@ -76,7 +76,6 @@ ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { */ ol.renderer.dom.Map.prototype.removeLayer = function(layer) { goog.base(this, 'removeLayer', layer); - this.getMap().render(); }; From d8e980a9dda8a1eb4eec259104042a44c79ba872 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 12:32:51 +0100 Subject: [PATCH 06/29] Upgrade to latest version of pake --- pake.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pake.py b/pake.py index cb3ac846b9..dec8b71a7a 100644 --- a/pake.py +++ b/pake.py @@ -152,9 +152,7 @@ class Target(object): content = urllib2.urlopen(url).read() if md5 and hashlib.md5(content).hexdigest() != md5: raise BuildError(self, 'corrupt download') - # FIXME Python on Windoze corrupts the content when writing it - # FIXME probably something to do with encodings - with open(self.name, 'w') as f: + with open(self.name, 'wb') as f: f.write(content) def error(self, message): @@ -178,6 +176,10 @@ class Target(object): self.info('mkdir -p %s', path) os.makedirs(path) + def newer(self, *args): + args = flatten_expand_list(args) + return [arg for arg in args if targets.get(arg).timestamp > self.timestamp] + def output(self, *args, **kwargs): args = flatten_expand_list(args) self.info(' '.join(args)) From 1ebea904abe2e0b1d9f406d861a90c3de0672695 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 12:33:10 +0100 Subject: [PATCH 07/29] Only run gjslint on modified files --- build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.py b/build.py index b19e28f9bd..6d2410ae59 100755 --- a/build.py +++ b/build.py @@ -192,13 +192,13 @@ def build_lint_src_timestamp(t): limited_doc_files = [path for path in ifind('externs', 'build/src/external/externs') if path.endswith('.js')] - t.run('%(GJSLINT)s', '--strict', '--limited_doc_files=%s' % (','.join(limited_doc_files),), SRC, INTERNAL_SRC, EXTERNAL_SRC, EXAMPLES_SRC) + t.run('%(GJSLINT)s', '--strict', '--limited_doc_files=%s' % (','.join(limited_doc_files),), t.newer(SRC, INTERNAL_SRC, EXTERNAL_SRC, EXAMPLES_SRC)) t.touch() @target('build/lint-spec-timestamp', SPEC) def build_lint_spec_timestamp(t): - t.run('%(GJSLINT)s', SPEC) + t.run('%(GJSLINT)s', t.newer(SPEC)) t.touch() From 4657b7ca97def10c1557e12b4ccc7205bdcead21 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 12:40:54 +0100 Subject: [PATCH 08/29] Remove removeLayer, thanks @fredj --- src/ol/renderer/dom/dommaprenderer.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/ol/renderer/dom/dommaprenderer.js b/src/ol/renderer/dom/dommaprenderer.js index a92323e1aa..79853a8d6c 100644 --- a/src/ol/renderer/dom/dommaprenderer.js +++ b/src/ol/renderer/dom/dommaprenderer.js @@ -71,14 +71,6 @@ ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { }; -/** - * @inheritDoc - */ -ol.renderer.dom.Map.prototype.removeLayer = function(layer) { - goog.base(this, 'removeLayer', layer); -}; - - /** * @inheritDoc */ From 7e7356dfd6921e650d7c5e5d02430c410a9a08be Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Mon, 14 Jan 2013 21:47:17 +0100 Subject: [PATCH 09/29] Add canvas checks --- src/ol/canvas/canvas.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/ol/canvas/canvas.js diff --git a/src/ol/canvas/canvas.js b/src/ol/canvas/canvas.js new file mode 100644 index 0000000000..4b62511cf7 --- /dev/null +++ b/src/ol/canvas/canvas.js @@ -0,0 +1,21 @@ +goog.provide('ol.canvas'); + +goog.require('goog.dom'); +goog.require('goog.dom.TagName'); + + +/** + * @return {boolean} Is supported. + */ +ol.canvas.isSupported = function() { + if (!('HTMLCanvasElement' in goog.global)) { + return false; + } + try { + var canvas = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement(goog.dom.TagName.CANVAS)); + return !goog.isNull(canvas.getContext('2d')); + } catch (e) { + return false; + } +}; From 54327fb75092e2f1016ebb71d54da987601510dc Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Mon, 14 Jan 2013 21:47:51 +0100 Subject: [PATCH 10/29] Add canvas renderer --- src/ol/map.exports | 1 + src/ol/map.js | 17 +- src/ol/renderer/canvas/canvaslayerrenderer.js | 37 +++ src/ol/renderer/canvas/canvasmaprenderer.js | 178 +++++++++++++ src/ol/renderer/canvas/canvasrenderer.js | 9 + .../canvas/canvastilelayerrenderer.js | 236 ++++++++++++++++++ 6 files changed, 477 insertions(+), 1 deletion(-) create mode 100644 src/ol/renderer/canvas/canvaslayerrenderer.js create mode 100644 src/ol/renderer/canvas/canvasmaprenderer.js create mode 100644 src/ol/renderer/canvas/canvasrenderer.js create mode 100644 src/ol/renderer/canvas/canvastilelayerrenderer.js diff --git a/src/ol/map.exports b/src/ol/map.exports index b2f70f549b..85ac465dfd 100644 --- a/src/ol/map.exports +++ b/src/ol/map.exports @@ -3,6 +3,7 @@ @exportProperty ol.Map.prototype.getInteractions @exportSymbol ol.RendererHint +@exportProperty ol.RendererHint.CANVAS @exportProperty ol.RendererHint.DOM @exportProperty ol.RendererHint.WEBGL diff --git a/src/ol/map.js b/src/ol/map.js index 383529adeb..349a32f65b 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -54,12 +54,20 @@ goog.require('ol.interaction.MouseWheelZoom'); goog.require('ol.interaction.condition'); goog.require('ol.renderer.Layer'); goog.require('ol.renderer.Map'); +goog.require('ol.renderer.canvas'); +goog.require('ol.renderer.canvas.Map'); goog.require('ol.renderer.dom'); goog.require('ol.renderer.dom.Map'); goog.require('ol.renderer.webgl'); goog.require('ol.renderer.webgl.Map'); +/** + * @define {boolean} Whether to enable canvas. + */ +ol.ENABLE_CANVAS = true; + + /** * @define {boolean} Whether to enable DOM. */ @@ -76,6 +84,7 @@ ol.ENABLE_WEBGL = true; * @enum {string} */ ol.RendererHint = { + CANVAS: 'canvas', DOM: 'dom', WEBGL: 'webgl' }; @@ -86,6 +95,7 @@ ol.RendererHint = { */ ol.DEFAULT_RENDERER_HINTS = [ ol.RendererHint.WEBGL, + ol.RendererHint.CANVAS, ol.RendererHint.DOM ]; @@ -795,7 +805,12 @@ ol.Map.createOptionsInternal = function(mapOptions) { var i, rendererHint; for (i = 0; i < rendererHints.length; ++i) { rendererHint = rendererHints[i]; - if (rendererHint == ol.RendererHint.DOM) { + if (rendererHint == ol.RendererHint.CANVAS) { + if (ol.ENABLE_CANVAS && ol.renderer.canvas.isSupported()) { + rendererConstructor = ol.renderer.canvas.Map; + break; + } + } else if (rendererHint == ol.RendererHint.DOM) { if (ol.ENABLE_DOM && ol.renderer.dom.isSupported()) { rendererConstructor = ol.renderer.dom.Map; break; diff --git a/src/ol/renderer/canvas/canvaslayerrenderer.js b/src/ol/renderer/canvas/canvaslayerrenderer.js new file mode 100644 index 0000000000..78ed9d6665 --- /dev/null +++ b/src/ol/renderer/canvas/canvaslayerrenderer.js @@ -0,0 +1,37 @@ +goog.provide('ol.renderer.canvas.Layer'); + +goog.require('ol.FrameState'); +goog.require('ol.layer.LayerState'); +goog.require('ol.renderer.Layer'); + + + +/** + * @constructor + * @extends {ol.renderer.Layer} + * @param {ol.renderer.Map} mapRenderer Map renderer. + * @param {ol.layer.Layer} layer Layer. + */ +ol.renderer.canvas.Layer = function(mapRenderer, layer) { + goog.base(this, mapRenderer, layer); +}; +goog.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer); + + +/** + * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas. + */ +ol.renderer.canvas.Layer.prototype.getImage = goog.abstractMethod; + + +/** + * @return {!goog.vec.Mat4.Number} Transform. + */ +ol.renderer.canvas.Layer.prototype.getTransform = goog.abstractMethod; + + +/** + * @param {ol.FrameState} frameState Frame state. + * @param {ol.layer.LayerState} layerState Layer state. + */ +ol.renderer.canvas.Layer.prototype.renderFrame = goog.abstractMethod; diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js new file mode 100644 index 0000000000..34d82d5722 --- /dev/null +++ b/src/ol/renderer/canvas/canvasmaprenderer.js @@ -0,0 +1,178 @@ +// FIXME offset panning + +goog.provide('ol.renderer.canvas.Map'); + +goog.require('goog.dom'); +goog.require('goog.style'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Size'); +goog.require('ol.layer.TileLayer'); +goog.require('ol.renderer.Map'); +goog.require('ol.renderer.canvas.TileLayer'); + + + +/** + * @constructor + * @extends {ol.renderer.Map} + * @param {Element} container Container. + * @param {ol.Map} map Map. + */ +ol.renderer.canvas.Map = function(container, map) { + + goog.base(this, container, map); + + /** + * @private + * @type {ol.Size} + */ + this.canvasSize_ = new ol.Size(container.clientHeight, container.clientWidth); + + /** + * @private + * @type {Element} + */ + this.canvas_ = goog.dom.createElement(goog.dom.TagName.CANVAS); + this.canvas_.height = this.canvasSize_.height; + this.canvas_.width = this.canvasSize_.width; + this.canvas_.className = 'ol-unselectable'; + goog.dom.insertChildAt(container, this.canvas_, 0); + + /** + * @private + * @type {boolean} + */ + this.renderedVisible_ = true; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = this.canvas_.getContext('2d'); + +}; +goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map); + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) { + if (layer instanceof ol.layer.TileLayer) { + return new ol.renderer.canvas.TileLayer(this, layer); + } else { + goog.asserts.assert(false); + return null; + } +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.handleBackgroundColorChanged = function() { + this.getMap().render(); +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.handleViewPropertyChanged = function() { + goog.base(this, 'handleViewPropertyChanged'); + this.getMap().render(); +}; + + +/** + * @param {goog.events.Event} event Event. + * @protected + */ +ol.renderer.canvas.Map.prototype.handleLayerRendererChange = function(event) { + this.getMap().render(); +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.handleSizeChanged = function() { + goog.base(this, 'handleSizeChanged'); + this.getMap().render(); +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.handleViewChanged = function() { + goog.base(this, 'handleViewChanged'); + this.getMap().render(); +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { + + if (goog.isNull(frameState)) { + if (this.renderedVisible_) { + goog.style.showElement(this.canvas_, false); + this.renderedVisible_ = false; + } + return; + } + + var size = frameState.size; + if (!this.canvasSize_.equals(size)) { + this.canvas_.width = size.width; + this.canvas_.height = size.height; + this.canvasSize_ = size; + } + + // FIXME filling the background doesn't seem to work + var context = this.context_; + context.setTransform(1, 0, 1, 0, 0, 0); + var backgroundColor = frameState.backgroundColor; + context.fillStyle = 'rgb(' + + backgroundColor.r.toFixed(0) + ',' + + backgroundColor.g.toFixed(0) + ',' + + backgroundColor.b.toFixed(0) + ')'; + context.globalAlpha = 1; + context.fillRect(0, 0, size.width, size.height); + + goog.array.forEach(frameState.layersArray, function(layer) { + + var layerState = frameState.layerStates[goog.getUid(layer)]; + if (!layerState.visible) { + return; + } else if (!layerState.ready) { + frameState.animate = true; + return; + } + var layerRenderer = this.getLayerRenderer(layer); + layerRenderer.renderFrame(frameState, layerState); + + var transform = layerRenderer.getTransform(); + context.setTransform( + goog.vec.Mat4.getElement(transform, 0, 0), + goog.vec.Mat4.getElement(transform, 1, 0), + goog.vec.Mat4.getElement(transform, 0, 1), + goog.vec.Mat4.getElement(transform, 1, 1), + goog.vec.Mat4.getElement(transform, 0, 3), + goog.vec.Mat4.getElement(transform, 1, 3)); + + context.globalAlpha = layerState.opacity; + context.drawImage(layerRenderer.getImage(), 0, 0); + + }, this); + + if (!this.renderedVisible_) { + goog.style.showElement(this.canvas_, true); + this.renderedVisible_ = true; + } + + this.calculateMatrices2D(frameState); + +}; diff --git a/src/ol/renderer/canvas/canvasrenderer.js b/src/ol/renderer/canvas/canvasrenderer.js new file mode 100644 index 0000000000..f28861dcdc --- /dev/null +++ b/src/ol/renderer/canvas/canvasrenderer.js @@ -0,0 +1,9 @@ +goog.provide('ol.renderer.canvas'); + +goog.require('ol.canvas'); + + +/** + * @return {boolean} Is supported. + */ +ol.renderer.canvas.isSupported = ol.canvas.isSupported; diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js new file mode 100644 index 0000000000..4c17795648 --- /dev/null +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -0,0 +1,236 @@ +// FIXME don't redraw tiles if not needed +// FIXME find correct globalCompositeOperation +// FIXME optimize :-) + +goog.provide('ol.renderer.canvas.TileLayer'); + +goog.require('goog.dom'); +goog.require('goog.style'); +goog.require('goog.vec.Mat4'); +goog.require('ol.Size'); +goog.require('ol.TileRange'); +goog.require('ol.layer.TileLayer'); +goog.require('ol.renderer.Map'); +goog.require('ol.renderer.canvas.Layer'); + + + +/** + * @constructor + * @extends {ol.renderer.canvas.Layer} + * @param {ol.renderer.Map} mapRenderer Map renderer. + * @param {ol.layer.TileLayer} tileLayer Tile layer. + */ +ol.renderer.canvas.TileLayer = function(mapRenderer, tileLayer) { + + goog.base(this, mapRenderer, tileLayer); + + /** + * @private + * @type {HTMLCanvasElement} + */ + this.canvas_ = null; + + /** + * @private + * @type {ol.Size} + */ + this.canvasSize_ = null; + + /** + * @private + * @type {CanvasRenderingContext2D} + */ + this.context_ = null; + + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.transform_ = goog.vec.Mat4.createNumber(); + +}; +goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); + + +/** + * @inheritDoc + */ +ol.renderer.canvas.TileLayer.prototype.getImage = function() { + return this.canvas_; +}; + + +/** + * @return {ol.layer.TileLayer} Tile layer. + */ +ol.renderer.canvas.TileLayer.prototype.getTileLayer = function() { + return /** @type {ol.layer.TileLayer} */ (this.getLayer()); +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.TileLayer.prototype.getTransform = function() { + return this.transform_; +}; + + +/** + * @inheritDoc + */ +ol.renderer.canvas.TileLayer.prototype.renderFrame = + function(frameState, layerState) { + + var view2DState = frameState.view2DState; + + var tileLayer = this.getTileLayer(); + var tileSource = tileLayer.getTileSource(); + var tileGrid = tileSource.getTileGrid(); + var tileSize = tileGrid.getTileSize(); + var z = tileGrid.getZForResolution(view2DState.resolution); + var tileResolution = tileGrid.getResolution(z); + var tileRange = tileGrid.getTileRangeForExtentAndResolution( + frameState.extent, tileResolution); + + var canvasSize = new ol.Size( + tileSize.width * tileRange.getWidth(), + tileSize.height * tileRange.getHeight()); + + var canvas, context; + if (goog.isNull(this.canvas_)) { + canvas = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement(goog.dom.TagName.CANVAS)); + canvas.width = canvasSize.width; + canvas.height = canvasSize.height; + context = /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d')); + this.canvas_ = canvas; + this.canvasSize_ = canvasSize; + this.context_ = context; + } else { + canvas = this.canvas_; + context = this.context_; + if (!this.canvasSize_.equals(canvasSize)) { + canvas.width = canvasSize.width; + canvas.height = canvasSize.height; + this.canvasSize_ = canvasSize; + } + } + + context.clearRect(0, 0, canvasSize.width, canvasSize.height); + + /** + * @type {Object.>} + */ + var tilesToDrawByZ = {}; + tilesToDrawByZ[z] = {}; + + var findInterimTiles = function(z, tileRange) { + // FIXME this could be more efficient about filling partial holes + var fullyCovered = true; + var tile, tileCoord, tileCoordKey, x, y; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + tileCoord = new ol.TileCoord(z, x, y); + tileCoordKey = tileCoord.toString(); + if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) { + return; + } + tile = tileSource.getTile(tileCoord); + if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) { + if (!tilesToDrawByZ[z]) { + tilesToDrawByZ[z] = {}; + } + tilesToDrawByZ[z][tileCoordKey] = tile; + } else { + fullyCovered = false; + } + } + } + return fullyCovered; + }; + + var allTilesLoaded = true; + var tile, tileCenter, tileCoord, tileState, x, y; + for (x = tileRange.minX; x <= tileRange.maxX; ++x) { + for (y = tileRange.minY; y <= tileRange.maxY; ++y) { + + tileCoord = new ol.TileCoord(z, x, y); + tile = tileSource.getTile(tileCoord); + if (goog.isNull(tile)) { + continue; + } + + tileState = tile.getState(); + if (tileState == ol.TileState.IDLE) { + tileCenter = tileGrid.getTileCoordCenter(tileCoord); + frameState.tileQueue.enqueue(tile, tileCenter, tileResolution); + } else if (tileState == ol.TileState.LOADED) { + tilesToDrawByZ[z][tileCoord.toString()] = tile; + continue; + } else if (tileState == ol.TileState.ERROR) { + continue; + } + + allTilesLoaded = false; + tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles); + + } + } + + /** @type {Array.} */ + var zs = goog.array.map(goog.object.getKeys(tilesToDrawByZ), Number); + goog.array.sort(zs); + var origin = tileGrid.getTileCoordExtent( + new ol.TileCoord(z, tileRange.minX, tileRange.maxY)).getTopLeft(); + var currentZ, i, scale, tileCoordKey, tileExtent, tilesToDraw; + for (i = 0; i < zs.length; ++i) { + currentZ = zs[i]; + tilesToDraw = tilesToDrawByZ[currentZ]; + if (currentZ == z) { + for (tileCoordKey in tilesToDraw) { + tile = tilesToDraw[tileCoordKey]; + context.drawImage( + tile.getImage(), + tileSize.width * (tile.tileCoord.x - tileRange.minX), + tileSize.height * (tileRange.maxY - tile.tileCoord.y)); + } + } else { + scale = tileGrid.getResolution(currentZ) / tileResolution; + for (tileCoordKey in tilesToDraw) { + tile = tilesToDraw[tileCoordKey]; + tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord); + context.drawImage( + tile.getImage(), + (tileExtent.minX - origin.x) / tileResolution, + (origin.y - tileExtent.maxY) / tileResolution, + scale * tileSize.width, + scale * tileSize.height); + } + } + } + + if (!allTilesLoaded) { + frameState.animate = true; + } + + this.updateTileUsage(frameState.tileUsage, tileSource, z, tileRange); + + var transform = this.transform_; + goog.vec.Mat4.makeIdentity(transform); + goog.vec.Mat4.translate(transform, + frameState.size.width / 2, frameState.size.height / 2, 0); + goog.vec.Mat4.rotateZ(transform, view2DState.rotation); + goog.vec.Mat4.scale( + transform, + tileResolution / view2DState.resolution, + tileResolution / view2DState.resolution, + 1); + goog.vec.Mat4.translate( + transform, + (origin.x - view2DState.center.x) / tileResolution, + (view2DState.center.y - origin.y) / tileResolution, + 0); + +}; From aeef26010193cc595658ed4cba4d64649595cda2 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Mon, 14 Jan 2013 21:48:22 +0100 Subject: [PATCH 11/29] Add canvas renderer to side-by-side demo --- examples/side-by-side.html | 5 ++++- examples/side-by-side.js | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/examples/side-by-side.html b/examples/side-by-side.html index 6aa2307ef5..ffc817397b 100644 --- a/examples/side-by-side.html +++ b/examples/side-by-side.html @@ -16,19 +16,22 @@

Side-by-side example

-
Side-by-side DOM and WebGL sync'ed maps.
+
Side-by-side DOM, WebGL and Canvas sync'ed maps.
+ + +
DOM WebGLCanvas
diff --git a/examples/side-by-side.js b/examples/side-by-side.js index 540a277e76..1c32f475e5 100644 --- a/examples/side-by-side.js +++ b/examples/side-by-side.js @@ -62,6 +62,22 @@ webglMap.getControls().push(new ol.control.MousePosition({ undefinedHTML: ' ' })); +var canvasMap = new ol.Map({ + renderer: ol.RendererHint.CANVAS, + target: 'canvasMap' +}); +if (canvasMap !== null) { + canvasMap.bindTo('layers', domMap); + canvasMap.bindTo('view', domMap); +} + +canvasMap.getControls().push(new ol.control.MousePosition({ + coordinateFormat: ol.Coordinate.toStringHDMS, + projection: ol.Projection.getFromCode('EPSG:4326'), + target: document.getElementById('canvasMousePosition'), + undefinedHtml: ' ' +})); + var keyboardInteraction = new ol.interaction.Keyboard(); keyboardInteraction.addCallback('0', function() { layer.setBrightness(0); @@ -94,11 +110,13 @@ keyboardInteraction.addCallback('j', function() { var bounce = ol.animation.createBounce(2 * view.getResolution()); domMap.addPreRenderFunction(bounce); webglMap.addPreRenderFunction(bounce); + canvasMap.addPreRenderFunction(bounce); }); keyboardInteraction.addCallback('l', function() { var panFrom = ol.animation.createPanFrom(view.getCenter()); domMap.addPreRenderFunction(panFrom); webglMap.addPreRenderFunction(panFrom); + canvasMap.addPreRenderFunction(panFrom); view.setCenter(LONDON); }); keyboardInteraction.addCallback('L', function() { @@ -111,12 +129,14 @@ keyboardInteraction.addCallback('L', function() { var preRenderFunctions = [bounce, panFrom, spin]; domMap.addPreRenderFunctions(preRenderFunctions); webglMap.addPreRenderFunctions(preRenderFunctions); + canvasMap.addPreRenderFunctions(preRenderFunctions); view.setCenter(LONDON); }); keyboardInteraction.addCallback('m', function() { var panFrom = ol.animation.createPanFrom(view.getCenter(), 1000); domMap.addPreRenderFunction(panFrom); webglMap.addPreRenderFunction(panFrom); + canvasMap.addPreRenderFunction(panFrom); view.setCenter(MOSCOW); }); keyboardInteraction.addCallback('M', function() { @@ -129,6 +149,7 @@ keyboardInteraction.addCallback('M', function() { var preRenderFunctions = [bounce, panFrom, spin]; domMap.addPreRenderFunctions(preRenderFunctions); webglMap.addPreRenderFunctions(preRenderFunctions); + canvasMap.addPreRenderFunctions(preRenderFunctions); view.setCenter(MOSCOW); }); keyboardInteraction.addCallback('o', function() { @@ -154,10 +175,12 @@ keyboardInteraction.addCallback('x', function() { var spin = ol.animation.createSpin(2000, 2); domMap.addPreRenderFunction(spin); webglMap.addPreRenderFunction(spin); + canvasMap.addPreRenderFunction(spin); }); keyboardInteraction.addCallback('X', function() { var spin = ol.animation.createSpin(2000, -2); domMap.addPreRenderFunction(spin); webglMap.addPreRenderFunction(spin); + canvasMap.addPreRenderFunction(spin); }); domMap.getInteractions().push(keyboardInteraction); From 5eeec41877ced881980ec2a04dd9f823fbf6047a Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Mon, 14 Jan 2013 21:48:55 +0100 Subject: [PATCH 12/29] Add canvas renderer to two layers demo --- examples/two-layers.html | 4 +++- examples/two-layers.js | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/two-layers.html b/examples/two-layers.html index cc71de2683..4d7ac617ce 100644 --- a/examples/two-layers.html +++ b/examples/two-layers.html @@ -16,15 +16,17 @@

Two-layer example

-
Sync'ed DOM and WebGL maps with two layers.
+
Sync'ed DOM, WebGL and Canvas maps with two layers.
+ +
DOM WebGLCanvas
diff --git a/examples/two-layers.js b/examples/two-layers.js index 8ab0550a7d..4817a59a15 100644 --- a/examples/two-layers.js +++ b/examples/two-layers.js @@ -40,3 +40,11 @@ var domMap = new ol.Map({ }); domMap.bindTo('layers', webglMap); domMap.bindTo('view', webglMap); + + +var canvasMap = new ol.Map({ + renderer: ol.RendererHint.CANVAS, + target: 'canvasMap' +}); +canvasMap.bindTo('layers', webglMap); +canvasMap.bindTo('view', webglMap); From 95b48bdec41f69eb089f50cab243335cdfc7bbb3 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 15:35:38 +0100 Subject: [PATCH 13/29] Add ol.easing.linear --- src/ol/easing.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ol/easing.js b/src/ol/easing.js index 74bd1c5210..7700c7fee6 100644 --- a/src/ol/easing.js +++ b/src/ol/easing.js @@ -1,6 +1,15 @@ goog.provide('ol.easing'); +/** + * @param {number} t Input between 0 and 1. + * @return {number} Output between 0 and 1. + */ +ol.easing.linear = function(t) { + return t; +}; + + /** * @param {number} t Input between 0 and 1. * @return {number} Output between 0 and 1. From 0257db05df581a7b19988be64bdb080b4a0441ef Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 15:36:02 +0100 Subject: [PATCH 14/29] Add zoom from animation --- src/ol/animation.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/ol/animation.js b/src/ol/animation.js index e85fccbd5a..582c7c5ad0 100644 --- a/src/ol/animation.js +++ b/src/ol/animation.js @@ -107,3 +107,36 @@ ol.animation.createSpin = } }; }; + + +/** + * @param {number} sourceResolution Source resolution. + * @param {number=} opt_duration Duration. + * @param {number=} opt_start Start. + * @param {function(number): number=} opt_easingFunction Easing function. + * @return {ol.PreRenderFunction} Pre-render function. + */ +ol.animation.createZoomFrom = + function(sourceResolution, opt_duration, opt_start, opt_easingFunction) { + var start = goog.isDef(opt_start) ? opt_start : Date.now(); + var duration = goog.isDef(opt_duration) ? opt_duration : 1000; + var easingFunction = goog.isDef(opt_easingFunction) ? + opt_easingFunction : ol.easing.linear; + return function(map, frameState) { + if (frameState.time < start) { + frameState.animate = true; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else if (frameState.time < start + duration) { + var delta = 1 - easingFunction((frameState.time - start) / duration); + var deltaResolution = + sourceResolution - frameState.view2DState.resolution; + frameState.animate = true; + frameState.view2DState.resolution += delta * deltaResolution; + frameState.viewHints[ol.ViewHint.ANIMATING] += 1; + return true; + } else { + return false; + } + }; +}; From 965d5e2cc8409456d4deb62f27181f2838c19f07 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 15:36:36 +0100 Subject: [PATCH 15/29] Add animation duration to ol.View2D.zoom --- src/ol/animation.js | 2 +- src/ol/view2d.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ol/animation.js b/src/ol/animation.js index 582c7c5ad0..4049186bb8 100644 --- a/src/ol/animation.js +++ b/src/ol/animation.js @@ -1,10 +1,10 @@ // FIXME works for View2D only +// FIXME dependency on ol.View2D suppressed to prevent dependency loop goog.provide('ol.animation'); goog.require('goog.fx.easing'); goog.require('ol.PreRenderFunction'); -goog.require('ol.View2D'); goog.require('ol.easing'); diff --git a/src/ol/view2d.js b/src/ol/view2d.js index e7cad27ed3..0ea5977c43 100644 --- a/src/ol/view2d.js +++ b/src/ol/view2d.js @@ -12,6 +12,7 @@ goog.require('ol.Projection'); goog.require('ol.ResolutionConstraint'); goog.require('ol.RotationConstraint'); goog.require('ol.View'); +goog.require('ol.animation'); /** @@ -289,9 +290,16 @@ ol.View2D.prototype.zoom_ = function(map, resolution, opt_anchor) { * @param {ol.Map} map Map. * @param {number} delta Delta from previous zoom level. * @param {ol.Coordinate=} opt_anchor Anchor coordinate. + * @param {number=} opt_duration Duration. */ -ol.View2D.prototype.zoom = function(map, delta, opt_anchor) { - var resolution = this.constraints_.resolution(this.getResolution(), delta); +ol.View2D.prototype.zoom = function(map, delta, opt_anchor, opt_duration) { + var currentResolution = this.getResolution(); + if (goog.isDef(currentResolution) && goog.isDef(opt_duration)) { + map.requestRenderFrame(); + map.addPreRenderFunction(ol.animation.createZoomFrom( + currentResolution, opt_duration)); + } + var resolution = this.constraints_.resolution(currentResolution, delta); this.zoom_(map, resolution, opt_anchor); }; From 90b7cfb33063c70d6649db4df5db069efb76df28 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 15:37:18 +0100 Subject: [PATCH 16/29] Add animated zoom to zoom control --- src/ol/control/zoomcontrol.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ol/control/zoomcontrol.js b/src/ol/control/zoomcontrol.js index 82be362311..96c83d703d 100644 --- a/src/ol/control/zoomcontrol.js +++ b/src/ol/control/zoomcontrol.js @@ -11,6 +11,12 @@ goog.require('ol.Projection'); goog.require('ol.control.Control'); +/** + * @define {number} Zoom duration. + */ +ol.control.ZOOM_DURATION = 250; + + /** * @constructor @@ -61,8 +67,9 @@ ol.control.Zoom.prototype.handleIn_ = function(browserEvent) { // prevent #zoomIn anchor from getting appended to the url browserEvent.preventDefault(); var map = this.getMap(); + map.requestRenderFrame(); // FIXME works for View2D only - map.getView().zoom(map, this.delta_); + map.getView().zoom(map, this.delta_, undefined, ol.control.ZOOM_DURATION); }; @@ -74,6 +81,7 @@ ol.control.Zoom.prototype.handleOut_ = function(browserEvent) { // prevent #zoomOut anchor from getting appended to the url browserEvent.preventDefault(); var map = this.getMap(); + map.requestRenderFrame(); // FIXME works for View2D only - map.getView().zoom(map, -this.delta_); + map.getView().zoom(map, -this.delta_, undefined, ol.control.ZOOM_DURATION); }; From 9428a94968ea3862c70673d04bac250a5b808ff5 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 15:37:32 +0100 Subject: [PATCH 17/29] Add animated zoom to keyboard zoom interaction --- src/ol/interaction/keyboardzoominteraction.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ol/interaction/keyboardzoominteraction.js b/src/ol/interaction/keyboardzoominteraction.js index 3075754ca7..9252cc652c 100644 --- a/src/ol/interaction/keyboardzoominteraction.js +++ b/src/ol/interaction/keyboardzoominteraction.js @@ -8,6 +8,12 @@ goog.require('ol.View2D'); goog.require('ol.interaction.Interaction'); +/** + * @define {number} Zoom duration. + */ +ol.interaction.KEYBOARD_ZOOM_DURATION = 100; + + /** * @constructor @@ -31,10 +37,11 @@ ol.interaction.KeyboardZoom.prototype.handleMapBrowserEvent = if (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0)) { var map = mapBrowserEvent.map; var delta = (charCode == '+'.charCodeAt(0)) ? 4 : -4; + map.requestRenderFrame(); // FIXME works for View2D only var view = map.getView(); goog.asserts.assert(view instanceof ol.View2D); - view.zoom(map, delta); + view.zoom(map, delta, undefined, ol.interaction.KEYBOARD_ZOOM_DURATION); keyEvent.preventDefault(); mapBrowserEvent.preventDefault(); } From 141e5aa9fcc806da494847386d3098e7139665bf Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 17 Jan 2013 13:05:47 -0700 Subject: [PATCH 18/29] Trim search string before use The `window.location.search` string includes the "?" symbol. Without this change, `createFromQueryData` only works if the "renderer" parameter is not in first position (see 4037bafc453a8bde0c6a6508e5f4f385702436c1). --- src/ol/map.js | 5 +++-- test/spec/ol/map.test.js | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/ol/map.js b/src/ol/map.js index 349a32f65b..cdd492f45a 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -947,8 +947,9 @@ ol.Map.createInteractions_ = function(mapOptions) { * @return {Array.} Renderer hints. */ ol.RendererHints.createFromQueryData = function(opt_queryData) { - var queryData = goog.isDef(opt_queryData) ? - opt_queryData : new goog.Uri.QueryData(goog.global.location.search); + var query = goog.global.location.search.substring(1), + queryData = goog.isDef(opt_queryData) ? + opt_queryData : new goog.Uri.QueryData(query); if (queryData.containsKey('renderers')) { return queryData.get('renderers').split(','); } else if (queryData.containsKey('renderer')) { diff --git a/test/spec/ol/map.test.js b/test/spec/ol/map.test.js index b30207e771..c23d71c237 100644 --- a/test/spec/ol/map.test.js +++ b/test/spec/ol/map.test.js @@ -8,6 +8,54 @@ goog.require('ol.View2D'); goog.require('ol.layer.TileLayer'); goog.require('ol.source.XYZ'); +describe('ol.RendererHints', function() { + + describe('#createFromQueryData()', function() { + + var savedGoogGlobal; + + beforeEach(function() { + savedGoogGlobal = goog.global; + goog.global = {}; + }); + + afterEach(function() { + goog.global = savedGoogGlobal; + }); + + it('returns defaults when no query string', function() { + goog.global.location = {search: ''}; + var hints = ol.RendererHints.createFromQueryData(); + expect(hints).toBe(ol.DEFAULT_RENDERER_HINTS); + }); + + it('returns defaults when no "renderer" or "renderers"', function() { + goog.global.location = {search: '?foo=bar'}; + var hints = ol.RendererHints.createFromQueryData(); + expect(hints).toBe(ol.DEFAULT_RENDERER_HINTS); + }); + + it('returns array of one for "renderer"', function() { + goog.global.location = {search: '?renderer=bogus'}; + var hints = ol.RendererHints.createFromQueryData(); + expect(hints).toEqual(['bogus']); + }); + + it('accepts comma delimited list for "renderers"', function() { + goog.global.location = {search: '?renderers=one,two'}; + var hints = ol.RendererHints.createFromQueryData(); + expect(hints).toEqual(['one', 'two']); + }); + + it('works with "renderer" in second position', function() { + goog.global.location = {search: '?foo=bar&renderer=one'}; + var hints = ol.RendererHints.createFromQueryData(); + expect(hints).toEqual(['one']); + }); + + }); +}); + describe('ol.Map', function() { describe('dispose', function() { From b36eab1dfaf4281d1756ea0eaf7e660b5979d1f0 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 17 Jan 2013 13:40:00 -0700 Subject: [PATCH 19/29] Properly set transform before filling background (closes #128) Order of args is m11, m12, m21, m22, dx, dy --- src/ol/renderer/canvas/canvasmaprenderer.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js index 34d82d5722..b664dc977a 100644 --- a/src/ol/renderer/canvas/canvasmaprenderer.js +++ b/src/ol/renderer/canvas/canvasmaprenderer.js @@ -131,9 +131,8 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { this.canvasSize_ = size; } - // FIXME filling the background doesn't seem to work var context = this.context_; - context.setTransform(1, 0, 1, 0, 0, 0); + context.setTransform(1, 0, 0, 1, 0, 0); var backgroundColor = frameState.backgroundColor; context.fillStyle = 'rgb(' + backgroundColor.r.toFixed(0) + ',' + From 10672ad30304d386ea0ab8895b690bf0380a9cea Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 17 Jan 2013 14:19:50 -0700 Subject: [PATCH 20/29] Standardizing color ranges (see #129) --- src/ol/color.js | 11 ++-- src/ol/map.js | 2 +- src/ol/renderer/canvas/canvasmaprenderer.js | 2 +- src/ol/renderer/webgl/webglmaprenderer.js | 3 +- test/ol.html | 1 + test/spec/ol/color.test.js | 73 +++++++++++++++++++++ 6 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 test/spec/ol/color.test.js diff --git a/src/ol/color.js b/src/ol/color.js index 5d6286f6f9..368e23fdda 100644 --- a/src/ol/color.js +++ b/src/ol/color.js @@ -1,6 +1,7 @@ goog.provide('ol.Color'); goog.require('goog.color'); +goog.require('goog.math'); @@ -9,29 +10,29 @@ goog.require('goog.color'); * @param {number} r Red, 0 to 255. * @param {number} g Green, 0 to 255. * @param {number} b Blue, 0 to 255. - * @param {number} a Alpha, 0 (fully transparent) to 255 (fully opaque). + * @param {number} a Alpha, 0 (fully transparent) to 1 (fully opaque). */ ol.Color = function(r, g, b, a) { /** * @type {number} */ - this.r = r; + this.r = goog.math.clamp(r, 0, 255); /** * @type {number} */ - this.g = g; + this.g = goog.math.clamp(g, 0, 255); /** * @type {number} */ - this.b = b; + this.b = goog.math.clamp(b, 0, 255); /** * @type {number} */ - this.a = a; + this.a = goog.math.clamp(a, 0, 1); }; diff --git a/src/ol/map.js b/src/ol/map.js index cdd492f45a..a0400327e3 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -618,7 +618,7 @@ ol.Map.prototype.renderFrame_ = function(time) { frameState = { animate: false, backgroundColor: goog.isDef(backgroundColor) ? - backgroundColor : new ol.Color(1, 1, 1, 1), + backgroundColor : new ol.Color(255, 255, 255, 1), coordinateToPixelMatrix: this.coordinateToPixelMatrix_, extent: null, layersArray: layersArray, diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js index b664dc977a..2798b18c62 100644 --- a/src/ol/renderer/canvas/canvasmaprenderer.js +++ b/src/ol/renderer/canvas/canvasmaprenderer.js @@ -138,7 +138,7 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { backgroundColor.r.toFixed(0) + ',' + backgroundColor.g.toFixed(0) + ',' + backgroundColor.b.toFixed(0) + ')'; - context.globalAlpha = 1; + context.globalAlpha = backgroundColor.a; context.fillRect(0, 0, size.width, size.height); goog.array.forEach(frameState.layersArray, function(layer) { diff --git a/src/ol/renderer/webgl/webglmaprenderer.js b/src/ol/renderer/webgl/webglmaprenderer.js index 3a071a686e..6e2e6c3990 100644 --- a/src/ol/renderer/webgl/webglmaprenderer.js +++ b/src/ol/renderer/webgl/webglmaprenderer.js @@ -490,7 +490,8 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { gl.bindFramebuffer(goog.webgl.FRAMEBUFFER, null); var clearColor = frameState.backgroundColor; - gl.clearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + gl.clearColor(clearColor.r / 255, clearColor.g / 255, + clearColor.b / 255, clearColor.a); gl.clear(goog.webgl.COLOR_BUFFER_BIT); gl.enable(goog.webgl.BLEND); gl.viewport(0, 0, size.width, size.height); diff --git a/test/ol.html b/test/ol.html index 9c00d22ecd..b0e05e2f6d 100644 --- a/test/ol.html +++ b/test/ol.html @@ -72,6 +72,7 @@ + diff --git a/test/spec/ol/color.test.js b/test/spec/ol/color.test.js new file mode 100644 index 0000000000..157a64788a --- /dev/null +++ b/test/spec/ol/color.test.js @@ -0,0 +1,73 @@ +describe('ol.Color', function() { + + describe('constructor', function() { + + it('limits r to 0-255', function() { + var c; + + // legit r + c = new ol.Color(10.5, 11, 12, 0.5); + expect(c.r).toBe(10.5); + + // under r + c = new ol.Color(-10, 11, 12, 0.5); + expect(c.r).toBe(0); + + // over r + c = new ol.Color(300, 11, 12, 0.5); + expect(c.r).toBe(255); + }); + + it('limits g to 0-255', function() { + var c; + + // legit g + c = new ol.Color(10, 11.5, 12, 0.5); + expect(c.g).toBe(11.5); + + // under g + c = new ol.Color(10, -11, 12, 0.5); + expect(c.g).toBe(0); + + // over g + c = new ol.Color(10, 275, 12, 0.5); + expect(c.g).toBe(255); + }); + + it('limits b to 0-255', function() { + var c; + + // legit b + c = new ol.Color(10, 11, 12.5, 0.5); + expect(c.b).toBe(12.5); + + // under b + c = new ol.Color(10, 11, -12, 0.5); + expect(c.b).toBe(0); + + // over b + c = new ol.Color(10, 11, 500, 0.5); + expect(c.b).toBe(255); + }); + + it('limits 1 to 0-1', function() { + var c; + + // legit a + c = new ol.Color(10, 11, 12, 0.5); + expect(c.a).toBe(0.5); + + // under a + c = new ol.Color(10, 11, 12, -0.5); + expect(c.a).toBe(0); + + // over a + c = new ol.Color(10, 11, 12, 2.5); + expect(c.a).toBe(1); + }); + + }); + +}); + +goog.require('ol.array'); From f39b6a1be33acbbe4a3ba6d984aabea8363735f9 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 17 Jan 2013 14:23:35 -0700 Subject: [PATCH 21/29] Errant require --- test/spec/ol/color.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/spec/ol/color.test.js b/test/spec/ol/color.test.js index 157a64788a..103c10a8fa 100644 --- a/test/spec/ol/color.test.js +++ b/test/spec/ol/color.test.js @@ -69,5 +69,3 @@ describe('ol.Color', function() { }); }); - -goog.require('ol.array'); From 7c660f6ac0e1930b1a543417910d29b2476d0f38 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 17 Jan 2013 22:39:47 +0100 Subject: [PATCH 22/29] Export animation functions, thanks @elemoine --- src/ol/animation.exports | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/ol/animation.exports diff --git a/src/ol/animation.exports b/src/ol/animation.exports new file mode 100644 index 0000000000..7286bf8cc3 --- /dev/null +++ b/src/ol/animation.exports @@ -0,0 +1,4 @@ +@exportSymbol ol.animation +@exportProperty ol.animation.createBounce +@exportProperty ol.animation.createPanFrom +@exportProperty ol.animation.createSpin From fe56b15c521ee7ae369042719b81651478bcb2df Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 17 Jan 2013 15:30:16 -0700 Subject: [PATCH 23/29] Clear canvas with opacity 1 --- src/ol/renderer/canvas/canvasmaprenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js index 2798b18c62..b664dc977a 100644 --- a/src/ol/renderer/canvas/canvasmaprenderer.js +++ b/src/ol/renderer/canvas/canvasmaprenderer.js @@ -138,7 +138,7 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { backgroundColor.r.toFixed(0) + ',' + backgroundColor.g.toFixed(0) + ',' + backgroundColor.b.toFixed(0) + ')'; - context.globalAlpha = backgroundColor.a; + context.globalAlpha = 1; context.fillRect(0, 0, size.width, size.height); goog.array.forEach(frameState.layersArray, function(layer) { From 0122c6cc0c1dc8c643f8e62a63a250c660e521d9 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Fri, 18 Jan 2013 00:17:09 +0100 Subject: [PATCH 24/29] Export ol.tilegrid.TileGridOptions --- src/objectliterals.exports | 7 +++++++ src/ol/tilegrid/tilegrid.exports | 1 + src/ol/tilegrid/tilegrid.js | 11 ----------- 3 files changed, 8 insertions(+), 11 deletions(-) create mode 100644 src/ol/tilegrid/tilegrid.exports diff --git a/src/objectliterals.exports b/src/objectliterals.exports index 9ba2c520b3..a7499dc259 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -63,6 +63,13 @@ @exportObjectLiteralProperty ol.source.TiledWMSOptions.url string|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.urls Array.|undefined +@exportObjectLiteral ol.tilegrid.TileGridOptions +@exportObjectLiteralProperty ol.tilegrid.TileGridOptions.extent ol.Extent|undefined +@exportObjectLiteralProperty ol.tilegrid.TileGridOptions.origin ol.Coordinate|undefined +@exportObjectLiteralProperty ol.tilegrid.TileGridOptions.origins Array.|undefined +@exportObjectLiteralProperty ol.tilegrid.TileGridOptions.resolutions !Array. +@exportObjectLiteralProperty ol.tilegrid.TileGridOptions.tileSize ol.Size|undefined + @exportObjectLiteral ol.View2DOptions @exportObjectLiteralProperty ol.View2DOptions.center ol.Coordinate|undefined @exportObjectLiteralProperty ol.View2DOptions.maxResolution number|undefined diff --git a/src/ol/tilegrid/tilegrid.exports b/src/ol/tilegrid/tilegrid.exports new file mode 100644 index 0000000000..f276cab084 --- /dev/null +++ b/src/ol/tilegrid/tilegrid.exports @@ -0,0 +1 @@ +@exportClass ol.tilegrid.TileGrid ol.tilegrid.TileGridOptions diff --git a/src/ol/tilegrid/tilegrid.js b/src/ol/tilegrid/tilegrid.js index 6edd839fa9..188692861c 100644 --- a/src/ol/tilegrid/tilegrid.js +++ b/src/ol/tilegrid/tilegrid.js @@ -1,7 +1,6 @@ // FIXME cope with tile grids whose minium zoom is not zero goog.provide('ol.tilegrid.TileGrid'); -goog.provide('ol.tilegrid.TileGridOptions'); goog.require('goog.array'); goog.require('goog.asserts'); @@ -20,16 +19,6 @@ goog.require('ol.array'); ol.DEFAULT_TILE_SIZE = 256; -/** - * @typedef {{extent: (ol.Extent|undefined), - * origin: (ol.Coordinate|undefined), - * origins: (Array.|undefined), - * resolutions: !Array., - * tileSize: (ol.Size|undefined)}} - */ -ol.tilegrid.TileGridOptions; - - /** * @constructor From 4f2c657cf2a683066cfd1e3698ab8fb448f2e49c Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Fri, 18 Jan 2013 00:17:35 +0100 Subject: [PATCH 25/29] Export ol.tilegrid.XYZOptions --- src/objectliterals.exports | 3 +++ src/ol/tilegrid/xyztilegrid.exports | 1 + src/ol/tilegrid/xyztilegrid.js | 7 ------- 3 files changed, 4 insertions(+), 7 deletions(-) create mode 100644 src/ol/tilegrid/xyztilegrid.exports diff --git a/src/objectliterals.exports b/src/objectliterals.exports index a7499dc259..4b5c7c6383 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -70,6 +70,9 @@ @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.resolutions !Array. @exportObjectLiteralProperty ol.tilegrid.TileGridOptions.tileSize ol.Size|undefined +@exportObjectLiteral ol.tilegrid.XYZOptions +@exportObjectLiteralProperty ol.tilegrid.XYZOptions.maxZoom number + @exportObjectLiteral ol.View2DOptions @exportObjectLiteralProperty ol.View2DOptions.center ol.Coordinate|undefined @exportObjectLiteralProperty ol.View2DOptions.maxResolution number|undefined diff --git a/src/ol/tilegrid/xyztilegrid.exports b/src/ol/tilegrid/xyztilegrid.exports new file mode 100644 index 0000000000..dd5b52245c --- /dev/null +++ b/src/ol/tilegrid/xyztilegrid.exports @@ -0,0 +1 @@ +@exportClass ol.tilegrid.XYZ ol.tilegrid.XYZOptions diff --git a/src/ol/tilegrid/xyztilegrid.js b/src/ol/tilegrid/xyztilegrid.js index aa30336997..b7b16faf60 100644 --- a/src/ol/tilegrid/xyztilegrid.js +++ b/src/ol/tilegrid/xyztilegrid.js @@ -1,5 +1,4 @@ goog.provide('ol.tilegrid.XYZ'); -goog.provide('ol.tilegrid.XYZOptions'); goog.require('ol.Coordinate'); goog.require('ol.Projection'); @@ -8,12 +7,6 @@ goog.require('ol.TileRange'); goog.require('ol.tilegrid.TileGrid'); -/** - * @typedef {{maxZoom: number}} - */ -ol.tilegrid.XYZOptions; - - /** * @constructor From 76e600d5f66eccd8b856625c1633e7d7da2501f9 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Fri, 18 Jan 2013 00:18:41 +0100 Subject: [PATCH 26/29] Fix Stamen exports --- src/objectliterals.exports | 4 ++++ src/ol/source/stamen.exports | 19 +++++++++++++++++++ src/ol/source/stamensource.js | 12 +++--------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/objectliterals.exports b/src/objectliterals.exports index 4b5c7c6383..171672ef67 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -51,6 +51,10 @@ @exportObjectLiteralProperty ol.source.BingMapsOptions.key string @exportObjectLiteralProperty ol.source.BingMapsOptions.style ol.BingMapsStyle +@exportObjectLiteral ol.source.StamenOptions +@exportObjectLiteralProperty ol.source.StamenOptions.flavor string|undefined +@exportObjectLiteralProperty ol.source.StamenOptions.provider string + @exportObjectLiteral ol.source.TiledWMSOptions @exportObjectLiteralProperty ol.source.TiledWMSOptions.attributions Array.|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.params Object diff --git a/src/ol/source/stamen.exports b/src/ol/source/stamen.exports index bc110646c5..40b2c8b0e7 100644 --- a/src/ol/source/stamen.exports +++ b/src/ol/source/stamen.exports @@ -1,2 +1,21 @@ @exportSymbol ol.source.Stamen +@exportSymbol ol.source.StamenFlavor +@exportProperty ol.source.StamenFlavor.TERRAIN_BACKGROUND +@exportProperty ol.source.StamenFlavor.TERRAIN_LABELS +@exportProperty ol.source.StamenFlavor.TERRAIN_LINES +@exportProperty ol.source.StamenFlavor.TONER_2010 +@exportProperty ol.source.StamenFlavor.TONER_2011 +@exportProperty ol.source.StamenFlavor.TONER_2011_LABELS +@exportProperty ol.source.StamenFlavor.TONER_2011_LINES +@exportProperty ol.source.StamenFlavor.TONER_2011_LITE +@exportProperty ol.source.StamenFlavor.TONER_BACKGROUND +@exportProperty ol.source.StamenFlavor.TONER_HYBRID +@exportProperty ol.source.StamenFlavor.TONER_LABELS +@exportProperty ol.source.StamenFlavor.TONER_LINES +@exportProperty ol.source.StamenFlavor.TONER_LITE + +@exportSymbol ol.source.StamenProvider +@exportProperty ol.source.StamenProvider.TERRAIN +@exportProperty ol.source.StamenProvider.TONER +@exportProperty ol.source.StamenProvider.WATERCOLOR diff --git a/src/ol/source/stamensource.js b/src/ol/source/stamensource.js index 089f8ece76..6c68e8e720 100644 --- a/src/ol/source/stamensource.js +++ b/src/ol/source/stamensource.js @@ -1,6 +1,8 @@ // FIXME Configure minZoom when supported by TileGrid goog.provide('ol.source.Stamen'); +goog.provide('ol.source.StamenFlavor'); +goog.provide('ol.source.StamenProvider'); goog.require('ol.source.XYZ'); @@ -25,13 +27,6 @@ ol.source.StamenFlavor = { }; -/** - * @typedef {{flavor: (ol.source.StamenFlavor|undefined), - * provider: ol.source.StamenProvider}} - */ -ol.source.StamenOptions; - - /** * @enum {string} */ @@ -43,8 +38,7 @@ ol.source.StamenProvider = { /** - * @type {Object.} + * @type {Object.} */ ol.source.StamenProviderConfig = {}; ol.source.StamenProviderConfig[ol.source.StamenProvider.TERRAIN] = { From d34a71e453abd57d59b9abb9c811db5b5dc07817 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Fri, 18 Jan 2013 00:19:22 +0100 Subject: [PATCH 27/29] Export ol.RendererHints.createFromQueryData --- src/ol/map.exports | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ol/map.exports b/src/ol/map.exports index 85ac465dfd..b8cb394c18 100644 --- a/src/ol/map.exports +++ b/src/ol/map.exports @@ -7,4 +7,5 @@ @exportProperty ol.RendererHint.DOM @exportProperty ol.RendererHint.WEBGL - +@exportSymbol ol.RendererHints +@exportProperty ol.RendererHints.createFromQueryData From e3c85dec8e6046fd527e2674c3ad9d58c9e51470 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Fri, 18 Jan 2013 00:19:45 +0100 Subject: [PATCH 28/29] Export ol.View2D --- src/ol/view2d.exports | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/ol/view2d.exports diff --git a/src/ol/view2d.exports b/src/ol/view2d.exports new file mode 100644 index 0000000000..aada08d7f3 --- /dev/null +++ b/src/ol/view2d.exports @@ -0,0 +1 @@ +@exportClass ol.View2D ol.View2DOptions From bb5170994577bb1fe0d8a71636a5a9b7852b2469 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Fri, 18 Jan 2013 00:34:43 +0100 Subject: [PATCH 29/29] Use OpenStreetMap tiles in canvas tiles example Stamen exports aren't quite right yet. --- examples/canvas-tiles.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/canvas-tiles.js b/examples/canvas-tiles.js index 92c3f15046..d8a0951754 100644 --- a/examples/canvas-tiles.js +++ b/examples/canvas-tiles.js @@ -5,14 +5,12 @@ goog.require('ol.Projection'); goog.require('ol.RendererHint'); goog.require('ol.layer.TileLayer'); goog.require('ol.source.DebugTileSource'); -goog.require('ol.source.Stamen'); +goog.require('ol.source.OpenStreetMap'); var layers = new ol.Collection([ new ol.layer.TileLayer({ - source: new ol.source.Stamen({ - provider: ol.source.StamenProvider.WATERCOLOR - }) + source: new ol.source.OpenStreetMap() }), new ol.layer.TileLayer({ source: new ol.source.DebugTileSource({