Select to view content in your preferred language

Selecting a group of features

5527
23
09-18-2015 08:34 AM
DaveSouthern
Deactivated User

I'm looking for a way to use the mouse to select a group of features on a map by dragging a rectangle around them.  I can select a single feature on the map by simply clicking on that feature - that much I have working.  But now I want to be able to drag a rectangle around a group of features and select all of them so I can do something with all of them.  So far I haven't found any code examples out there that discuss this.

0 Kudos
23 Replies
ChrisSmith7
Honored Contributor

Also, you can try creating Fiddler samples. Here's some examples to get you started:

gavinr's Fiddles - JSFiddle - Online JavaScript Editor - jQuery, Angular, Backbone, Underscore, Knoc...

c/o

Gavin Rehkemper

DaveSouthern
Deactivated User

Thanks - let me look these over and see where they go.

0 Kudos
DaveSouthern
Deactivated User

Here you go...

      require(["esri/toolbars/draw"], function (draw) {
            tb = new draw(map);
            tb.on("draw-end", getFeatures);
            tb.activate(draw.EXTENT);
        });
    getFeatures = function (evt) {
        require(["esri/geometry/Polygon", "esri/tasks/query"], function (polygon, query) {
            var extentPoly = new polygon(evt.geometry);
            var extentQuery = new query();
            extentQuery.geometry = extentPoly.getExtent();
            dojo.forEach(map.graphics.graphics, function (graphic) {
                if (extentQuery.contains(graphic.geometry)) {
                    selectedFeatures.push(graphic.getContent());
                }
            });
        });
    }

extentQuery says that it doesn't have a 'contains' method.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Dave,

extentQuery is a query object and thus does not have a contains method (this is what the error is telling you).  You should be using extentPoly.contains

