diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index 77f8234587..12b8e29b33 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -49,6 +49,12 @@ ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer) { */ this.renderedOpacity_ = 1; + /** + * @private + * @type {number} + */ + this.renderedRevision_ = 0; + /** * @private * @type {Object.} @@ -145,6 +151,19 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = } + // If the tile source revision changes, we destroy the existing DOM structure + // so that a new one will be created. It would be more efficient to modify + // the existing structure. + var tileLayerZ, tileLayerZKey; + if (this.renderedRevision_ != tileSource.getRevision()) { + for (tileLayerZKey in this.tileLayerZs_) { + tileLayerZ = this.tileLayerZs_[+tileLayerZKey]; + goog.dom.removeNode(tileLayerZ.target); + } + this.tileLayerZs_ = {}; + this.renderedRevision_ = tileSource.getRevision(); + } + /** @type {Array.} */ var zs = goog.array.map(goog.object.getKeys(tilesToDrawByZ), Number); goog.array.sort(zs); @@ -152,8 +171,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = /** @type {Object.} */ var newTileLayerZKeys = {}; - var iz, iziz; - var tileCoordKey, tileCoordOrigin, tileLayerZ, tileLayerZKey, tilesToDraw; + var iz, iziz, tileCoordKey, tileCoordOrigin, tilesToDraw; for (iz = 0, iziz = zs.length; iz < iziz; ++iz) { tileLayerZKey = zs[iz]; if (tileLayerZKey in this.tileLayerZs_) { diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index 0c37253d65..915b75e0dd 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -72,6 +72,12 @@ ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) { */ this.renderedFramebufferExtent_ = null; + /** + * @private + * @type {number} + */ + this.renderedRevision_ = -1; + }; goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer); @@ -138,7 +144,8 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = var framebufferExtent; if (!goog.isNull(this.renderedTileRange_) && - this.renderedTileRange_.equals(tileRange)) { + this.renderedTileRange_.equals(tileRange) && + this.renderedRevision_ == tileSource.getRevision()) { framebufferExtent = this.renderedFramebufferExtent_; } else { @@ -255,9 +262,11 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = if (allTilesLoaded) { this.renderedTileRange_ = tileRange; this.renderedFramebufferExtent_ = framebufferExtent; + this.renderedRevision_ = tileSource.getRevision(); } else { this.renderedTileRange_ = null; this.renderedFramebufferExtent_ = null; + this.renderedRevision_ = -1; frameState.animate = true; } diff --git a/src/ol/source/debugtilesource.js b/src/ol/source/debugtilesource.js index df9f2cf0d1..8c53bce520 100644 --- a/src/ol/source/debugtilesource.js +++ b/src/ol/source/debugtilesource.js @@ -125,7 +125,7 @@ ol.source.TileDebug.prototype.expireCache = function(usedTiles) { * @inheritDoc */ ol.source.TileDebug.prototype.getTile = function(z, x, y) { - var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y); + var tileCoordKey = this.getKeyZXY(z, x, y); if (this.tileCache_.containsKey(tileCoordKey)) { return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(tileCoordKey)); } else { diff --git a/src/ol/source/imagetilesource.js b/src/ol/source/imagetilesource.js index f26aa9f4b0..453dd29126 100644 --- a/src/ol/source/imagetilesource.js +++ b/src/ol/source/imagetilesource.js @@ -90,7 +90,7 @@ ol.source.TileImage.prototype.expireCache = function(usedTiles) { * @inheritDoc */ ol.source.TileImage.prototype.getTile = function(z, x, y, projection) { - var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y); + var tileCoordKey = this.getKeyZXY(z, x, y); if (this.tileCache_.containsKey(tileCoordKey)) { return /** @type {!ol.Tile} */ (this.tileCache_.get(tileCoordKey)); } else { @@ -112,7 +112,7 @@ ol.source.TileImage.prototype.getTile = function(z, x, y, projection) { * @inheritDoc */ ol.source.TileImage.prototype.useTile = function(z, x, y) { - var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y); + var tileCoordKey = this.getKeyZXY(z, x, y); if (this.tileCache_.containsKey(tileCoordKey)) { this.tileCache_.get(tileCoordKey); } diff --git a/src/ol/source/singleimagewmssource.exports b/src/ol/source/singleimagewmssource.exports index 17486b875c..393cd6406a 100644 --- a/src/ol/source/singleimagewmssource.exports +++ b/src/ol/source/singleimagewmssource.exports @@ -1 +1,3 @@ @exportClass ol.source.SingleImageWMS ol.source.SingleImageWMSOptions +@exportProperty ol.source.SingleImageWMS.prototype.getParams +@exportProperty ol.source.SingleImageWMS.prototype.updateParams diff --git a/src/ol/source/singleimagewmssource.js b/src/ol/source/singleimagewmssource.js index 4e2fe097e0..2d82b35da5 100644 --- a/src/ol/source/singleimagewmssource.js +++ b/src/ol/source/singleimagewmssource.js @@ -1,6 +1,7 @@ goog.provide('ol.source.SingleImageWMS'); goog.require('goog.asserts'); +goog.require('goog.object'); goog.require('ol.Image'); goog.require('ol.ImageUrlFunction'); goog.require('ol.extent'); @@ -17,9 +18,16 @@ goog.require('ol.source.wms'); * @param {ol.source.SingleImageWMSOptions} options Options. */ ol.source.SingleImageWMS = function(options) { + + /** + * @private + * @type {Object} + */ + this.params_ = options.params; + var imageUrlFunction = goog.isDef(options.url) ? ol.ImageUrlFunction.createFromParamsFunction( - options.url, options.params, ol.source.wms.getUrl) : + options.url, this.params_, ol.source.wms.getUrl) : ol.ImageUrlFunction.nullImageUrlFunction; goog.base(this, { @@ -55,6 +63,16 @@ ol.source.SingleImageWMS = function(options) { goog.inherits(ol.source.SingleImageWMS, ol.source.Image); +/** + * Get the user-provided params, i.e. those passed to the constructor through + * the "params" option, and possibly updated using the updateParams method. + * @return {Object} Params. + */ +ol.source.SingleImageWMS.prototype.getParams = function() { + return this.params_; +}; + + /** * @inheritDoc */ @@ -97,3 +115,14 @@ ol.source.SingleImageWMS.prototype.getFeatureInfoForPixel = ol.source.wms.getFeatureInfo(url, pixel, this.getFeatureInfoOptions_, success, opt_error); }; + + +/** + * Update the user-provided params. + * @param {Object} params Params. + */ +ol.source.SingleImageWMS.prototype.updateParams = function(params) { + goog.object.extend(this.params_, params); + this.image_ = null; + this.dispatchChangeEvent(); +}; diff --git a/src/ol/source/source.js b/src/ol/source/source.js index 7d1cf9bc43..0072d8f60e 100644 --- a/src/ol/source/source.js +++ b/src/ol/source/source.js @@ -45,6 +45,12 @@ ol.source.Source = function(options) { */ this.logo_ = options.logo; + /** + * @private + * @type {number} + */ + this.revision_ = 0; + }; goog.inherits(ol.source.Source, goog.events.EventTarget); @@ -53,6 +59,7 @@ goog.inherits(ol.source.Source, goog.events.EventTarget); * @protected */ ol.source.Source.prototype.dispatchChangeEvent = function() { + ++this.revision_; this.dispatchEvent(goog.events.EventType.CHANGE); }; @@ -61,6 +68,7 @@ ol.source.Source.prototype.dispatchChangeEvent = function() { * @protected */ ol.source.Source.prototype.dispatchLoadEvent = function() { + ++this.revision_; this.dispatchEvent(goog.events.EventType.LOAD); }; @@ -103,6 +111,14 @@ ol.source.Source.prototype.getProjection = function() { ol.source.Source.prototype.getResolutions = goog.abstractMethod; +/** + * @return {number} Revision. + */ +ol.source.Source.prototype.getRevision = function() { + return this.revision_; +}; + + /** * @return {boolean} Is ready. */ diff --git a/src/ol/source/tiledwmssource.exports b/src/ol/source/tiledwmssource.exports index e71fa0bce2..94fb2c22b3 100644 --- a/src/ol/source/tiledwmssource.exports +++ b/src/ol/source/tiledwmssource.exports @@ -1 +1,3 @@ @exportClass ol.source.TileWMS ol.source.TileWMSOptions +@exportProperty ol.source.TileWMS.prototype.getParams +@exportProperty ol.source.TileWMS.prototype.updateParams diff --git a/src/ol/source/tiledwmssource.js b/src/ol/source/tiledwmssource.js index bb5cb54ed3..8a9ae3e153 100644 --- a/src/ol/source/tiledwmssource.js +++ b/src/ol/source/tiledwmssource.js @@ -5,6 +5,7 @@ goog.provide('ol.source.TileWMS'); goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.math'); +goog.require('goog.object'); goog.require('ol.TileCoord'); goog.require('ol.TileUrlFunction'); goog.require('ol.extent'); @@ -33,12 +34,25 @@ ol.source.TileWMS = function(options) { urls = ol.TileUrlFunction.expandUrl(options.url); } + /** + * @private + * @type {Object} + */ + this.params_ = options.params; + + /** + * @private + * @type {string} + */ + this.coordKeyPrefix_ = ''; + this.resetCoordKeyPrefix_(); + if (goog.isDef(urls)) { var tileUrlFunctions = goog.array.map( urls, function(url) { return ol.TileUrlFunction.createFromParamsFunction( - url, options.params, ol.source.wms.getUrl); - }); + url, this.params_, ol.source.wms.getUrl); + }, this); tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( tileUrlFunctions); } @@ -97,6 +111,24 @@ ol.source.TileWMS = function(options) { goog.inherits(ol.source.TileWMS, ol.source.TileImage); +/** + * @inheritDoc + */ +ol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) { + return this.coordKeyPrefix_ + goog.base(this, 'getKeyZXY', z, x, y); +}; + + +/** + * Get the user-provided params, i.e. those passed to the constructor through + * the "params" option, and possibly updated using the updateParams method. + * @return {Object} Params. + */ +ol.source.TileWMS.prototype.getParams = function() { + return this.params_; +}; + + /** * @inheritDoc */ @@ -118,3 +150,27 @@ ol.source.TileWMS.prototype.getFeatureInfoForPixel = [pixel[0] - offset[0], pixel[1] - offset[1]], this.getFeatureInfoOptions_, success, opt_error); }; + + +/** + * @private + */ +ol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() { + var i = 0; + var res = []; + for (var key in this.params_) { + res[i++] = key + '-' + this.params_[key]; + } + this.coordKeyPrefix_ = res.join('/'); +}; + + +/** + * Update the user-provided params. + * @param {Object} params Params. + */ +ol.source.TileWMS.prototype.updateParams = function(params) { + goog.object.extend(this.params_, params); + this.resetCoordKeyPrefix_(); + this.dispatchChangeEvent(); +}; diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js index 2f05579f65..c357a8dbd7 100644 --- a/src/ol/source/tilesource.js +++ b/src/ol/source/tilesource.js @@ -85,7 +85,7 @@ ol.source.Tile.prototype.findLoadedTiles = function(loadedTilesByZ, var tile, tileCoordKey, x, y; for (x = tileRange.minX; x <= tileRange.maxX; ++x) { for (y = tileRange.minY; y <= tileRange.maxY; ++y) { - tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y); + tileCoordKey = this.getKeyZXY(z, x, y); if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) { continue; } @@ -104,6 +104,18 @@ ol.source.Tile.prototype.findLoadedTiles = function(loadedTilesByZ, }; +/** + * @param {number} z Z. + * @param {number} x X. + * @param {number} y Y. + * @return {string} Key. + * @protected + */ +ol.source.Tile.prototype.getKeyZXY = function(z, x, y) { + return ol.TileCoord.getKeyZXY(z, x, y); +}; + + /** * @return {boolean} Opaque. */ diff --git a/src/ol/source/wmtssource.exports b/src/ol/source/wmtssource.exports index ef840a8124..f29f7d0ec5 100644 --- a/src/ol/source/wmtssource.exports +++ b/src/ol/source/wmtssource.exports @@ -1,2 +1,4 @@ @exportClass ol.source.WMTS ol.source.WMTSOptions +@exportProperty ol.source.WMTS.prototype.getDimensions +@exportProperty ol.source.WMTS.prototype.updateDimensions @exportSymbol ol.source.WMTS.optionsFromCapabilities diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js index 8db43772df..0a44eede2c 100644 --- a/src/ol/source/wmtssource.js +++ b/src/ol/source/wmtssource.js @@ -36,7 +36,19 @@ ol.source.WMTS = function(options) { var version = goog.isDef(options.version) ? options.version : '1.0.0'; var format = goog.isDef(options.format) ? options.format : 'image/jpeg'; - var dimensions = options.dimensions || {}; + + /** + * @private + * @type {Object} + */ + this.dimensions_ = options.dimensions || {}; + + /** + * @private + * @type {string} + */ + this.coordKeyPrefix_ = ''; + this.resetCoordKeyPrefix_(); // FIXME: should we guess this requestEncoding from options.url(s) // structure? that would mean KVP only if a template is not provided. @@ -53,19 +65,14 @@ ol.source.WMTS = function(options) { 'Style': options.style, 'TileMatrixSet': options.matrixSet }; - goog.object.extend(context, dimensions); - var kvpParams; + if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { - kvpParams = { + goog.object.extend(context, { 'Service': 'WMTS', 'Request': 'GetTile', 'Version': version, - 'Format': format, - 'TileMatrix': '{TileMatrix}', - 'TileRow': '{TileRow}', - 'TileCol': '{TileCol}' - }; - goog.object.extend(kvpParams, context); + 'Format': format + }); } /** @@ -73,6 +80,17 @@ ol.source.WMTS = function(options) { * @return {ol.TileUrlFunctionType} Tile URL function. */ function createFromWMTSTemplate(template) { + + // TODO: we may want to create our own appendParams function so that params + // order conforms to wmts spec guidance, and so that we can avoid to escape + // special template params + + template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ? + goog.uri.utils.appendParamsFromMap(template, context) : + template.replace(/\{(\w+?)\}/g, function(m, p) { + return (p in context) ? context[p] : m; + }); + return ( /** * @this {ol.source.WMTS} @@ -89,13 +107,14 @@ ol.source.WMTS = function(options) { 'TileCol': tileCoord.x, 'TileRow': tileCoord.y }; - if (requestEncoding != ol.source.WMTSRequestEncoding.KVP) { - goog.object.extend(localContext, context); - } + goog.object.extend(localContext, this.dimensions_); var url = template; - for (var key in localContext) { - url = url.replace('{' + key + '}', localContext[key]) - .replace('%7B' + key + '%7D', localContext[key]); + if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { + url = goog.uri.utils.appendParamsFromMap(url, localContext); + } else { + url = url.replace(/\{(\w+?)\}/g, function(m, p) { + return localContext[p]; + }); } return url; } @@ -109,15 +128,7 @@ ol.source.WMTS = function(options) { } if (goog.isDef(urls)) { tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions( - goog.array.map(urls, function(url) { - if (goog.isDef(kvpParams)) { - // TODO: we may want to create our own appendParams function - // so that params order conforms to wmts spec guidance, - // and so that we can avoid to escape special template params - url = goog.uri.utils.appendParamsFromMap(url, kvpParams); - } - return createFromWMTSTemplate(url); - })); + goog.array.map(urls, createFromWMTSTemplate)); } var tmpExtent = ol.extent.createEmpty(); @@ -173,6 +184,49 @@ ol.source.WMTS = function(options) { goog.inherits(ol.source.WMTS, ol.source.TileImage); +/** + * Get the dimensions, i.e. those passed to the constructor through the + * "dimensions" option, and possibly updated using the updateDimensions + * method. + * @return {Object} Dimensions. + */ +ol.source.WMTS.prototype.getDimensions = function() { + return this.dimensions_; +}; + + +/** + * @inheritDoc + */ +ol.source.WMTS.prototype.getKeyZXY = function(z, x, y) { + return this.coordKeyPrefix_ + goog.base(this, 'getKeyZXY', z, x, y); +}; + + +/** + * @private + */ +ol.source.WMTS.prototype.resetCoordKeyPrefix_ = function() { + var i = 0; + var res = []; + for (var key in this.dimensions_) { + res[i++] = key + '-' + this.dimensions_[key]; + } + this.coordKeyPrefix_ = res.join('/'); +}; + + +/** + * Update the dimensions. + * @param {Object} dimensions Dimensions. + */ +ol.source.WMTS.prototype.updateDimensions = function(dimensions) { + goog.object.extend(this.dimensions_, dimensions); + this.resetCoordKeyPrefix_(); + this.dispatchChangeEvent(); +}; + + /** * @param {Object} wmtsCap An object representing the capabilities document. * @param {string} layer The layer identifier.