From 711d412f887a3d074a16a8e051fe3aa0d5247a65 Mon Sep 17 00:00:00 2001 From: bartvde Date: Wed, 9 Dec 2009 14:29:48 +0000 Subject: [PATCH] WMSGetFeatureInfo control: add support for mutiple WMS services, r=ahocevar (closes #2091) git-svn-id: http://svn.openlayers.org/trunk/openlayers@9874 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- lib/OpenLayers/Control/WMSGetFeatureInfo.js | 226 ++++++++++++++------ tests/Control/WMSGetFeatureInfo.html | 45 ++++ 2 files changed, 204 insertions(+), 67 deletions(-) diff --git a/lib/OpenLayers/Control/WMSGetFeatureInfo.js b/lib/OpenLayers/Control/WMSGetFeatureInfo.js index 82553298d1..6fdc14b33c 100644 --- a/lib/OpenLayers/Control/WMSGetFeatureInfo.js +++ b/lib/OpenLayers/Control/WMSGetFeatureInfo.js @@ -31,6 +31,14 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { */ hover: false, + /** + * APIProperty: drillDown + * {Boolean} Drill down over all WMS layers in the map. When + * using drillDown mode, hover is not possible, and an infoFormat that + * returns parseable features is required. Default is false. + */ + drillDown: false, + /** * APIProperty: maxFeatures * {Integer} Maximum number of features to return from a WMS query. This @@ -139,7 +147,10 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { * response (String), a *features* property with an array of the * parsed features, an *xy* property with the position of the mouse * click or hover event that triggered the request, and a *request* - * property with the request itself. + * property with the request itself. If drillDown is set to true and + * multiple requests were issued to collect feature info from all + * layers, *text* and *request* will only contain the response body + * and request object of the last request. */ EVENT_TYPES: ["beforegetfeatureinfo", "getfeatureinfo"], @@ -166,8 +177,12 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { options.formatOptions ); } + + if(this.drillDown === true) { + this.hover = false; + } - if (this.hover) { + if(this.hover) { this.handler = new OpenLayers.Handler.Hover( this, { 'move': this.cancelHover, @@ -256,9 +271,8 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { */ findLayers: function() { - var layers = []; - var candidates = this.layers || this.map.layers; + var layers = []; var layer, url; for(var i=0, len=candidates.length; i} The position on the map where the mouse + * event occurred. + * format - {String} The format from the corresponding GetMap request + */ + buildWMSOptions: function(url, layers, clickPosition, format) { + var layerNames = [], styleNames = []; + for (var i = 0, len = layers.length; i < len; i++) { + layerNames = layerNames.concat(layers[i].params.LAYERS); + styleNames = styleNames.concat(this.getStyleNames(layers[i])); + } + return { + url: url, + params: OpenLayers.Util.applyDefaults({ + service: "WMS", + version: "1.1.0", + request: "GetFeatureInfo", + layers: layerNames, + query_layers: layerNames, + styles: styleNames, + bbox: this.map.getExtent().toBBOX(), + srs: this.map.getProjection(), + feature_count: this.maxFeatures, + x: clickPosition.x, + y: clickPosition.y, + height: this.map.getSize().h, + width: this.map.getSize().w, + format: format, + info_format: this.infoFormat + }, this.vendorParams), + callback: function(request) { + this.handleResponse(clickPosition, request); + }, + scope: this + }; + }, + + /** + * Method: getStyleNames + * Gets the STYLES parameter for the layer. Make sure the STYLES parameter + * matches the LAYERS parameter + * + * Parameters: + * layer - {} + * + * Returns: + * {Array(String)} The STYLES parameter + */ + getStyleNames: function(layer) { + // in the event of a WMS layer bundling multiple layers but not + // specifying styles,we need the same number of commas to specify + // the default style for each of the layers. We can't just leave it + // blank as we may be including other layers that do specify styles. + var styleNames; + if (layer.params.STYLES) { + styleNames = layer.params.STYLES; + } else { + if (layer.params.LAYERS instanceof Array) { + styleNames = new Array(layer.params.LAYERS.length); + } else { // Assume it's a String + styleNames = layer.params.LAYERS.replace(/[^,]/g, ""); + } + } + return styleNames; + }, + /** * Method: request * Sends a GetFeatureInfo request to the WMS @@ -317,65 +402,70 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { * - *hover* {Boolean} true if we do the request for the hover handler */ request: function(clickPosition, options) { - options = options || {}; - var layerNames = []; - var styleNames = []; - var layers = this.findLayers(); - if(layers.length > 0) { - - for (var i = 0, len = layers.length; i < len; i++) { - layerNames = layerNames.concat(layers[i].params.LAYERS); - // in the event of a WMS layer bundling multiple layers but not - // specifying styles,we need the same number of commas to specify - // the default style for each of the layers. We can't just leave it - // blank as we may be including other layers that do specify styles. - if (layers[i].params.STYLES) { - styleNames = styleNames.concat(layers[i].params.STYLES); - } else { - if (layers[i].params.LAYERS instanceof Array) { - styleNames = styleNames.concat(new Array(layers[i].params.LAYERS.length)); - } else { // Assume it's a String - styleNames = styleNames.concat(layers[i].params.LAYERS.replace(/[^,]/g, "")); - } - } - } - - var wmsOptions = { - url: this.url, - params: OpenLayers.Util.applyDefaults({ - service: "WMS", - version: "1.1.0", - request: "GetFeatureInfo", - layers: layerNames, - query_layers: layerNames, - styles: styleNames, - bbox: this.map.getExtent().toBBOX(), - srs: this.map.getProjection(), - feature_count: this.maxFeatures, - x: clickPosition.x, - y: clickPosition.y, - height: this.map.getSize().h, - width: this.map.getSize().w, - format: layers[0].params.FORMAT, - info_format: this.infoFormat - }, this.vendorParams), - callback: function(request) { - this.handleResponse(clickPosition, request); - }, - scope: this - }; - + if(layers.length == 0) { + // Reset the cursor. + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); + return; + } + + options = options || {}; + if(this.drillDown === false) { + var wmsOptions = this.buildWMSOptions(this.url, layers, + clickPosition, layers[0].params.FORMAT); var response = OpenLayers.Request.GET(wmsOptions); if (options.hover === true) { this.hoverRequest = response.priv; } } else { - // Reset the cursor. - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); + this._requestCount = 0; + this._numRequests = 0; + this.features = []; + // group according to service url to combine requests + var services = {}, url; + for(var i=0, len=layers.length; i} The position on the map where the + * mouse event occurred. + * features - {Array()} + */ + triggerGetFeatureInfo: function(request, xy, features) { + this.events.triggerEvent("getfeatureinfo", { + text: request.responseText, + features: features, + request: request, + xy: xy + }); + + // Reset the cursor. + OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); + }, /** * Method: handleResponse @@ -393,16 +483,18 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { doc = request.responseText; } var features = this.format.read(doc); - - this.events.triggerEvent("getfeatureinfo", { - text: request.responseText, - features: features, - request: request, - xy: xy - }); - - // Reset the cursor. - OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); + if (this.drillDown === false) { + this.triggerGetFeatureInfo(request, xy, features); + } else { + this._requestCount++; + this._features = (this._features || []).concat(features); + if (this._requestCount === this._numRequests) { + this.triggerGetFeatureInfo(request, xy, this._features.concat()); + delete this._features; + delete this._requestCount; + delete this._numRequests; + } + } }, /** diff --git a/tests/Control/WMSGetFeatureInfo.html b/tests/Control/WMSGetFeatureInfo.html index 29424c62b7..ad353ab07f 100644 --- a/tests/Control/WMSGetFeatureInfo.html +++ b/tests/Control/WMSGetFeatureInfo.html @@ -307,6 +307,51 @@ } + function test_drillDown(t) { + t.plan(4); + var map = new OpenLayers.Map("map", { + getExtent: function() {return(new OpenLayers.Bounds(-180,-90,180,90));} + } + ); + + var a = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", { + layers: "a" + }); + + var b = new OpenLayers.Layer.WMS("dummy","http://localhost/wms", { + layers: "c" + }); + + var c = new OpenLayers.Layer.WMS("dummy","http://myhost/wms", { + layers: "x" + }); + + map.addLayers([a, b, c]); + + var click = new OpenLayers.Control.WMSGetFeatureInfo({ + drillDown: true + }); + + map.addControl(click); + + var count = 0; + var _request = OpenLayers.Request.GET; + OpenLayers.Request.GET = function(options) { + count++; + if (count == 1) { + t.eq(options.params["query_layers"].join(","), "a,c", "Layers should be grouped by service url"); + t.eq(options.url, "http://localhost/wms", "Correct url used for first request"); + } else if (count == 2) { + t.eq(options.url, "http://myhost/wms", "Correct url used for second request"); + } + }; + click.activate(); + click.getInfoForClick({xy: {x: 50, y: 50}}); + OpenLayers.Request.GET = _request; + t.eq(count, 2, "We expect 2 requests to go off"); + map.destroy(); + } +