Selecting point features on map

2622
7
Jump to solution
11-29-2017 08:57 AM
EvonFranklin
New Contributor III

how can I select point features that are within a certain buffer zone to a mouse click on the map?

Tags (1)
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Evon,

   Here is a sample:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>Query features in 1mile radius - 4.5</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
  <script src="https://js.arcgis.com/4.5/"></script>

  <script>
  var flView;
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/symbols/SimpleFillSymbol",
        "esri/Color",
        "esri/geometry/Circle",
        "esri/Graphic",
        "esri/tasks/support/Query",
        "esri/renderers/SimpleRenderer",
        "dojo/dom",
        "dojo/domReady!"
      ],
      function(
        Map, MapView,
        FeatureLayer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Color,
        Circle, Graphic, Query, SimpleRenderer, dom
      ) {

        var map = new Map({
          basemap: "dark-gray"
        });

        var view = new MapView({
          container: "mapDiv",
          map: map,
          center: [-73.950, 40.702],
          zoom: 11,
          padding: {
            top: 32
          }
        });

        // Create the FeatureLayer using the popupTemplate
        var featureLayer = new FeatureLayer({
          url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0",
          outFields: ["POP2000"],
          visible: false
        });

        // Make unselected features invisible
        // var nullSymbol = new SimpleMarkerSymbol();
        // nullSymbol.size = 0;
        // featureLayer.renderer = new SimpleRenderer(nullSymbol);

        map.add(featureLayer);

        var circleSymb = new SimpleFillSymbol(
          SimpleFillSymbol.STYLE_NULL,
          new SimpleLineSymbol(
            SimpleLineSymbol.STYLE_SHORTDASHDOTDOT,
            new Color([105, 105, 105]),
            2
          ), new Color([255, 255, 0, 0.25])
        );

        view.whenLayerView(featureLayer).then(function(lyrView) {
          flView = lyrView;
          view.on("click", doBuffer);
        });

        function doBuffer(evt) {
          dom.byId("messages").innerHTML = "Calculating&hellip;"
          circle = new Circle({
            center: evt.mapPoint,
            geodesic: true,
            radius: 1,
            radiusUnit: "miles"
          });
          view.graphics.removeAll();
          var graphic = new Graphic(circle, circleSymb);
          view.graphics.add(graphic);
          var query = featureLayer.createQuery();
          query.geometry = circle.extent;
          query.outSpatialReference = view.spatialReference;
          // Use a fast bounding box query. It will only go to the server if bounding box is outside of the visible map.
          featureLayer.queryFeatures(query).then(selectInBuffer);
        }

        function selectInBuffer(response) {
          var feature;
          var features = response.features;
          var inBuffer = [];
          // Filter out features that are not actually in buffer, since we got all points in the buffer's bounding box
          for (var i = 0; i < features.length; i++) {
            feature = features[i];
            if (circle.contains(feature.geometry)) {
              inBuffer.push(feature.attributes[featureLayer.objectIdField]);
            }
          }
          var query = featureLayer.createQuery();
          query.objectIds = inBuffer;
          query.outSpatialReference = view.spatialReference;

          var symbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CIRCLE,
            12,
            new SimpleLineSymbol(
              SimpleLineSymbol.STYLE_NULL,
              new Color([247, 34, 101, 0.9]),
              1
            ),
            new Color([207, 34, 171, 0.5])
          );

          // Use an objectIds selection query (should not need to go to the server)
          featureLayer.queryFeatures(query).then(function(results) {
            var graArr = [], graphic;
            results.features.map( function(feat){
              graphic = new Graphic(feat.geometry, symbol);
              graArr.push(graphic);
            });
            view.graphics.addMany(graArr);
            var totalPopulation = sumPopulation(results.features);
            var r = "";
            r = "<b>The total Census Block population within the buffer is <i>" + totalPopulation + "</i>.</b>";
            dom.byId("messages").innerHTML = r;
          });
        }

        function sumPopulation(features) {
          var popTotal = 0;
          for (var x = 0; x < features.length; x++) {
            popTotal = popTotal + features[x].attributes["POP2000"];
          }
          return popTotal;
        }

      });
  </script>

  <style>
    html,
    body,
    #mapDiv {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
    }

    .panel-container {
      position: relative;
      width: 100%;
      height: 100%;
    }

    .panel-side {
      padding: 2px;
      box-sizing: border-box;
      width: 100%;
      height: 32px;
      position: absolute;
      top: 0;
      right: 0;
      color: #fff;
      background-color: rgba(0, 0, 0, 0.6);
      overflow: auto;
      z-index: 60;
    }

    #census_div {
      height: 100%
    }
    #messages {
      line-height: 30px;
    }

  </style>

</head>

<body>
  <div class="panel-container">
    <div class="panel-side">
      <div id="census_div">
        <span id="messages">Click on the map to select census block points within 1 mile.</span>
      </div>
    </div>
    <div id="mapDiv"></div>
  </div>
</body>

</html>
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

View solution in original post

7 Replies
RobertScheitlin__GISP
MVP Emeritus

