[GIS] Select single feature from multiple types with WFS in OpenLayers

geoserveropenlayers-2wfs

I have a WMS base and from that create a Vector Layer for selections. Then I create 3 Control.GetFeature() controls, each using WFS to select a different feature type upon clicking the map (the 'featureselect' event). Doing it this way, however, I end up with as many as 3 Features being selected, when I want a maximum of one.

Now, ideally I'd like GeoServer to pick the best (closest) feature to the mouse click, but even using Javascript in the browser, how would I detect when all the features have come in via WFS so I can test the geometries? And what would be the best way to test them? (mostly multilines and multilinestrings)

Here's the simplified code to give you the idea of what I've got now:

function init() {
    var mapOptions = { /* yada yada */ }
    var map = new OpenLayers.Map('map', mapOptions);

    var wmsOptions = { /* yada yada */ }
    var wmsLayers = 'parcelshape_lin,wmain_lin,wservice_lin,buildings_pol';
    var wms = new OpenLayers.Layer.WMS(
        "Testing",
        baseUrl+"/geoserver/wms",
        { layers: wmsLayers },
        wmsOptions
    );

    var select = new OpenLayers.Layer.Vector("Selection", {
        styleMap: new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"])
    });

    map.addLayers([wms,select]);

    var BuildingsControl = new OpenLayers.Control.GetFeature({
        protocol: OpenLayers.Protocol.WFS.fromWMSLayer(wms, {
            url: baseUrl+"/geoserver/wfs",
            featureType: "buildings_pol"
        }),
        hover: false
    });
    BuildingsControl.events.register("featureselected", this, function(e) {
        select.addFeatures([e.feature]);
    });
    BuildingsControl.events.register("featureunselected", this, function(e) {
        select.removeFeatures([e.feature]);
    });


    var WaterMainsControl = new OpenLayers.Control.GetFeature({
        protocol: OpenLayers.Protocol.WFS.fromWMSLayer(wms, {
            url: baseUrl+"/geoserver/wfs",
            featureType: "wmain_lin"
        }),
        hover: false
    });
    WaterMainsControl.events.register("featureselected", this, function(e) {
        select.addFeatures([e.feature]);
    });
    WaterMainsControl.events.register("featureunselected", this, function(e) {
        select.removeFeatures([e.feature]);
    });

    map.addControl(BuildingsControlCtrl);
    map.addControl(WaterMainsControl);

    BuildingsControl.activate();
    WaterMainsControl.activate();
}

Best Answer

If your WFS supports it (and it looks like you're using GeoServer, which does), OpenLayers can query multiple feature types in a single WFS query:

var featureTypes = ["parcelshape_lin", "wmain_lin", "buildings_pol"];

var allLayersControl = new OpenLayers.Control.GetFeature({
    protocol: OpenLayers.Protocol.WFS.fromWMSLayer(wms, {
        url: baseUrl + "/geoserver/wfs",
        featureType: featureTypes
    }),
    hover: false
});

This is exactly what I do in my OpenLayers/GeoServer installation, the only difference being that I create a new OpenLayers.Protocol.WFS({ ... }) manually instead of using fromWMSLayer. However, it should work identically.

Just register the events on allLayerscontrol and the GetFeature control will take care of parsing the geometries and finding the best match. If you're interested in how it does that, I'd recommend taking a look at the source for the control (GetFeature.js in OpenLayers).