JS API 4.22, Querying points that intersect inside polygon

402
8
Jump to solution
01-11-2022 12:40 PM
MinaN_SCCWRP
New Contributor III

Hey everyone,

I've been currently working on a JavaScript API application and I'm stuck on how to formulate a query based on a polygon's geometry...

Right now I have a layer containing a set of  polygons and another layer with a set of points. I have a query that returns a set points based on the radius of a bufferGraphic.

Now I need to query these points if they fall within a polygon selection; i.e. the user clicks on the polygon which he/she wants to query and then return the same data as this current code I wrote does.

Any assistance on how to accomplish this would be a huge help! @BlakeTerhune 

 

 

 

<html>
<body>
  <button id="myButton" type>Query Selected Datasets</button>
  <button id="myButton2" type>Query Selected Datasets within Polygons</button>
  <div id="viewDiv"></div>
  <div id="panel"></div>
  <div id="mySQL"></div>
</body>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>ArcGIS API for Javascript&colon; SCCWRP Water</title>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 95%;
      width: 100%;
    }

    #titleDiv {
      padding: 10px;
    }

    #titleText {
      font-size: 20pt;
      font-weight: 60;
      padding-bottom: 10px;
    }
  </style>

  <link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/css/main.css">
  <script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" type="text/javascript"></script>
  <script src="https://js.arcgis.com/4.21/"></script>

  <script>

    json_array = [];
    // set distance and units - get dots within that boundary
    distance = 0.5;
    units = "miles";

    require([
      "esri/Map",
      "esri/Graphic",
      "esri/views/MapView",
      "esri/layers/FeatureLayer",
      "esri/widgets/LayerList",
      "esri/renderers/SimpleRenderer",
      "esri/symbols/SimpleFillSymbol",
      "esri/symbols/SimpleLineSymbol",
      "esri/renderers/UniqueValueRenderer",
      "esri/widgets/Legend",
      "esri/widgets/BasemapGallery",
      "esri/widgets/Expand",
      "esri/core/watchUtils",
    ], function (Map, Graphic, MapView, FeatureLayer, LayerList, SimpleRenderer, SimpleLineSymbol, UniqueValueRenderer, SimpleFillSymbol, Legend, BasemapGallery, Expand, watchUtils) {


      const map = new Map({  // creating a new map
        basemap: "satellite"
      });
      var view = new MapView({  // take that new map we just made above and display it
        container: "viewDiv",
        map: map,
        // center: [-118.243683, 34.052235],
        // zoom: 5,
        popup: {
          autoOpenEnabled: false,
          dockEnabled: true,
          dockOptions: {
            // dock popup at bottom-right side of view
            buttonEnabled: true,
            breakpoint: false,
            position: "bottom-right"
          }
        }
      });

      // County label + renderer + feature layer + add layer
      const countyLabel = ({
        symbol: {
          type: "text",  // autocasts as new TextSymbol()
          color: "white",
          font: {  // autocast as new Font()
            family: "Playfair Display",
            size: 12,
            weight: "regular"
          }
        },
        labelPlacement: "above-center",
        labelExpressionInfo: {
          expression: "$feature.NAME_PCASE"
        },
        deconflictionStrategy: "none"
      });
      const countyRend = {
        type: "simple",  // autocasts as new SimpleRenderer()
        symbol: {
          type: "simple-fill",  // autocasts as new SimpleFillSymbol()
          color: [0, 76, 115, 0.1],
          outline: {  // autocasts as new SimpleLineSymbol()
            width: 1,
            color: "white"
          }
        }
      };
      const counties = new FeatureLayer({
        url: "https://gis.sccwrp.org/arcserver/rest/services/Hosted/Counties/FeatureServer",
        renderer: countyRend,
        title: "Counties",
        labelingInfo: countyLabel
      });
      map.add(counties);

      // Stations label + renderer + feature layer + add layer
      let renderer = {
        type: "unique-value",
        field: "grp",
        uniqueValueInfos: [{
          value: "Projects",
          symbol: {
            size: 3,
            type: "simple-marker",
            color: [0, 255, 255],
            outline: null
          },
          label: "Projects"
        }, {
          value: "Regional Monitoring",
          symbol: {
            size: 3,
            type: "simple-marker",
            color: [0, 0, 139],
            outline: null
          },
          label: "Regional Monitoring"
        }]

      };
      const layer = new FeatureLayer({
        // autocasts as new PortalItem()
        portalItem: {
          id: "4ce8725b7968421eaa945025e2eca221"
        },
        renderer: renderer,
        outFields: ["*"]
      });
      map.add(layer);

      // Merging the 2 files together...

      //create graphic for mouse point click
      // Create graphic for distance buffer
      const pointGraphic = new Graphic({
        symbol: {
          type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
          color: [0, 0, 139],
          outline: {
            color: [255, 255, 255],
            width: 1.5
          }
        }
      });
      const bufferGraphic = new Graphic({
        symbol: {
          type: "simple-fill", // autocasts as new SimpleFillSymbol()
          color: [173, 216, 230, 0.2],
          outline: {
            // autocasts as new SimpleLineSymbol()
            color: [255, 255, 255],
            width: 1
          }
        }
      });

      layer.load().then(() => {
        // Set the view extent to the data extent
        view.extent = layer.fullExtent;
        layer.popupTemplate = layer.createPopupTemplate();
        loadLayerList();
      });

      view.on("click", (event) => {
        view.graphics.remove(pointGraphic);
        if (view.graphics.includes(bufferGraphic)) {
          view.graphics.remove(bufferGraphic);
        }
        queryFeatures(event);
      });

      function findLayerByTitle(title) {
        return view.map.allLayers.find(function (layer) {
          console.log(layer.title);
          return layer.title === title;
        });
      };

      let layerList, analysisLayer;

      function loadLayerList() {
        console.log("loadLayerList");
        console.log(json_array);
      };

      function queryFeatures(screenPoint) {
        console.log("click:");
        const point = view.toMap(screenPoint);
        console.log(point);
        console.log(point.latitude);
        console.log(point.longitude);
        layer
          .queryFeatures({
            geometry: point,
            distance: distance,
            units: units,
            spatialRelationship: "intersects",
            returnGeometry: false,
            returnQueryGeometry: true,
            outFields: ["*"]
          })
          .then((featureSet) => {
            // set graphic location to mouse pointer and add to mapview
            pointGraphic.geometry = point;
            view.graphics.add(pointGraphic);
            // open popup of query result
            console.log(featureSet);
            console.log(featureSet);
            view.popup.open({
              location: point,
              features: featureSet.features,
              featureMenuOpen: true
            });
            if (featureSet.queryGeometry) {
              bufferGraphic.geometry = featureSet.queryGeometry;
              view.graphics.add(bufferGraphic);
            }
            featureSet.features.forEach(function (item, index) {
              //console.log(featureSet.features[index].attributes);
              json_array.push(featureSet.features[index].attributes);
              //console.log(featureSet.features[0].attributes);
            });
          });
      };

      // Query the layer view for statistics on each analysis variable in the layer
      function queryLayerViewStats(layerView) {
        query = layerView.layer.createQuery();
        query.geometry = layerView.extent;
        return layerView.queryFeatures(query).then(function (response) {
          stats = response.features[0].attributes;
        });
      };

      function formatTable(station, origin_fname, datatype, json) {
        console.log("formatTable");
        stationdiv = "#" + CSS.escape(station) + "-" + CSS.escape(datatype);
        var el = document.querySelector(stationdiv);
        console.log(el);
        fieldnames = [];
        fieldvalues = [];
        Object.keys(json.fields).forEach(function (item) {
          fieldnames.push(json.fields[item].name);
        });
        Object.keys(json.features).forEach(function (feature_index) {
          fieldvalues[feature_index] = json.features[feature_index].attributes;
        });
        console.log(fieldnames);
        console.log(fieldvalues);
        if (json.fields != "empty") {
          let table = new simpleDatatables.DataTable(stationdiv, {
            data: {
              headings: fieldnames,
              data: fieldvalues.map(item => Object.values(item))
            },
          });
        } else {
          console.log("empty");
        };
      };

      function retrieveData(station, origin_fname, datatype, url) {
        h4 = ""
        table = document.createElement("table"),
          h4 = document.createElement("h4"),
          table.id = station + "-" + datatype;
        h4.innerHTML = table.id;
        document.body.appendChild(h4);
        document.body.appendChild(table);
        search_url = url + "/query?where=" + origin_fname + "='" + station + "'&outFields=*&f=json";
        console.log("search_url:" + search_url);
        protocol = "GET";
        fetch(search_url, { method: protocol, cache: "no-cache", }).then(function (response) { return response.json(); }).then(function (data) { console.log(data); formatTable(station, origin_fname, datatype, data); }).catch(function (err) { console.log("We had a problem Houston", err); });

      };

      document.querySelector('#myButton').addEventListener("click", function (event, ui) {
        str = " ";
        json_array.forEach(function (item, index) {
          console.log(item);
          str += retrieveData(item.stationid, item.origin_fname, item.dtp, item.link);
        });
        console.log(str);
      });

      var layerlist = new LayerList({ // this right here creates a layerlist or "dropdown" menu so that one can toggle off / on any of the layers that are present
        view: view
      });
      var basemapGallery = new BasemapGallery({ // This right here provides the gallery of basemaps users can pull from. I think.
        view: view,
        container: document.createElement("div")
      });
      var bgExpand = new Expand({ // This gives users the ability to choose which basemap they want to use
        view: view,
        content: basemapGallery
      });
      var legend = new Expand({ 
        content: new Legend({
          view: view,
          style: "classic"
        }),
        view: view,
        expanded: true
      });

      view.ui.add(layerlist, { position: "bottom-right" });
      view.ui.add(bgExpand, "top-left");
      view.ui.add(legend, "bottom-left");
      view.ui.add("titleDiv", "top-right"); // for "SCCWRP California Water Data" title on top right

    });
  </script>