Evon,

   Here is a sample:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>Query features in 1mile radius - 4.5</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
  <script src="https://js.arcgis.com/4.5/"></script>

  <script>
  var flView;
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/symbols/SimpleFillSymbol",
        "esri/Color",
        "esri/geometry/Circle",
        "esri/Graphic",
        "esri/tasks/support/Query",
        "esri/renderers/SimpleRenderer",
        "dojo/dom",
        "dojo/domReady!"
      ],
      function(
        Map, MapView,
        FeatureLayer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Color,
        Circle, Graphic, Query, SimpleRenderer, dom
      ) {

        var map = new Map({
          basemap: "dark-gray"
        });

        var view = new MapView({
          container: "mapDiv",
          map: map,
          center: [-73.950, 40.702],
          zoom: 11,
          padding: {
            top: 32
          }
        });

        // Create the FeatureLayer using the popupTemplate
        var featureLayer = new FeatureLayer({
          url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0",
          outFields: ["POP2000"],
          visible: false
        });

        // Make unselected features invisible
        // var nullSymbol = new SimpleMarkerSymbol();
        // nullSymbol.size = 0;
        // featureLayer.renderer = new SimpleRenderer(nullSymbol);

        map.add(featureLayer);

        var circleSymb = new SimpleFillSymbol(
          SimpleFillSymbol.STYLE_NULL,
          new SimpleLineSymbol(
            SimpleLineSymbol.STYLE_SHORTDASHDOTDOT,
            new Color([105, 105, 105]),
            2
          ), new Color([255, 255, 0, 0.25])
        );

        view.whenLayerView(featureLayer).then(function(lyrView) {
          flView = lyrView;
          view.on("click", doBuffer);
        });

        function doBuffer(evt) {
          dom.byId("messages").innerHTML = "Calculating&hellip;"
          circle = new Circle({
            center: evt.mapPoint,
            geodesic: true,
            radius: 1,
            radiusUnit: "miles"
          });
          view.graphics.removeAll();
          var graphic = new Graphic(circle, circleSymb);
          view.graphics.add(graphic);
          var query = featureLayer.createQuery();
          query.geometry = circle.extent;
          query.outSpatialReference = view.spatialReference;
          // Use a fast bounding box query. It will only go to the server if bounding box is outside of the visible map.
          featureLayer.queryFeatures(query).then(selectInBuffer);
        }

        function selectInBuffer(response) {
          var feature;
          var features = response.features;
          var inBuffer = [];
          // Filter out features that are not actually in buffer, since we got all points in the buffer's bounding box
          for (var i = 0; i < features.length; i++) {
            feature = features[i];
            if (circle.contains(feature.geometry)) {
              inBuffer.push(feature.attributes[featureLayer.objectIdField]);
            }
          }
          var query = featureLayer.createQuery();
          query.objectIds = inBuffer;
          query.outSpatialReference = view.spatialReference;

          var symbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CIRCLE,
            12,
            new SimpleLineSymbol(
              SimpleLineSymbol.STYLE_NULL,
              new Color([247, 34, 101, 0.9]),
              1
            ),
            new Color([207, 34, 171, 0.5])
          );

          // Use an objectIds selection query (should not need to go to the server)
          featureLayer.queryFeatures(query).then(function(results) {
            var graArr = [], graphic;
            results.features.map( function(feat){
              graphic = new Graphic(feat.geometry, symbol);
              graArr.push(graphic);
            });
            view.graphics.addMany(graArr);
            var totalPopulation = sumPopulation(results.features);
            var r = "";
            r = "<b>The total Census Block population within the buffer is <i>" + totalPopulation + "</i>.</b>";
            dom.byId("messages").innerHTML = r;
          });
        }

        function sumPopulation(features) {
          var popTotal = 0;
          for (var x = 0; x < features.length; x++) {
            popTotal = popTotal + features[x].attributes["POP2000"];
          }
          return popTotal;
        }

      });
  </script>

  <style>
    html,
    body,
    #mapDiv {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
      font-family: sans-serif;
    }

    .panel-container {
      position: relative;
      width: 100%;
      height: 100%;
    }

    .panel-side {
      padding: 2px;
      box-sizing: border-box;
      width: 100%;
      height: 32px;
      position: absolute;
      top: 0;
      right: 0;
      color: #fff;
      background-color: rgba(0, 0, 0, 0.6);
      overflow: auto;
      z-index: 60;
    }

    #census_div {
      height: 100%
    }
    #messages {
      line-height: 30px;
    }

  </style>

</head>

<body>
  <div class="panel-container">
    <div class="panel-side">
      <div id="census_div">
        <span id="messages">Click on the map to select census block points within 1 mile.</span>
      </div>
    </div>
    <div id="mapDiv"></div>
  </div>
</body>

</html>
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
EvonFranklin
New Contributor III

Thanks for replying, I will take a look at this now. i have been trying to do it on my own but for the past 2 days not working as I would like it to.

0 Kudos
ThomasSolow
Occasional Contributor III

Robert's answer is a good client-side method.

Another option is to do this on the backend with an IdentifyTask: IdentifyTask | API Reference | ArcGIS API for JavaScript 4.5 or just by querying a feature service with some geometry (a circle maybe).

These are only possible if your data is contained in a feature service/map service.

0 Kudos
EvonFranklin
New Contributor III

Yea my data was pushed by the server admins to a service which I call each layer from, not sure if server or client side way would be the most efficient but I normally make server calls when querying data rather than layer queries. Maybe I am being inefficient?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Evon,

  Depends on whether you are already showing the layer in the map and have access to the layer object.

Don't forget to mark this question as answered by clicking on the "Mark Correct" link on the reply that answered your question.

0 Kudos
EvonFranklin
New Contributor III

Well I guess I will have to add the feature layer as well as the symbolized map image layer to the map.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Evon,

   If you are using a map image layer then you would be best to continue using QueryTask and Query then.

0 Kudos