Buffer & select points

1377
9
12-16-2013 07:46 AM
AndrewPratt
New Contributor III
I�??ve been trying to get a select by buffer tool working as we are often asked to provide simple mapping products that are a summary of our projects that fall within �??X�?� miles of that location.  Anyway I�??ve added the buffer tool to a simple map and it works nicely in that you enable the tool, enter a distance and then click the map to buffer. What I�??m having problems with is that once I get the buffer drawn I need to use that geometry to intersect the points layer and I can�??t seem to get that part working. What am I doing wrong?  The buffer code is at the very bottom of the index page.

http://maps.ducks.ca/buffer/
0 Kudos
9 Replies
JakeSkinner
Esri Esteemed Contributor
Hi Andrew,

Try selecting your features after the event 'buffer-complete' fires.  Ex:

gsvc = new esri.tasks.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");

gsvc.on("buffer-complete", function(result){
      var symbol = new esri.symbol.SimpleFillSymbol(
          esri.symbol.SimpleFillSymbol.STYLE_SOLID,
           new esri.symbol.SimpleLineSymbol(
               esri.symbol.SimpleLineSymbol.STYLE_SOLID,
                  new dojo.Color([0,0,0,0.85]), 2
                ),
                  new dojo.Color([0,0,0,0.35])
                );
              
     var bufferGeometry = result.geometries[0];
     var graphic = new Graphic(bufferGeometry, symbol);
     app.map.graphics.add(graphic);
     app.map.setExtent(graphic.geometry.getExtent().expand(1.4));
     
     var query = new Query();
     query.geometry = bufferGeometry;
     featureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW)
});

....
....

function BufferPrj(evt){
      BufferDistance = document.getElementById('BufferDistanceKM').value;
      if (BufferDistance.length < 1){
        alert("Please enter a buffer distance")
      }else{          
          app.map.graphics.clear();
          var bufparams = new esri.tasks.BufferParameters();
          bufparams.geometries = [ evt.mapPoint ];
     
          //buffer in linear units such as meters, km, miles etc.
          bufparams.distances = [ BufferDistance ];
          bufparams.geodesic = true;
          bufparams.bufferSpatialReference = app.map.spatialReference;
          bufparams.unit = esri.tasks.GeometryService.UNIT_KILOMETER;
          bufparams.outSpatialReference = app.map.spatialReference;

          gsvc.buffer(bufparams);
      }            
}
0 Kudos
JssrRR
by
Occasional Contributor II

Jake,

I am new to JavaScript API and I came across your reply. I am trying to do something similar, using buffer to select from a feature layer and I want the results of the selection sent to a table, but when I put your code to buffer it does not work, do I need something else?

Here is the link to my code so far on JSFiddle:http://jsfiddle.net/JSSR/Lrby1wve/1/

It will be great if you can take a look at this and help me figure out what I am missing here

Thanks

0 Kudos
KenBuja
MVP Esteemed Contributor

Are you aware of the new capabilities added in the 3.9 version of the API that allows you to query against a Feature Layer hosted on ArcGIS.com where you can specify a buffer distance (and units)? This means you wouldn't have to use a GeometryService to return a buffer.

0 Kudos
JssrRR
by
Occasional Contributor II

Ken,

I saw those and the only sample I found was doing this was using a Circle, for which I can give a radius to draw buffer and select features, but I was looking for something where the users can put in any distance value to buffer and select the features falling within that distance,

something like this:

BufferDistance = document.getElementById('BufferDistanceMiles').value;

Is there any way I can do this using Circle class?

Here is the sample I am referring to and I have added my hosted service to this example:

