Buffer and Select

1877
12
03-16-2020 12:11 PM
jaykapalczynski
Frequent Contributor

I am looking for a down and dirty example of taking an XY coordinate from user and running a buffer (set distance), then selecting all the poly features that touch or are within the buffer.....

Any examples out there?

0 Kudos
12 Replies
UndralBatsukh
Esri Regular Contributor

Hi there, 

You can achieve this by running a query by distance which does not involve geometryEngine which can be heavy to load. 

Please take a look at the following SDK doc and samples how to query features by distance (in essence select features by buffer). 

Query | ArcGIS API for JavaScript 4.14 

Query statistics client-side by distance | ArcGIS API for JavaScript 4.14 

-Undral

0 Kudos
jaykapalczynski
Frequent Contributor

This seems more logical BUT what I need is two fold...

I want to retain the map click 

But I also want the user to type in an address, geocode it and use those XY coordinates

So they can click and it does its thing.

Or they can choose to type in an address and wuen they choose which one they want it automatically zooms to that location and uses that XY to fuel the query.

Thoughts on how to add that?  Can I just push an XY location here?

query.geometry = view.toMap(event);

If so what would the syntax look like?

EDIT: Second question.... how do I remove the web map stuff....I want to use a straight feature layer RestEP

0 Kudos
jaykapalczynski
Frequent Contributor

I am doing this....is there a way to set a parameter to query in miles and not the view extent\

Where can I find a list of the available parameters for the .queryFeatures?

          layerView.watch("updating", function(value) {
            if (!value) {
              // query all the features available for drawing.
              layerView
                .queryFeatures({
                  geometry: view.extent,
                  returnGeometry: true,
                  orderByFields: ["WMA_Name"]
                })
                .then(function(results) {
                  graphics = results.features;

                  const fragment = document.createDocumentFragment();

                  graphics.forEach(function(result, index) {
                    const attributes = result.attributes;
                    const name = attributes.WMA_NAME;
0 Kudos
UndralBatsukh
Esri Regular Contributor

HI there, 

Please take your time looking at the sample code and its description. Also the SDK documents. 

FeatureLayerView | ArcGIS API for JavaScript 4.14 

The sample I provided above does query features within one mile of cursor location as shown below. You can also adjust the function (queryStatsOnDrag) that is called from view's click event to be called whenever user searches for address. 

 view.whenLayerView(layer).then(function(layerView) {
            watchUtils.whenFalseOnce(layerView, "updating", function(val) {
              // Query layer view statistics as the user clicks
              // or drags the pointer across the view.
              view.on(["click", "drag"], function(event) {
                // disables navigation by pointer drag
                event.stopPropagation();
                queryStatsOnDrag(layerView, event)
                  .then(updateCharts)
                  .catch(function(error) {
                    if (error.name !== "AbortError") {
                      console.error(error);
                    }
                  });
              });
            });
 });


// query set when user clicks on the view or drag 
const query = layerView.layer.createQuery();
query.geometry = view.toMap(event); // converts the screen point to a map point
query.distance = 1; // queries all features within 1 mile of the point
query.units = "miles";‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
jaykapalczynski
Frequent Contributor

I am shuffling a couple different approaches here....and getting very confused....I thank you for your patience...

My problem is I cannot combine the two solutions. I have below....I want to use the first below but need a way to specify the distance....I cant figure that part out....combining the two solutions.

I do not want to drive this from a map click....

This example works well with the geocoder where I can type in an address and when the map zooms it queries the features in the maps extent.  OR I can simply pan the map and it reruns the query...

This gives me a list of the features in the map that I can interact with....

If I can just set a parameter here I would be all set.

ISSUES:  I need to specify the distance in miles.  I cannot figure that out.

    view.whenLayerView(featureLayer).then(function (layerView) {

        // wait for the layer view to finish updating

        layerView.watch("updating", function (value) {
            if (!value) {
                // query all the features available for drawing.
                layerView
                    .queryFeatures({
                        geometry: view.extent,
                        returnGeometry: true,
                        orderByFields: ["WMA_Name"]
                    })
                    .then(function (results) {
                        graphics = results.features;
                        const fragment = document.createDocumentFragment();
                        var nameArray = []
                        graphics.forEach(function (result, index) {
                            const attributes = result.attributes;
                            const name = attributes.WMA_NAME;

                            nameArray.push(name);

                            // Create a list zip codes in NY
                            const li = document.createElement("li");
                            li.classList.add("panel-result");
                            li.tabIndex = 0;
                            li.setAttribute("data-result-id", index);
                            li.textContent = name;

                            fragment.appendChild(li);
                        });

                        alert("WMAs: " + nameArray);
                        // Empty the current list
                        listNode.innerHTML = "";
                        listNode.appendChild(fragment);
                    })
                    .catch(function (error) {
                        console.error("query failed: ", error);
                        //alert("query failed: ", error);
                    });

            }  // END OF VALUE ABOVE
        }); // END OF LAYER WATCH

        watchUtils.whenFalseOnce(layerView, "updating", function (val) {
            // Query layer view statistics as the user clicks
            // or drags the pointer across the view.
            //view.on(["click", "drag"], function (event) {                    
            view.on(["click"], function (event) {
                // disables navigation by pointer drag
                event.stopPropagation();

            });  // END OF VIEW ON CLICK
        });  // END OF WATCH UTILS


    });‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

2nd Solution

I can use a view Map Click as such and specify the distance like the below

        view.on("click", function (event) {

            var query = new Query();
            query.geometry = event.mapPoint;  // obtained from a view click event
            query.distance = 10;
            query.units = "miles";
            query.spatialRelationship = "intersects";

            view.whenLayerView(featureLayer).then(function (layerView) {
                watchUtils.whenNotOnce(layerView, "updating")
                    .then(function () {
                        return layerView.queryObjectIds(query);
                    })
                    .then(function (ids) {
                        //console.log(ids);  // prints the ids of the client-side 
                        alert(ids);
                    });
            });
            
        });
0 Kudos
UndralBatsukh
Esri Regular Contributor

In your first section, all you have to add is distance and units to your query parameter. FeatureLayer.queryFeatures() accepts query parameter. As I pointed above, you can specify distance and units on your query.  

layerView.queryFeatures({
  geometry: view.extent,
  returnGeometry: true,
  orderByFields: ["WMA_Name"],
  distance: 10, 
  units: "miles"
 });

Is this what you are referring to?

0 Kudos
jaykapalczynski
Frequent Contributor

this is what I am doing right now....

When the app loads it is supposed to locate all the WMAs within 500 miles (ridiculous number for testing).  BUT it seems to only return what is in the current map view.

THEN when you search an address (Toano, VA) it zooms there and then re-queries and returns the WMAs that are again within 500 miles...but AGAIN it seems to only return within the map view.

If I change the distance to 1 mile or 500 miles I dont get a different return

Trying to figure out what I am doing that is not applying the distance and units parameters...

Edit fiddle - JSFiddle - Code Playground 

0 Kudos
jaykapalczynski
Frequent Contributor

instead of view.extent do I need to grab the center of the map or something.

0 Kudos