2

I have an OpenLayers map that draws features in a vector layer. The features are selectable and have a popup on select. Unfortunately in a lot of cases the features overlap so it can be impossible to select some features. I think that what I need to do to fix this is change my select control so that it uses a click handler and searches the map for features at this point. What sort of function do i need to write? are there any examples of this being implemented before?

This is how the features are drawn:

var vector_Layer = new OpenLayers.Layer.Vector();

function GetFeaturesFromKMLString (strKML) {
    var format = new OpenLayers.Format.KML({
    'internalProjection': new OpenLayers.Projection("EPSG:900913"),
    'extranalProjection': new OpenLayers.Projection("EPSG:4326")    
    });
    return format.read(strKML);
};

vector_Layer.addFeatures(GetFeaturesFromKMLString('$newkml'));

And this is how Layers are currently selected:

var select = new OpenLayers.Control.SelectFeature(vector_Layer, {clickout: true}); 
        vector_Layer.events.on({
            "featureselected": onFeatureSelect,
            "featureunselected": onFeatureUnselect}); 



        map.addControl(select);
        select.activate();

        select.handlers['feature'].stopDown = false; 
        select.handlers['feature'].stopUp = false;

here is the click event listener I was planning on using:

OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {                
            defaultHandlerOptions: {
                'single': true,
                'double': false,
                'pixelTolerance': 0,
                'stopSingle': false,
                'stopDouble': false
            },

            initialize: function(options) {
                this.handlerOptions = OpenLayers.Util.extend(
                    {}, this.defaultHandlerOptions
                );
                OpenLayers.Control.prototype.initialize.apply(
                    this, arguments
                ); 
                this.handler = new OpenLayers.Handler.Click(
                    this, {
                        'click': this.onClick,
                        'dblclick': this.onDblclick 
                    }, this.handlerOptions
                );
            }, 

            onClick: function(evt) {
                //function that seachers for and selectas features at this point
            },

3 Answers 3

1

I've had this this situation, and came up with a novel solution: use the WMSGetFeatureInfo instead of the SelectFeature control, because it is able to return multiple features associated with a click event. Even though the WMSGetFeatureInfo is not supposed to be used with vector layers, it is possible to trick OpenLayers into thinking it is interacting with a WMS layer by adding WMS properties to the vector layer, and hacking some layer methods.

var lyrJobs = new OpenLayers.Layer.Vector(
"User Jobs",
{
    strategies: [
            new OpenLayers.Strategy.BBOX({ resFactor: 1 }) //Force bb to refresh on every zoom.
    ],
    url: wmsServerAddress + '?',
    protocol: new OpenLayers.Protocol.WFS({
        version: '1.1.0',
        srsName: map.getProjection(),
        url: wfsServerAddress,
        featureType: 'MyLayerName',
        featureNS: 'MyNameSpace', //URI
        geometryName: 'Geom'
    }),
    //Add WMS-style properties to allow WMSGetFeatureInfo protocol to be used.
    params: {
        FORMAT: 'image/png',
        VERSION: '1.1.1',
        STYLES: '',
        LAYERS: 'myNameSpace' + layerName
    }
}
);

lyrJobs.reverseAxisOrder = function ()
{
    return (parseFloat(this.params.VERSION) >= 1.3 &&
    !!this.yx[map.getProjectionObject().getCode()]);
}

It's perhaps a bit weird, but it works extremely well. When you get a response from the control, you can check if it returned a single features or multiple features, and display a popup accordingly.

0

One observation first: if you have vector features of a same group overlapping on your map, you might want to look into some clustering implementation first. One reason for this is that rendering vector graphics in a browser is expensive. Running into performance issues nowadays is less of a problem, but depending on the number of vector points and the browser-machine rendering them, you could still run into problems, especially on mobile platforms. Let say that it is good practice to keep the vector features (and the DOM elements) in your page as lower as possible. Openlayers has its own clustering strategy implemented in its API, but if you do not like it you could still plugin a third party one or roll your own.

Having pointed this out, one possible route I would suggest is to try having a look at what OpenLayers.Geometry has to offer and especially this example. I have never tried this, but depending on needs, you could even think at creating a temporary circle on click (all within OpenLayers) and then intersect your vector points with this circle...

Hope this can be of some help.

2
  • Do you know if clustering strategies work with polygons? The only one I'm aware of takes everything as a point, or so i thought... Jul 14, 2013 at 15:39
  • I assumed you were talking about points. No, on top of my head I am not aware of obvious clustering strategies with polygons. But, at a certain zoom level these polygons could be clustered and abstracted as points on centroids. Again, having polygons, the openlayers.geometry intersection method should work reasonably well for what you are trying to do. Finally, you could have simplified polygons for certain zoom levels... it all depends obviously from the specific case...
    – Decio
    Jul 15, 2013 at 20:49
0

you might want something like leatlet's spiderfy https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet. here is a demo http://jawj.github.io/OverlappingMarkerSpiderfier-Leaflet/demo.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.