[GIS] How to get list of all markers from selected polygon using OpenLayers 2 Map

javascriptmarkersopenlayers-2polygon

I am able to run the following features on OpenLayers version 2.x Map:

  • Put Markers on Map
  • Draw Polygon on Map
  • Select Polygon on Map

Now my requirement is when I select any polygon then I would like to show an alert box with all markers which are inside the selected polygon.

I am using following code:

<html>
    <head>
        <link href="common.css" type="text/css" rel="stylesheet">
        <link rel="stylesheet" href="style.css" type="text/css" />
        <script src="OpenLayers.js"></script>
    </head>
    <body>
        <div id="map"></div>
        <div style="font-weight: bold">OSM Drawing Layer</div>
        <select id="mapMode" name="mapMode" size="1" onchange="changeMapMode(this.value);">
            <option value="none" selected>Navigation</option>
            <option value="polygon">Draw Polygon</option>
            <option value="line">Draw Line</option>
            <option value="select">Select Features</option>
        </select>
        <div id="highlighted"></div>
        <br />
        <div id="featureTable"></div>
        <script type="text/javascript">
            //https://gis.stackexchange.com/questions/115500/how-to-find-markers-in-selected-dragbox-openlayers-3

            var lat=23.033863;
            var lon=72.585022;
            var zoom=4;
            var mapOptions = {
                div: "map"
            };

            var map = new OpenLayers.Map('map', mapOptions);
            map.addLayer(new OpenLayers.Layer.OSM());
            map.addControl(new OpenLayers.Control.LayerSwitcher());
            var epsg4326 = new OpenLayers.Projection("EPSG:4326");
            var projectTo = map.getProjectionObject();

            if(!map.getCenter()){
                var lonLat = new OpenLayers.LonLat(lon, lat).transform(epsg4326, projectTo);
                map.setCenter (lonLat, zoom);
            }

            drawingLayer = new OpenLayers.Layer.Vector("Drawing layer");
            drawingLayer.events.on({
                'featureselected': function(feature) {
                    updateFeatureTable(this.selectedFeatures);
                },
                'featureunselected': function(feature) {
                    updateFeatureTable(this.selectedFeatures);
                }
            });
            map.addLayer(drawingLayer);

            var lonLatSarkhej = new OpenLayers.LonLat(72.5000,22.9833).transform(epsg4326,projectTo);
            var lonLatVadodara = new OpenLayers.LonLat(73.2003,22.3000).transform(epsg4326,projectTo);
            var lonLatBhuj = new OpenLayers.LonLat(69.6700,23.2500).transform(epsg4326,projectTo);
            var lonLatMumbai = new OpenLayers.LonLat(72.8258,18.9750).transform(epsg4326,projectTo);
            var lonLatJaipur = new OpenLayers.LonLat(75.8235,26.9260).transform(epsg4326,projectTo);
            var lonLatDelhi = new OpenLayers.LonLat(77.2300,28.6100).transform(epsg4326,projectTo);

            var markers = new OpenLayers.Layer.Markers("Markers");
            map.addLayer(markers);
            var size = new OpenLayers.Size(24,24);
            var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
            var icon = new OpenLayers.Icon('icon/Marker-Pink.png', size, offset);

            markers.addMarker(new OpenLayers.Marker(lonLatSarkhej,icon)); //Sarkhej
            markers.addMarker(new OpenLayers.Marker(lonLatVadodara,icon.clone())); //Vadodara
            markers.addMarker(new OpenLayers.Marker(lonLatBhuj,icon.clone())); //Bhuj
            markers.addMarker(new OpenLayers.Marker(lonLatMumbai,icon.clone())); //Mumbai
            markers.addMarker(new OpenLayers.Marker(lonLatJaipur,icon.clone())); //Jaipur
            markers.addMarker(new OpenLayers.Marker(lonLatDelhi,icon.clone())); //Delhi

            drawingControls = {
                polygon: new OpenLayers.Control.DrawFeature(drawingLayer, OpenLayers.Handler.Polygon, {
                    eventListeners: {
                        "featureadded": controlFeatureHandler
                    }
                }),
                line: new OpenLayers.Control.DrawFeature(drawingLayer, OpenLayers.Handler.Path),
                select: new OpenLayers.Control.SelectFeature(
                        drawingLayer,
                        {
                            clickout: false,
                            toggle: false,
                            multiple: false,
                            hover: false,
                            toggleKey: "ctrlKey", // ctrl key removes from selection
                            multipleKey: "shiftKey", // shift key adds to selection
                            box: true
                        }
                )
            };

            for (var key in drawingControls) {
                map.addControl(drawingControls[key]);
            }

            var highlightCtrl = new OpenLayers.Control.SelectFeature(drawingLayer, {
                hover: true,
                highlightOnly: true,
                renderIntent: "temporary",
                eventListeners: {
                    //beforefeaturehighlighted: report,
                    featurehighlighted: report,
                    featureunhighlighted: unReport
                }
            });
            map.addControl(highlightCtrl);
            highlightCtrl.activate();

            function report(e) {
                //OpenLayers.Console.log(e.type, e.feature.id);
                document.getElementById('highlighted').innerHTML=e.feature.id;
            };
            function unReport(e) {
                //OpenLayers.Console.log(e.type, e.feature.id);
                document.getElementById('highlighted').innerHTML="";
            };

            function changeMapMode(value) {
                for (var key in drawingControls) {
                    var control = drawingControls[key];
                    if (value == key) {
                        control.activate();
                    } else {
                        control.deactivate();
                    }
                }
            }

            function controlFeatureHandler(e) {
                alert(e.feature.geometry.getBounds());
            }

            function updateFeatureTable(featureList) {
                var wkt = new OpenLayers.Format.WKT();
                var table = "<table border='1'>";
                for(var key in featureList) {
                    table += "<tr><td>";
                    table += featureList[key].id;
                    table += "</td><td>";
                    table += wkt.write(featureList[key]);
                    table += "</td></tr>";
                }
                table += "</table>";
                document.getElementById('featureTable').innerHTML=table;
            }
        </script>
    </body>