<!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>Select with feature layer</title>

    <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/dojo/dijit/themes/tundra/tundra.css">

    <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">

    <style>

      html, body, #mapDiv {

        padding: 0;

        margin: 0;

        height: 100%;

      }

      #messages{

        background-color: #fff;

        box-shadow: 0 0 5px #888;

        font-size: 1.1em;

        max-width: 15em;

        padding: 0.5em;

        position: absolute;

        right: 20px;

        top: 20px;

        z-index: 40;

      }

    </style>

    <script src="http://js.arcgis.com/3.10/"></script>

    <script>

      var map;

      require([

        "esri/map", "esri/layers/FeatureLayer",

        "esri/tasks/query", "esri/geometry/Circle",

        "esri/graphic", "esri/InfoTemplate", "esri/symbols/SimpleMarkerSymbol",

        "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleFillSymbol", "esri/renderers/SimpleRenderer",

        "esri/config", "esri/Color", "dojo/dom", "dojo/domReady!"

      ], function(

        Map, FeatureLayer,

        Query, Circle,

        Graphic, InfoTemplate, SimpleMarkerSymbol,

        SimpleLineSymbol, SimpleFillSymbol, SimpleRenderer,

        esriConfig, Color, dom

      ) {

        // use a proxy page if a URL generated by this page is greater than 2000 characters

        //

        // this should not be needed as nearly all query & select functions are performed on the client

        esriConfig.defaults.io.proxyUrl = "/proxy";

        map = new Map("mapDiv", {

          basemap: "streets",

          center: [-99.249, 31.954],

          zoom: 7,

          slider: true

        });

    

        // Note that an info template has been defined so when

        //selected features are clicked a popup window will appear displaying the content defined in the info template.

        var featureLayer = new FeatureLayer("https://services1.arcgis.com/hVMNhMnY75fwfIFy/ArcGIS/rest/services/NursingFacilities/FeatureServer/0",{

          infoTemplate: new InfoTemplate("NursingFacility: ${FacilityID}", "${*}"),

          outFields: ["ObjectID", "FacilityID", "FacilityName", "Full_Address", "Phone1"],

          mode: FeatureLayer.MODE_ONDEMAND

        });

        // selection symbol used to draw the selected census block points within the buffer polygon

        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])

        );

        featureLayer.setSelectionSymbol(symbol);

    

        //make unselected features invisible

        //var nullSymbol = new SimpleMarkerSymbol().setSize(0);

        //featureLayer.setRenderer(new SimpleRenderer(nullSymbol));

    

        map.addLayer(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])

        );

        var circle;

        //when the map is clicked create a buffer around the click point of the specified distance.

        map.on("click", function(evt){

          circle = new Circle({

            center: evt.mapPoint,

            geodesic: true,

            radius: 10,

            radiusUnit: "esriMiles"

          });

          map.graphics.clear();

          map.infoWindow.show();

          var graphic = new Graphic(circle, circleSymb);

          map.graphics.add(graphic);

          var query = new Query();

          query.geometry = circle.getExtent();

          //use a fast bounding box query. will only go to the server if bounding box is outside of the visible map

          featureLayer.queryFeatures(query, 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;

            if(circle.contains(feature.geometry)){

              inBuffer.push(feature.attributes[featureLayer.objectIdField]);

            }

          }

          var query = new Query();

          query.objectIds = inBuffer;

          //use a fast objectIds selection query (should not need to go to the server)

          featureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function(results){

            var totalFeatures = sumCount(results);

            var r = "";

            r = "<b>The total Number of Nursing Homes within the Buffer  <i>" + totalFeatures+ "</i>.</b>";

            dom.byId("messages").innerHTML = r;

          });

        }

    

        function sumCount(features) {

          var TotalCountl = 0;

          for (var x = 0; x < features.length; x++) {

            TotalCount = TotalCount + features.attributes["POP2000"];

          }

          return TotalCount;

        }

      });

    </script>

  </head>

  <body>

    <span id="messages">Click on the map to select Nursing Homes within a 10 mile buffer.</span>

    <div id="mapDiv"></div>

  </body>

It is selecting the features like I want but I still need to figure out a way to have a choice to put in any distance to buffer and to send the selection to the datagrid.

Thanks

0 Kudos
JakeSkinner
Esri Esteemed Contributor

Hi Saloni,

You can create an input text box and then use the value from this using the dojo/dom module, ex:

var radius = parseInt(dom.byId("bufferDistance").value);

You will then want to specify this for the 'radius' option for the Circle:

