diff --git a/src/ol/source/singleimagewmssource.js b/src/ol/source/singleimagewmssource.js index c1b9f1dd0d..4f8e4f99b6 100644 --- a/src/ol/source/singleimagewmssource.js +++ b/src/ol/source/singleimagewmssource.js @@ -1,8 +1,11 @@ goog.provide('ol.source.SingleImageWMS'); +goog.require('goog.asserts'); +goog.require('goog.uri.utils'); goog.require('ol.Image'); goog.require('ol.ImageUrlFunction'); goog.require('ol.extent'); +goog.require('ol.source.FeatureInfoSource'); goog.require('ol.source.ImageSource'); goog.require('ol.source.wms'); @@ -11,6 +14,7 @@ goog.require('ol.source.wms'); /** * @constructor * @extends {ol.source.ImageSource} + * @implements {ol.source.FeatureInfoSource} * @param {ol.source.SingleImageWMSOptions} options Options. */ ol.source.SingleImageWMS = function(options) { @@ -28,6 +32,13 @@ ol.source.SingleImageWMS = function(options) { imageUrlFunction: imageUrlFunction }); + /** + * @private + * @type {ol.source.WMSGetFeatureInfoOptions} + */ + this.getFeatureInfoOptions_ = goog.isDef(options.getFeatureInfoOptions) ? + options.getFeatureInfoOptions : {}; + /** * @private * @type {ol.Image} @@ -68,3 +79,30 @@ ol.source.SingleImageWMS.prototype.getImage = this.image_ = this.createImage(extent, resolution, size, projection); return this.image_; }; + + +/** + * @inheritDoc + */ +ol.source.SingleImageWMS.prototype.getFeatureInfoForPixel = + function(pixel, map, success, opt_error) { + var view2D = map.getView().getView2D(), + projection = view2D.getProjection(), + size = map.getSize(), + bottomLeft = map.getCoordinateFromPixel([0, size[1]]), + topRight = map.getCoordinateFromPixel([size[0], 0]), + extent = [bottomLeft[0], topRight[0], bottomLeft[1], topRight[1]], + x = pixel[0], + y = pixel[1], + url = this.imageUrlFunction(extent, size, projection); + goog.asserts.assert(goog.isDef(url), + 'ol.source.SingleImageWMS#imageUrlFunction does not return a url'); + // TODO: X, Y is for WMS 1.1 and I, J for 1.3 - without a closure url + // function this could be set conditionally. + url = goog.uri.utils.appendParamsFromMap(url, { + 'X': x, 'I': x, + 'Y': y, 'J': y + }); + ol.source.wms.getFeatureInfo(url, this.getFeatureInfoOptions_, success, + opt_error); +}; diff --git a/src/ol/source/tiledwmssource.js b/src/ol/source/tiledwmssource.js index b2ee6562f7..0211c5d0b6 100644 --- a/src/ol/source/tiledwmssource.js +++ b/src/ol/source/tiledwmssource.js @@ -3,10 +3,13 @@ goog.provide('ol.source.TiledWMS'); goog.require('goog.array'); +goog.require('goog.asserts'); goog.require('goog.math'); +goog.require('goog.uri.utils'); goog.require('ol.TileCoord'); goog.require('ol.TileUrlFunction'); goog.require('ol.extent'); +goog.require('ol.source.FeatureInfoSource'); goog.require('ol.source.ImageTileSource'); goog.require('ol.source.wms'); @@ -15,9 +18,11 @@ goog.require('ol.source.wms'); /** * @constructor * @extends {ol.source.ImageTileSource} + * @implements {ol.source.FeatureInfoSource} * @param {ol.source.TiledWMSOptions} options Tiled WMS options. */ ol.source.TiledWMS = function(options) { + var tileGrid; if (goog.isDef(options.tileGrid)) { tileGrid = options.tileGrid; @@ -28,6 +33,7 @@ ol.source.TiledWMS = function(options) { if (!goog.isDef(urls) && goog.isDef(options.url)) { urls = ol.TileUrlFunction.expandUrl(options.url); } + if (goog.isDef(urls)) { var tileUrlFunctions = goog.array.map( urls, function(url) { @@ -81,5 +87,42 @@ ol.source.TiledWMS = function(options) { tileCoordTransform, tileUrlFunction) }); + /** + * @private + * @type {ol.source.WMSGetFeatureInfoOptions} + */ + this.getFeatureInfoOptions_ = goog.isDef(options.getFeatureInfoOptions) ? + options.getFeatureInfoOptions : {}; + }; goog.inherits(ol.source.TiledWMS, ol.source.ImageTileSource); + + +/** + * @inheritDoc + */ +ol.source.TiledWMS.prototype.getFeatureInfoForPixel = + function(pixel, map, success, opt_error) { + var coord = map.getCoordinateFromPixel(pixel), + view2D = map.getView().getView2D(), + projection = view2D.getProjection(), + tileGrid = goog.isNull(this.tileGrid) ? + ol.tilegrid.getForProjection(projection) : tileGrid, + tileCoord = tileGrid.getTileCoordForCoordAndResolution(coord, + view2D.getResolution()), + tileExtent = tileGrid.getTileCoordExtent(tileCoord), + offset = map.getPixelFromCoordinate(ol.extent.getTopLeft(tileExtent)), + x = Math.round(pixel[0] - offset[0]), + y = Math.round(pixel[1] - offset[1]), + url = this.tileUrlFunction(tileCoord, projection); + goog.asserts.assert(goog.isDef(url), + 'ol.source.TiledWMS#tileUrlFunction does not return a url'); + // TODO: X, Y is for WMS 1.1 and I, J for 1.3 - without a closure url + // function this could be set conditionally. + url = goog.uri.utils.appendParamsFromMap(url, { + 'X': x, 'I': x, + 'Y': y, 'J': y + }); + ol.source.wms.getFeatureInfo(url, this.getFeatureInfoOptions_, success, + opt_error); +}; diff --git a/src/ol/source/wmssource.exports b/src/ol/source/wmssource.exports new file mode 100644 index 0000000000..7e9a24f714 --- /dev/null +++ b/src/ol/source/wmssource.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.WMSGetFeatureInfoMethod diff --git a/src/ol/source/wmssource.js b/src/ol/source/wmssource.js index 9eb6e22be7..fa9c308b5c 100644 --- a/src/ol/source/wmssource.js +++ b/src/ol/source/wmssource.js @@ -1,9 +1,29 @@ +goog.provide('ol.source.WMSGetFeatureInfoMethod'); goog.provide('ol.source.wms'); +goog.require('goog.net.XhrIo'); goog.require('goog.object'); goog.require('goog.uri.utils'); +/** + * Method to use to get WMS feature info. + * @enum {string} + */ +ol.source.WMSGetFeatureInfoMethod = { + /** + * Load the info in an IFRAME. Only works with 'text/html and 'text/plain' as + * `INFO_FORMAT`. + */ + IFRAME: 'iframe', + /** + * Use an asynchronous GET request. Requires CORS headers or a server at the + * same origin as the application script. + */ + XHR_GET: 'xhr_get' +}; + + /** * @param {string} baseUrl WMS base url. * @param {Object.} params Request parameters. @@ -40,3 +60,43 @@ ol.source.wms.getUrl = return goog.uri.utils.appendParamsFromMap(baseUrl, baseParams); }; + + +/** + * @param {string} url URL as provided by the url function, with added I, J, X + * and Y params. + * @param {Object} options Options as defined in the source. + * @param {function(string)} success Callback function for successful queries. + * @param {function()=} opt_error Optional callback function for unsuccessful + * queries. + */ +ol.source.wms.getFeatureInfo = function(url, options, success, opt_error) { + options = goog.isDef(options) ? goog.object.clone(options) : {}; + goog.object.extend(options, { + method: ol.source.WMSGetFeatureInfoMethod.IFRAME, + params: {} + }); + var params = { + 'INFO_FORMAT': 'text/html' + }; + goog.object.extend(params, options.params); + url = goog.uri.utils.appendParamsFromMap(url, params); + // TODO: This could be done in a smarter way if the url function was not a + // closure + url = url.replace('REQUEST=GetMap', 'REQUEST=GetFeatureInfo') + .replace(/LAYERS=([^&]+)/, 'LAYERS=$1&QUERY_LAYERS=$1'); + if (options.method == ol.source.WMSGetFeatureInfoMethod.IFRAME) { + goog.global.setTimeout(function() { + success('