filter shakemaps by earthquake name (or id)

542
8
Jump to solution
06-10-2020 07:19 AM
CamCode
New Contributor III

My goal is to be able to toggle shake intensities on / or off (display or hide) individually via either an ID or name... I see options of id and object id available in the data field options in the rest doc.. however, I am unsure how to implement... In my below codepen, you can see I am doing a rest call and returning all the shake map data at once... I am trying to return them one at a time per earthquake name or ID... so, I can filter them later "on" or "off"...

CodePen..

Full Code:


<html><head>  <meta charset="utf-8">  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">  <title>ArcGIS JavaScript Tutorials: Add layers to a map</title>  <style>    html, body, #viewDiv {      padding: 0;      margin: 0;      height: 100%;      width: 100%;    }  </style>  <link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/themes/light/main.css">  <script src="https://js.arcgis.com/4.15/"></script>   <script>    require([      "esri/Map",      "esri/views/MapView",      "esri/layers/FeatureLayer",      "esri/widgets/Legend"    ], function(Map, MapView, FeatureLayer, Legend) {        var map = new Map({            basemap: "gray"        });         var view = new MapView({            container: "viewDiv",               map: map,            center: [-122, 37],            zoom: 5                     });         view.ui.add(            new Legend({                view: view           }),            "bottom-left"        );     // Define a popup for USGS_Seismic_Data_v1      var popupUSGS = {        title: "Shake Intensity",        content: [          {            type: "fields",            fieldInfos: [            {                fieldName: "grid_value",                label: "Grid Value"              },              {                fieldName: "mag",                label: "Magnitude"              },              {                fieldName: "eventTime",                label: "Event Time",                format: {                  dateFormat: "short-date-short-time"                }              },              {                fieldName: "updated",                label: "Updated",                format: {                  dateFormat: "short-date-short-time"                }              },              {                fieldName: "url",                label: "Url"              }            ]          }        ]      }    // USGS_Seismic_Data_v1 feature layer (polygons)      var SeismicData = new FeatureLayer({        title: "MMI - Shake Intensity",        url:  "https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/USGS_Seismic_Data_v1/FeatureServer/1/",           outFields: ["mag","eventTime","url"],          popupTemplate: popupUSGS       });      map.add(SeismicData);    });  </script></head><body>  <div id="viewDiv"></div></body></html> 
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Esteemed Contributor

Cam,

   Just set a filter from the start them.

        view.whenLayerView(layer).then(function(layerView) {
          eqLayerView = layerView;

          eqLayerView.filter = {
            where: "id = ''"
          };
...

View solution in original post

8 Replies
RobertScheitlin__GISP
MVP Esteemed Contributor

Cam Code,

   It looks like this sample is what you are looking for then:

https://developers.arcgis.com/javascript/latest/sample-code/sandbox/index.html?sample=featurefilter-... 

0 Kudos
CamCode
New Contributor III

Thanks, I'm seeming to get a better handle with this approach... except, would there be a way to loop through the definitionExpression ids without having to manually specify?

I have tried to console log SeismicData , but for some reason I am not finding a collection of ids but only one.. I would like to loop through and store these ids in variables as I will later add a time range parameter...

const SeismicData = new FeatureLayer({
title: "MMI - Shake Intensity",
url: "https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/USGS_Seismic_Data_v1/FeatureServer/1/",
outFields: ["id","mag","eventTime","url"],
popupTemplate: popupUSGS
});

SeismicData.definitionExpression = "grid_value > 2",
SeismicData.definitionExpression = "id = 'us70008jr5'", <------------ i.e. here

map.add(SeismicData);

0 Kudos
CamCode
New Contributor III

Ultimately I suppose how could I loop through and get all the shakemap ids returned from my rest URL call?

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Cam,

Here the sample updated for that:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>Filter features by attribute - 4.15</title>

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

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

      #id-filter {
        max-height: 400px;
        width: 100%;
        visibility: hidden;
        overflow-y: scroll;
      }

      .id-item {
        width: 100%;
        padding: 12px;
        text-align: center;
        vertical-align: baseline;
        cursor: pointer;
        height: 40px;
      }

      .id-item:focus {
        background-color: dimgrey;
      }

      .id-item:hover {
        background-color: dimgrey;
      }

      #titleDiv {
        padding: 10px;
      }

      #titleText {
        font-size: 20pt;
        font-weight: 60;
        padding-bottom: 10px;
      }
    </style>
    <script>
      require([
        "esri/views/MapView",
        "esri/Map",
        "esri/layers/FeatureLayer",
        "esri/widgets/Expand"
      ], function(MapView, Map, FeatureLayer, Expand) {
        let floodLayerView;

        // flash flood warnings layer
        const layer = new FeatureLayer({
          url: "https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/USGS_Seismic_Data_v1/FeatureServer/1/",
          outFields: ["*"]
        });

        const map = new Map({
          basemap: "gray-vector",
          layers: [layer]
        });

        const view = new MapView({
          map: map,
          container: "viewDiv",
          center: [-98, 40],
          zoom: 4
        });

        const idNodes = document.querySelectorAll(`.id-item`);
        const idElement = document.getElementById("id-filter");

        // click event handler for id choices
        idElement.addEventListener("click", filterByID);

        // User clicked on EQ id
        // set an attribute filter on earthquake layer view
        // to display the areas in that id
        function filterByID(event) {
          const selectedID = event.target.getAttribute("data-id");
          eqLayerView.filter = {
            where: "id = '" + selectedID + "'"
          };
        }

        view.whenLayerView(layer).then(function(layerView) {
          eqLayerView = layerView;

          // set up UI items
          idElement.style.visibility = "visible";
          const idExpand = new Expand({
            view: view,
            content: idElement,
            expandIconClass: "esri-icon-filter",
            group: "top-left"
          });
          //clear the filters when user closes the expand widget
          idExpand.watch("expanded", function() {
            if (!idExpand.expanded) {
              eqLayerView.filter = null;
            }
          });
          view.ui.add(idExpand, "top-left");
          view.ui.add("titleDiv", "top-right");
          var query = layer.createQuery();
          query.outFields = ["id"];
          query.returnDistinctValues = true;
          query.returnGeometry = false;
          layer.queryFeatures(query).then(function(results){
            results.features.map(function(feat){
              var id = feat.attributes.id;
              var opt = document.createElement("div");
              opt.className = "id-item visible-id";
              opt.setAttribute("data-id", id);
              opt.innerHTML = id;
              idElement.appendChild(opt);
            });
          });
          
        });
      });
    </script>
  </head>

  <body>
    <div id="id-filter" class="esri-widget">
    </div>
    <div id="viewDiv"></div>
    <div id="titleDiv" class="esri-widget">
      <div id="titleText">Earthquakes</div>
      <div>Shake Intensity</div>
    </div>
  </body>
</html>
CamCode
New Contributor III

Thanks so much, Robert! Small question - is it necessary to add the layer (all) first, or initially, before being able to accomplish the filter?

For instance, in my CodePen

I've added all the layers by the id as checkboxes, the goal would be to add each when clicked one at a time, starting with no layers. It works after I click one checkbox initally which seems to clear all, then I select a layer. But I'd like to start with no shake maps, and add just the ones that are checked via checkbox one at a time.

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Cam,

   Just set a filter from the start them.

        view.whenLayerView(layer).then(function(layerView) {
          eqLayerView = layerView;

          eqLayerView.filter = {
            where: "id = ''"
          };
...
CamCode
New Contributor III

Thanks Robert, is it possible to 'toggle by attribute id' on or off showing multiple at a time...

The goal would be push the attributes ids in a checkbox list, and check or unchecked to toggle the display of each shakemap by attribute id. The current problem is I've only been able to get it work as follows: start with nothing display -> checked checkbox would only show one at a time (and hide previous checked).

In other words I'm trying to create the ability to show or hide specific quakes by id, not just showing one a time as such with the definition expression technique and filter above, but rather the ability to check and show multiple at a time, is this possible?

i.e. with the below how could I retain multiple if needed (if checked)? It seems to only operate with one at a time.

          eqLayerView.filter = {
            where: "id = '" + selectedID + "'"
          };
0 Kudos
CamCode
New Contributor III

Thanks so much again. Robert, I have found one last issue with this I'm struggling with... Now with the popups, once I hit paginate... the pagination is displaying pop-up content for my shake graphics that are not visible (that are filtered out); how do I get my popup pagination to reflect the filter as well? Thanks so much for any advise

0 Kudos