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
This commit is contained in:
bartvde
2009-12-09 14:29:48 +00:00
parent b655b14f01
commit 711d412f88
2 changed files with 204 additions and 67 deletions
+142 -50
View File
@@ -31,6 +31,14 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
*/ */
hover: false, 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 * APIProperty: maxFeatures
* {Integer} Maximum number of features to return from a WMS query. This * {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 * response (String), a *features* property with an array of the
* parsed features, an *xy* property with the position of the mouse * parsed features, an *xy* property with the position of the mouse
* click or hover event that triggered the request, and a *request* * 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"], EVENT_TYPES: ["beforegetfeatureinfo", "getfeatureinfo"],
@@ -167,6 +178,10 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
); );
} }
if(this.drillDown === true) {
this.hover = false;
}
if(this.hover) { if(this.hover) {
this.handler = new OpenLayers.Handler.Hover( this.handler = new OpenLayers.Handler.Hover(
this, { this, {
@@ -256,9 +271,8 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
*/ */
findLayers: function() { findLayers: function() {
var layers = [];
var candidates = this.layers || this.map.layers; var candidates = this.layers || this.map.layers;
var layers = [];
var layer, url; var layer, url;
for(var i=0, len=candidates.length; i<len; ++i) { for(var i=0, len=candidates.length; i<len; ++i) {
layer = candidates[i]; layer = candidates[i];
@@ -267,15 +281,14 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
url = layer.url instanceof Array ? layer.url[0] : layer.url; url = layer.url instanceof Array ? layer.url[0] : layer.url;
// if the control was not configured with a url, set it // if the control was not configured with a url, set it
// to the first layer url // to the first layer url
if(!this.url) { if(this.drillDown === false && !this.url) {
this.url = url; this.url = url;
} }
if(this.urlMatches(url)) { if(this.drillDown === true || this.urlMatches(url)) {
layers.push(layer); layers.push(layer);
} }
} }
} }
return layers; return layers;
}, },
@@ -305,44 +318,24 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
}, },
/** /**
* Method: request * Method: buildWMSOptions
* Sends a GetFeatureInfo request to the WMS * Build an object with the relevant WMS options for the GetFeatureInfo request
* *
* Parameters: * Parameters:
* clickPosition - {<OpenLayers.Pixel>} The position on the map where the * url - {String} The url to be used for sending the request
* mouse event occurred. * layers - {Array(<OpenLayers.Layer.WMS)} An array of layers
* options - {Object} additional options for this method. * clickPosition - {<OpenLayers.Pixel>} The position on the map where the mouse
* * event occurred.
* Valid options: * format - {String} The format from the corresponding GetMap request
* - *hover* {Boolean} true if we do the request for the hover handler
*/ */
request: function(clickPosition, options) { buildWMSOptions: function(url, layers, clickPosition, format) {
options = options || {}; var layerNames = [], styleNames = [];
var layerNames = [];
var styleNames = [];
var layers = this.findLayers();
if(layers.length > 0) {
for (var i = 0, len = layers.length; i < len; i++) { for (var i = 0, len = layers.length; i < len; i++) {
layerNames = layerNames.concat(layers[i].params.LAYERS); layerNames = layerNames.concat(layers[i].params.LAYERS);
// in the event of a WMS layer bundling multiple layers but not styleNames = styleNames.concat(this.getStyleNames(layers[i]));
// 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, ""));
} }
} return {
} url: url,
var wmsOptions = {
url: this.url,
params: OpenLayers.Util.applyDefaults({ params: OpenLayers.Util.applyDefaults({
service: "WMS", service: "WMS",
version: "1.1.0", version: "1.1.0",
@@ -357,7 +350,7 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
y: clickPosition.y, y: clickPosition.y,
height: this.map.getSize().h, height: this.map.getSize().h,
width: this.map.getSize().w, width: this.map.getSize().w,
format: layers[0].params.FORMAT, format: format,
info_format: this.infoFormat info_format: this.infoFormat
}, this.vendorParams), }, this.vendorParams),
callback: function(request) { callback: function(request) {
@@ -365,16 +358,113 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
}, },
scope: this scope: this
}; };
},
/**
* Method: getStyleNames
* Gets the STYLES parameter for the layer. Make sure the STYLES parameter
* matches the LAYERS parameter
*
* Parameters:
* layer - {<OpenLayers.Layer.WMS>}
*
* 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
*
* Parameters:
* clickPosition - {<OpenLayers.Pixel>} 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) {
var layers = this.findLayers();
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); var response = OpenLayers.Request.GET(wmsOptions);
if (options.hover === true) { if (options.hover === true) {
this.hoverRequest = response.priv; this.hoverRequest = response.priv;
} }
} else { } else {
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<len; i++) {
var layer = layers[i];
var service, found = false;
url = layer.url instanceof Array ? layer.url[0] : layer.url;
if(url in services) {
services[url].push(layer);
} else {
this._numRequests++;
services[url] = [layer]
}
}
var layers;
for (var url in services) {
layers = services[url];
var wmsOptions = this.buildWMSOptions(url, layers,
clickPosition, layers[0].params.FORMAT);
OpenLayers.Request.GET(wmsOptions);
}
}
},
/**
* Method: triggerGetFeatureInfo
* Trigger the getfeatureinfo event when all is done
*
* Parameters:
* request - {XMLHttpRequest} The request object
* xy - {<OpenLayers.Pixel>} The position on the map where the
* mouse event occurred.
* features - {Array(<OpenLayers.Feature.Vector>)}
*/
triggerGetFeatureInfo: function(request, xy, features) {
this.events.triggerEvent("getfeatureinfo", {
text: request.responseText,
features: features,
request: request,
xy: xy
});
// Reset the cursor. // Reset the cursor.
OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait");
}
}, },
/** /**
@@ -393,16 +483,18 @@ OpenLayers.Control.WMSGetFeatureInfo = OpenLayers.Class(OpenLayers.Control, {
doc = request.responseText; doc = request.responseText;
} }
var features = this.format.read(doc); var features = this.format.read(doc);
if (this.drillDown === false) {
this.events.triggerEvent("getfeatureinfo", { this.triggerGetFeatureInfo(request, xy, features);
text: request.responseText, } else {
features: features, this._requestCount++;
request: request, this._features = (this._features || []).concat(features);
xy: xy if (this._requestCount === this._numRequests) {
}); this.triggerGetFeatureInfo(request, xy, this._features.concat());
delete this._features;
// Reset the cursor. delete this._requestCount;
OpenLayers.Element.removeClass(this.map.viewPortDiv, "olCursorWait"); delete this._numRequests;
}
}
}, },
/** /**
+45
View File
@@ -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();
}
</script> </script>
</head> </head>
<body> <body>