</html>

Does anybody have an idea how could I get all the markers inside the selected polygon?

I have found one article which is written using OpenLayers version 3 (How to find markers in selected dragbox openlayers 3?). But I am using version 2.x.

Best Answer

Selections with multiple polygons are kind of tricky in OpenLayers 2. You have to check for every markers if they're within every selected polygon. With more markers, this can slow down the application drastically. There might be an easier way to do this, however this is my solution for your problem:

function updateFeatureTable(featureList) {
    var wkt = new OpenLayers.Format.WKT();
    var table = "<table border='1'>";
    var markersArray = [];
    for(var key in featureList) {
        table += "<tr><td>";
        table += featureList[key].id;
        table += "</td><td>";
        table += wkt.write(featureList[key]);
        table += "</td></tr>";
        if ( featureList[key].geometry.id.indexOf("Polygon") > -1 ) {
            for (var i in markers.markers) {
                var p = new OpenLayers.Geometry.Point(markers.markers[i].lonlat.lon, markers.markers[i].lonlat.lat);
                if (featureList[key].geometry.intersects(p)) {
                    if (markersArray.indexOf(markers.markers[i]) == -1){
                        markersArray.push(markers.markers[i]);
                    }
                }
            } 
        }
        asd = featureList[key];
    }
    table += "</table>";
    document.getElementById('featureTable').innerHTML=table;
    console.log(markersArray);
}

I have checked the intersection in the select featureselected function of your algorithm.

First, we check if the current selected feature is a polygon. I didn't have an easier solution for it, than to check if the id of the current feature's geometry contains the word "Polygon". You can do this with the indexOf() method. It has some compatibility issues on older IEs though (below IE 9). If the id doesn't contain the substring "Polygon", the method will return -1.

If it is a polygon, we loop thru the markers, which can be accessed from the markers layer variable, called markers. They're stored in a markers object, so in this case, we have to call markers.markers. We have to transform the marker to a point feature, because OpenLayers 2 can't resolve the intersection problem with a marker object.

If the point object derivated from the marker intersects the polygon, we store the current marker object in an empty array. We only store every marker once, so we check for duplicates before.

After the algorithm completes, we present the marker array to the user.

NOTE:

The fetureselected event is a little buggy. It will do its correspondent function for every new feature in the selection, until it reaches the maximum number of features (e.g. if you have selected 3 features, the function will run for feature 0, feature 0+1, feature 0+1+2).

For this bug, you will get as many alerts as many features you have selected. To prevent this, you should make the markersArray as a global variable, empty it every time the featureselected function starts, and only show it after the function has ended. This is only a necessary consideration, if you want to show the selected markers as an alert.