if (extentPoly.contains(graphic.geometry)) {

0 Kudos
DaveSouthern
Deactivated User

Changing that line to extentPoly.contains gets me past that error, but something still isn't right.  I don't get any items added to the selectedFeatures array, even though there were three features under the rectangle I selected.  In fact, the forEach loop only loops once, even though there are many features on the map.

Let me ask you - if you were writing the code to do something like this, how would you approach it?

0 Kudos
thejuskambi
Frequent Contributor

You cannot create a Polygon by using  var extentPoly = new polygon(evt.geometry);  since there is no constructor for Polygon which takes geometry/Extent for parameter. Atleast as per documentation.

The right way to do it is by using the fromExtent static method like this

var extentPoly = Polygon.fromExtent(evt.geometry);

Hope this helps

DaveSouthern
Deactivated User

Thanks, thejus - that tells me that the example code I looked at was not correct. 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Dave,

  The way I would approach it is like the sample Chris Smith provided but written in AMD:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <!--The viewport meta tag is used to improve the presentation and behavior of the samples
      on iOS devices-->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Points in Extent</title>

    <link rel="stylesheet" href="http://js.arcgis.com/3.14/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.14/esri/css/esri.css">

    <script src="http://js.arcgis.com/3.14/"></script>
    <script>
      var map;
      require([
        "esri/map", "esri/toolbars/draw", "esri/tasks/QueryTask", "esri/tasks/query",
        "esri/symbols/SimpleFillSymbol", "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleMarkerSymbol",
        "esri/graphic", "esri/geometry/Polygon", "esri/InfoTemplate",
        "dojo/_base/Color", "dojo/dom", "dojo/on", "dojo/_base/array", "dojo/domReady!"
      ], function(
        Map, Draw, QueryTask, Query,
        SimpleFillSymbol, SimpleLineSymbol, SimpleMarkerSymbol,
        Graphic, Polygon, InfoTemplate,
        Color, dom, on, array
      ) {
        //create map, set initial extent and disable default info window behavior
        map = new Map("mapDiv", {
          basemap: "streets",
          center: [-120.275, 47.485],
          zoom: 6,
          slider: false,
          showInfoWindowOnClick:false
        });
        map.on("load", function(){
          //initialize & execute query
          var queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/Map...");
          var query = new Query();
          query.where = "STATE_NAME = 'Washington'";
          query.outSpatialReference = map.spatialRefernce;
          query.returnGeometry = true;
          query.outFields = ["CITY_NAME"];
          queryTask.execute(query, addPointsToMap);

          var toolbar = new Draw(map);

          //find points in Extent when user completes drawing extent
          toolbar.on("draw-end", findPointsInExtent);

          //set drawing mode to extent
          toolbar.activate(Draw.EXTENT);
        });

        //initialize symbology
        defaultSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 16, new SimpleLineSymbol(), new Color([0,0,255]));
        highlightSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 16, new SimpleLineSymbol(), new Color([255,0,0]));

        //info template for points returned
        resultTemplate = new InfoTemplate("City", "<tr><td>${CITY_NAME}</tr></td>");

        //add points to map and set their symbology + info template
        function addPointsToMap(featureSet) {
          array.forEach(featureSet.features, function(feature){
            map.graphics.add(feature.setSymbol(defaultSymbol).setInfoTemplate(resultTemplate));
          });
        }

        //find all points within argument extent
        function findPointsInExtent(extent) {
          var results = [];
          array.forEach(map.graphics.graphics, function(graphic){
            if (extent.geometry.contains(graphic.geometry)) {
              graphic.setSymbol(highlightSymbol);
              results.push(graphic.getContent());
            }
            //else if point was previously highlighted, reset its symbology
            else if (graphic.symbol == highlightSymbol) {
              graphic.setSymbol(defaultSymbol);
            }
          });

          //display number of points in extent
          dojo.byId("inextent").innerHTML = results.length;

          //display list of points in extent
          dojo.byId("results").innerHTML = "<table><tbody>" + results.join("") + "</tbody></table>";
        }
      });
    </script>

  </head>
  <body class="claro">
    Draw an Extent on the map to find all points within this extent

    <!-- map div -->
    <div id="mapDiv" style="width:800px; height:400px; border:1px solid #000;"></div>
    <br />

    <!-- display number of points in drawn extent -->
    <b># of points in extent = <span id="inextent">0</span></b>

    <!-- list points in extent -->
    <div id="results" style="width:400px; height:200px; border:1px solid #000; overflow:auto;">
    </div>
  </body>
</html>
ChrisSmith7
Honored Contributor

Dave,

When Robert refers to AMD, he is referring to Asynchronous Module Definition (Introduction to AMD Modules - Dojo Toolkit Tutorial). These are the modules included in the Require at the top of your main page, like so:

require([
'dojo/on',
'dojo/aspect',
'dojo/_base/lang'], function(
on, aspect, lang) {

It looks like the sample I gave used the Legacy Module Require, which looks like:

dojo.require("esri.layers.DataSource")

You will find the JSAPI generally shows both in reference, but you'll want to use AMD.

DaveSouthern
Deactivated User

So here is where I currently am:

        require(["esri/toolbars/draw"], function (draw) {
            tb = new draw(map);
            tb.on("draw-end", getFeatures);
            tb.activate(draw.EXTENT);
        });

    getFeatures = function (extent) {

        //third try
        require(["dojo/_base/array"], function (array) {
            array.forEach(map.graphics.graphics, function (graphic) {
                if (extent.geometry.contains(graphic.geometry)) {
                    selectedFeatures.push(graphic.getContent());
                }
            });
        });

    }

but again, I don't get any items added to the selectedFeatures array, even though there were three features under the rectangle I selected.  In fact, the forEach loop only loops once, even though there are many features on the map.

Maybe it would help to point out that this functionality is associated with a button on a toolbar.  When the user clicks the button, the tool is activated so they can select the features they want on the map.  It's just one of a pretty extensive array of tools - not just a stand alone page.

0 Kudos