map.on("click", function(evt){

          circle = new Circle({

            center: evt.mapPoint,

            geodesic: true,

            radius: radius,

            radiusUnit: "esriMiles"

          });

Here is an example:

<!DOCTYPE html>

<html>

  <head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">

    <title>Select with feature layer</title>

    <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/dojo/dijit/themes/tundra/tundra.css">

    <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">

    <style>

      html, body, #mapDiv {

        padding: 0;

        margin: 0;

        height: 100%;

      }

      #messages{

        background-color: #fff;

        box-shadow: 0 0 5px #888;

        font-size: 1.1em;

        max-width: 15em;

        padding: 0.5em;

        position: absolute;

        right: 20px;

        top: 20px;

        z-index: 40;

      }

     

      #bufferDiv{

        background-color: #fff;

        box-shadow: 0 0 5px #888;

        font-size: 1.1em;

        max-width: 15em;

        padding: 0.5em;

        position: absolute;

        left: 70px;

        top: 20px;

        z-index: 40;

      }

    </style>

    <script src="http://js.arcgis.com/3.10/"></script>

    <script>

      var map;

      require([

        "esri/map", "esri/layers/FeatureLayer",

        "esri/tasks/query", "esri/geometry/Circle",

        "esri/graphic", "esri/InfoTemplate", "esri/symbols/SimpleMarkerSymbol",

        "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleFillSymbol", "esri/renderers/SimpleRenderer",

        "esri/config", "esri/Color", "dojo/dom", "dojo/domReady!"

      ], function(

        Map, FeatureLayer,

        Query, Circle,

        Graphic, InfoTemplate, SimpleMarkerSymbol,

        SimpleLineSymbol, SimpleFillSymbol, SimpleRenderer,

        esriConfig, Color, dom

      ) {

        // use a proxy page if a URL generated by this page is greater than 2000 characters

        // this should not be needed as nearly all query & select functions are performed on the client

        esriConfig.defaults.io.proxyUrl = "/proxy";

        map = new Map("mapDiv", {

          basemap: "streets",

          center: [-99.249, 31.954],

          zoom: 7,

          slider: true

        });

        // Note that an info template has been defined so when

        //selected features are clicked a popup window will appear displaying the content defined in the info template.

        var featureLayer = new FeatureLayer("https://services1.arcgis.com/hVMNhMnY75fwfIFy/ArcGIS/rest/services/NursingFacilities/FeatureServer/0",{

          infoTemplate: new InfoTemplate("NursingFacility: ${FacilityID}", "${*}"),

          outFields: ["ObjectID", "FacilityID", "FacilityName", "Full_Address", "Phone1"],

          mode: FeatureLayer.MODE_ONDEMAND

        });

        // selection symbol used to draw the selected census block points within the buffer polygon

        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])

        );

        featureLayer.setSelectionSymbol(symbol);

        map.addLayer(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])

        );

        var circle;

        var radius = parseInt(dom.byId("bufferDistance").value);

        //when the map is clicked create a buffer around the click point of the specified distance.

        map.on("click", function(evt){

          circle = new Circle({

            center: evt.mapPoint,

            geodesic: true,

            radius: radius,

            radiusUnit: "esriMiles"

          });

          map.graphics.clear();

          map.infoWindow.show();

         

          var graphic = new Graphic(circle, circleSymb);

          map.graphics.add(graphic);

          var query = new Query();

          query.geometry = circle.getExtent();

          //use a fast bounding box query. will only go to the server if bounding box is outside of the visible map

          featureLayer.queryFeatures(query, 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;

            if(circle.contains(feature.geometry)){

              inBuffer.push(feature.attributes[featureLayer.objectIdField]);

            }

          }

          var query = new Query();

          query.objectIds = inBuffer;

          //use a fast objectIds selection query (should not need to go to the server)

          featureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function(results){                       

            var totalFeatures = results.length;

            var r = "";

            r = "<b>The total Number of Nursing Homes within the Buffer  <i>" + totalFeatures+ "</i>.</b>";

            dom.byId("messages").innerHTML = r;

          });

        }

   

        function sumCount(features) {

          var TotalCount = 0;

         

          for (var x = 0; x < features.length; x++) {

            TotalCount = TotalCount + features.attributes["POP2000"];

          }

          return TotalCount;

        }

      });

    </script>

  </head>

 

  <body>

    <span id="messages">Click on the map to select Nursing Homes within specified buffer distance.</span>

    <div id="mapDiv">

      <div id="bufferDiv">

        <label for="bufferDistance">Enter distance: </label><input type="text" value="30" id="bufferDistance"/>       

      </div>

    </div>

  </body>

 

</html>

JssrRR
by
Occasional Contributor II

Hi Jake,

Thanks for the help, it looks like it should be doing exactly what we are looking for, but for some reason, when we change the value or put in a different number, the size of the buffer, it is actually drawing does not change when we move or click on another point. I tried it in ArcGIS  API for JavaScript Sandbox.

Let me know if it looks right when you try.

Thanks again!

0 Kudos
JakeSkinner
Esri Esteemed Contributor

To fix this, you will just need to place the radius variable within the 'map.on' click event.  Ex:

map.on("click", function(evt){

          var radius = parseInt(dom.byId("bufferDistance").value);

          circle = new Circle({

            center: evt.mapPoint,

            geodesic: true,

            radius: radius,

            radiusUnit: "esriMiles"

          });

JssrRR
by
Occasional Contributor II

Jake,

I tried it and it works fine now.

I will look at the reference link you sent for dojo/dom documentation and try out other examples given there.

Appreciate your help, Thanks.

0 Kudos
AndrewPratt
New Contributor III
Thanks! Works like a champ!
0 Kudos