From 59c49eb98eafc03bcc30dae1ea1cb14f3e9cbd0c Mon Sep 17 00:00:00 2001 From: ahocevar Date: Wed, 1 Apr 2009 09:13:23 +0000 Subject: [PATCH] Added WMSGetFeatureInfo control. Thanks dwins for the patch. I made the following modifications: * WMSGetFeatureInfo class was contained twice in WMSGetFeatureInfo.js. Removed one. * Fixed @requires * Added vendorParams option (with test) to allow for e.g. adding custom params like RADIUS * Changed the clickPosition key in the getfeatureinfo event parameter to xy to comply with other event parameters in OpenLayers * Modified concatenation of layerNames and styleNames as proposed in my previous comment * Made a separate handleResponse function from the previously closured callback function and added xy to the scope * Fixed some ND comments, especially removed links (<..>) from object types that cannot be linked (e.g. {String}) * Inserted line breaks where lines exceeded 80 chars * Fixed test for format option, because this is now formats and has a different type * Fixed tests in the example (this is no US census data) * added ProxyHost and absolute WMS url to the example * removed custom format from the click handler in the example so users can also see the simpler instantiation with the default formats r=me (closes #2007) git-svn-id: http://svn.openlayers.org/trunk/openlayers@9159 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- examples/getfeatureinfo-control.html | 182 ++++++++++ lib/OpenLayers.js | 1 + lib/OpenLayers/Control/WMSGetFeatureInfo.js | 363 ++++++++++++++++++++ tests/Control/WMSGetFeatureInfo.html | 293 ++++++++++++++++ tests/list-tests.html | 1 + 5 files changed, 840 insertions(+) create mode 100644 examples/getfeatureinfo-control.html create mode 100644 lib/OpenLayers/Control/WMSGetFeatureInfo.js create mode 100644 tests/Control/WMSGetFeatureInfo.html diff --git a/examples/getfeatureinfo-control.html b/examples/getfeatureinfo-control.html new file mode 100644 index 0000000000..281cffdc10 --- /dev/null +++ b/examples/getfeatureinfo-control.html @@ -0,0 +1,182 @@ + + + OpenLayers WMS Feature Info Example (GeoServer) + + + + + + +

Feature Info Example

+ +
+ +

+ Demonstrates the WMSGetFeatureInfo control for fetching information about a position from WMS. +

+ +
+ +
+

South Africa

+

Click on the map to get feature info.

+
+
+
+
+ + +
+
+ + + + + diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 7f87255f4b..0ff5f9e070 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -163,6 +163,7 @@ "OpenLayers/Control/SelectFeature.js", "OpenLayers/Control/NavigationHistory.js", "OpenLayers/Control/Measure.js", + "OpenLayers/Control/WMSGetFeatureInfo.js", "OpenLayers/Geometry.js", "OpenLayers/Geometry/Rectangle.js", "OpenLayers/Geometry/Collection.js", diff --git a/lib/OpenLayers/Control/WMSGetFeatureInfo.js b/lib/OpenLayers/Control/WMSGetFeatureInfo.js new file mode 100644 index 0000000000..a35940af3b --- /dev/null +++ b/lib/OpenLayers/Control/WMSGetFeatureInfo.js @@ -0,0 +1,363 @@ +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Control.js + * @requires OpenLayers/Handler/Click.js + * @requires OpenLayers/Handler/Hover.js + * @requires OpenLayers/Request.js + */ + +/** + * Class: OpenLayers.Control.WMSGetFeatureInfo + * The WMSGetFeatureInfo control uses a WMS query to get information about a point on the map. The + * information may be in a display-friendly format such as HTML, or a machine-friendly format such + * as GML, depending on the server's capabilities and the client's configuration. This control + * handles click or hover events, attempts to parse the results using an OpenLayers.Format, and + * fires a 'getfeatureinfo' event with the click position, the raw body of the response, and an + * array of features if it successfully read the response. + * + * Inherits from: + * - + */ +OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, { + + /** + * APIProperty: hover + * {Boolean} Send WMS request on mouse moves. This will cause the + * "hoverfeature" and "outfeature" events to be triggered. + * Default is false. + */ + hover: false, + + /** + * APIProperty: maxFeatures + * {Integer} maximum number of features to return from a WMS query. This + * has the same effect as the feature_count parameter on WMS GetFeatureInfo + * requests. Will be ignored for box selections. + */ + maxFeatures: 10, + + /** + * Property: layers + * {} The Layer objects for which to find + * feature info. If omitted, search all WMS layers from the map whose url + * is the same as the one in this control's configuration. See the + * property + */ + layers: null, + + /** + * Property: queryVisible + * {Boolean} If true, filter out hidden layers when searching the map for + * layers to query. If an explicit layers parameter is set, then this does + * nothing. + */ + queryVisible: false, + + /** + * Property: url + * {String} The URL of the WMS service to use. + */ + url: null, + + /** + * Property: infoFormat + * {String} The mimetype to request from the server + */ + infoFormat: 'text/html', + + /** + * Property: vendorParams + * {Object} Additional parameters that will be added to the request, for + * WMS implementations that support them. This could e.g. look like + * (start code) + * { + * radius: 5 + * } + * (end) + */ + + /** + * Property: formats + * An object mapping from mime-types to OL Format objects to use when + * parsing GFI responses. The default mapping is + * (start code) + * { + * 'application/vnd.ogc.gml': new OpenLayers.Format.WMSGetFeatureInfo() + * } + * (end) + * An object provided here will extend the default mapping. + */ + formats: null, + + /** + * APIProperty: handlerOptions + * {Object} Additional options for the handlers used by this control, e.g. + * (start code) + * { + * "click": {delay: 100}, + * "hover": {delay: 300} + * } + * (end) + */ + handlerOptions: null, + + /** + * Property: handler + * {Object} Reference to the for this control + */ + handler: null, + + /** + * Property: hoverRequest + * {} contains the currently running hover request + * (if any). + */ + hoverRequest: null, + + /** + * Constant: EVENT_TYPES + * + * Supported event types: + * - *getfeatureinfo* Triggered when a GetFeatureInfo response is received. + * The event object has a text property with: + * text: a string containing the body of the response, + * features: an array of the parsed features, if parsing succeeded. + * xy: the position of the mouse click or hover event that + * triggered the request + */ + EVENT_TYPES: ["getfeatureinfo"], + + /** + * Constructor: + * + * Parameters: + * url - {String} + * options - {Object} + */ + initialize: function(url, options) { + // concatenate events specific to vector with those from the base + this.EVENT_TYPES = + OpenLayers.Control.WMSGetFeatureInfo.prototype.EVENT_TYPES.concat( + OpenLayers.Control.prototype.EVENT_TYPES + ); + + options = options || {}; + options.handlerOptions = options.handlerOptions || {}; + + OpenLayers.Control.prototype.initialize.apply(this, [options]); + this.url = url; + this.layers = options.layers; + + this.formats = OpenLayers.Util.extend({ + 'application/vnd.ogc.gml': new OpenLayers.Format.WMSGetFeatureInfo() + }, options.formats); + + + if (this.hover) { + this.handler = new OpenLayers.Handler.Hover( + this, { + 'move': this.cancelHover, + 'pause': this.getInfoForHover + }, + OpenLayers.Util.extend(this.handlerOptions.hover || {}, { + 'delay': 250 + })); + } else { + this.handler = new OpenLayers.Handler.Click(this, + {click: this.getInfoForClick}, this.handlerOptions.click || {}); + } + }, + + /** + * Method: activate + * Activates the control. + * + * Returns: + * {Boolean} The control was effectively activated. + */ + activate: function () { + if (!this.active) { + this.handler.activate(); + } + return OpenLayers.Control.prototype.activate.apply( + this, arguments + ); + }, + + /** + * Method: deactivate + * Deactivates the control. + * + * Returns: + * {Boolean} The control was effectively deactivated. + */ + deactivate: function () { + return OpenLayers.Control.prototype.deactivate.apply( + this, arguments + ); + }, + + /** + * Method: getInfoForClick + * Called on click + * + * Parameters: + * evt - {} + */ + getInfoForClick: function(evt) { + // Set the cursor to "wait" to tell the user we're working on their + // click. + OpenLayers.Element.addClass(this.map.div, "olCursorWait"); + this.request(evt.xy, {}); + }, + + /** + * Method: getInfoForHover + * Pause callback for the hover handler + * + * Parameters: + * evt - {Object} + */ + getInfoForHover: function(evt) { + this.request(evt.xy, {hover: true}); + }, + + /** + * Method: cancelHover + * Cancel callback for the hover handler + */ + cancelHover: function() { + if (this.hoverRequest) { + this.hoverRequest.abort(); + this.hoverRequest = null; + } + }, + + /** + * Method: findLayers + * Internal method to get the layers, independent of whether we are + * inspecting the map or using a client-provided array + */ + findLayers: function() { + if (this.layers) return this.layers; + + var layers = []; + + for (var i = 0, len = this.map.layers.length; i < len; i++) { + var mapLayer = this.map.layers[i]; + if (mapLayer instanceof OpenLayers.Layer.WMS + && mapLayer.url === this.url + && (!this.queryVisible || mapLayer.getVisibility())) { + + layers.push(mapLayer); + } + } + + return layers; + }, + + /** + * Method: request + * Sends a GetFeatureInfo request to the WMS + * + * Parameters: + * clickPosition - The position on the map where the mouse event occurred + * options - {Object} additional options for this method. + * + * Valid options: + * - *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(); + + 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. + styleNames = styleNames.concat(layers[i].params.STYLES || + 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, + info_format: this.infoFormat + }, this.vendorParams), + callback: this.handleResponse, + scope: OpenLayers.Util.extend({ + xy: clickPosition + }, this) + }; + + var response = OpenLayers.Request.GET(wmsOptions); + + if (options.hover === true) { + this.hoverRequest = response.priv; + } + }, + + /** + * Method: handleResponse + * Handler for the GetFeatureInfo response. Will be called in an extended + * scope of this instance plus an xy property with the click position. + * + * Parameters: + * response - {Object} + */ + handleResponse: function(response) { + var features; + var fmt = this.formats[ + response.getResponseHeader("Content-type").split(";")[0] + ]; + if (fmt) { + features = fmt.read(response.responseXml || + response.responseText); + } + + this.events.triggerEvent("getfeatureinfo", { + text: response.responseText, + features: features, + xy: this.xy + }); + + // Reset the cursor. + OpenLayers.Element.removeClass(this.map.div, "olCursorWait"); + }, + + /** + * Method: setMap + * Set the map property for the control. + * + * Parameters: + * map - {} + */ + setMap: function(map) { + this.handler.setMap(map); + OpenLayers.Control.prototype.setMap.apply(this, arguments); + }, + + CLASS_NAME: "OpenLayers.Control.WMSGetFeatureInfo" +}); diff --git a/tests/Control/WMSGetFeatureInfo.html b/tests/Control/WMSGetFeatureInfo.html new file mode 100644 index 0000000000..1fe5d359b3 --- /dev/null +++ b/tests/Control/WMSGetFeatureInfo.html @@ -0,0 +1,293 @@ + + + + + + +
+ + + + + + + + +
+ + diff --git a/tests/list-tests.html b/tests/list-tests.html index 8693e0f0c3..eb5fa80ce6 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -33,6 +33,7 @@
  • Control/SelectFeature.html
  • Control/Snapping.html
  • Control/Split.html
  • +
  • Control/WMSGetFeatureInfo.html
  • Events.html
  • Extras.html
  • Feature.html