</head>

<body>
  <div id="viewDiv"></div>
  <div id="titleDiv" class="esri-widget">
    <div id="titleText">SCCWRP California Water Data</div>
</body>

</html>

 

 

 

s the data of each point

0 Kudos
2 Solutions

Accepted Solutions
BlakeTerhune
MVP Regular Contributor

Use hittest() to get the polygon clicked. Use the geometry of the graphic returned in the HitTestResult to query the points layer just like you do with the buffer (except no distance).

View solution in original post

UndralBatsukh
Esri Regular Contributor

Hi there, 

I shared a very simple test app that showcases what you are asking a while back in one of the threads. Hopefully, you can find it helpful. https://codepen.io/U_B_U/pen/bGgaBKX?editors=1000

 

View solution in original post

8 Replies
Vakhtang_Zubiashvili
Occasional Contributor II
MinaN_SCCWRP
New Contributor III

Hi @Vakhtang_Zubiashvili  thanks for sharing this code sample and I will take a deep look at it.

Instead of having users draw a rectangle, would there be any way to click on a polygon and have that instead in returning the points? 

0 Kudos
BlakeTerhune
MVP Regular Contributor

Use hittest() to get the polygon clicked. Use the geometry of the graphic returned in the HitTestResult to query the points layer just like you do with the buffer (except no distance).

MinaN_SCCWRP
New Contributor III

I didn't even consider using the hittest() functionality; thanks for bringing this to my attn. Would you happen to be aware of any sample code I can draw from? Thanks in advance

0 Kudos
BlakeTerhune
MVP Regular Contributor
UndralBatsukh
Esri Regular Contributor

Hi there, 

I shared a very simple test app that showcases what you are asking a while back in one of the threads. Hopefully, you can find it helpful. https://codepen.io/U_B_U/pen/bGgaBKX?editors=1000

 

MinaN_SCCWRP
New Contributor III

Thanks @UndralBatsukh! This is helping me greatly

0 Kudos
Vakhtang_Zubiashvili
Occasional Contributor II

also check this, might be helpfull for you:

https://developers.arcgis.com/javascript/latest/find-length-and-area/