Dependency between Time Slider and dgrid table

566
0
02-09-2021 01:38 PM
KarstenRank
Occasional Contributor III

Hi,

I created a web app with the JavaScript Api 4.18 to show csv files on a web map with a time slider and a dgrid table. The table has a dependency to the map because of the view. The slider also has a dependency to the map because of the view. If I query the points with the time slider, the table shows all points that are in the shown extend. How can I achieve, that the table also shows the reduced points?

Thanks for your help,

Karsten

<!DOCTYPE html>
<html>
<head>
<meta name="description" content="CSVViewer">
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
  <title>CSVViewer</title>
  <style>
    html, body{
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
      overflow: hidden;
      font-family: "Helvetica Neue";
    }

    #viewDiv{
      flex: 2;
      width: 100%;
    }

    .header {
      grid-area: header;
      background: linear-gradient(to right, #007cb0, #001a4c);
    }

    #info,
    #gridDisplay {
      position: absolute;
      bottom: 0;
      left: 0;
      height: 35%;
      background-color: white;
      border-color: grey;
      width: 100%;
      font-family: "Avenir Next W00", "Helvetica Neue", Helvetica, Arial, sans-serif;
      font-size: 14px;
    }

    #info {
      z-index: 90;
      font-size: 16px;
      padding-left: 20px;
    }

    #info * {
      padding-right: 20px;
    }

    #gridDisplay {
      z-index: 80;
    }

    .info {
      line-height: 20px;
      padding-left: 5px ! important;
    }

    .dgrid-header,
    .dgrid-header-row {
      background-color: #eee;
      color: #57585A;
    }

    .dgrid-row-even {
      background-color: #F7F8F8;
    }

    .dgrid-row-odd {
      background-color: #EFEFEF;
    }

    .dgrid-selected {
      background: #B4DAF5;
    }

    .dgrid-row {
      border: none
    }

    .dgrid .dgrid-scroller {
        position: relative;
        max-height: 200px;
        overflow: auto;
      }

    .map {
      grid-area: map;
    }

    .wrapper {
      display: grid;
      grid-template-rows: 25%  100% auto;
      grid-template-areas:
       "header"
       "map";
      width: 100vw;
      height: 100%;
    }

    .box {
      color: #fff;
      padding: 10px;
      font-size: 20px; 
    }
    .container {
        display: flex;
        flex: 1;
        width: 100%;
      }
    
    .containerT {
      height: 30%;
      width: 100%;
    }
      .hidden {
        display: none;
      }

    @media only screen and (min-width: 544px)  {
      .wrapper {
        grid-template-columns: 100% auto;
        grid-template-rows: 40px  auto;
        grid-template-areas:
          "header   header"
          " map";
        }
      }

  </style>

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

  <script>
    require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/CSVLayer",
      "esri/Graphic",
      "esri/widgets/Legend",
      "esri/widgets/TimeSlider",
      "esri/widgets/Expand",
      "esri/widgets/BasemapGallery",
      "esri/widgets/FeatureTable",
      "esri/widgets/LayerList",
      "dgrid/OnDemandGrid",
      "dgrid/extensions/ColumnHider",
      "dojo/store/Memory",
      "dstore/legacy/StoreAdapter",
      "dgrid/Selection"
    ], function(Map, MapView, CSVLayer, Graphic, Legend, TimeSlider, 
       Expand, BasemapGallery, FeatureTable, LayerList, OnDemandGrid, 
       ColumnHider, Memory, StoreAdapter, Selection) {

      let map, view, csvLayer, csvLayerView, grid, node_table;
      const gridDiv = document.getElementById("grid");
      const infoDiv = document.getElementById("info");

      // create new map, view and csvlayer
      setupTheView();

      const gridFields = ["__OBJECTID", "time", "depth", "mag",
          "magType", "nst"];
      //time,latitude,longitude,depth,mag,magType,nst,gap,dmin,rms,net,id,updated,place,type,horizontalError,depthError,magError,magNst,status,locationSource,magSource

      // create a new datastore for the on demandgrid
      // will be used to display attributes of selected features
      const dataStore = new StoreAdapter({
        objectStore: new Memory({
          idProperty: "__OBJECTID"
        })
      });
    
      // create a grid with given columns once the csvlayer is loaded
      csvLayer.when(function() {
          // create a grid with columns specified in gridFields variable
          createGrid(csvLayer.fields);

          // get a reference the csvlayerview when it is ready. It will used to do
          // client side queries when user draws polygon to select features
          view.whenLayerView(csvLayer).then(function(layerView) {
            csvLayerView = layerView;
            console.log("timeout start");
            console.log(csvLayer.fullExtent);
            
            //wait for the layerview to be done updating
              csvLayerView.watch("updating", function(bool){
                if(!bool){
                  popGrid();
                  
                  console.log(csvLayer.timeInfo.fullTimeExtent.start);
                  console.log(csvLayer.timeInfo.fullTimeExtent.end);
 
            }})  

            });
      })
      .catch(errorCallback);

/****************************************************
         * Selects features from the csv layer that intersect
         * a polygon that user drew using sketch view model
         ****************************************************/
         function popGrid() {
          view.graphics.removeAll();
          if (csvLayerView) {
            const query = {
              where: "1=1",
              outFields: ["*"]
            };
            console.log(csvLayerView); 
            // query graphics from the csv layer view. Geometry set for the query
            // can be polygon for point features and only intersecting geometries are returned
            csvLayerView.queryFeatures(query).then(function(results) {
                const graphics = results.features;
                console.log(graphics.length);
                // if the grid div is displayed while query results does not
                // return graphics then hide the grid div and show the instructions div
                if (graphics.length > 0) {
                  gridDiv.style.zIndex = 90;
                  infoDiv.style.zIndex = 80;
                  document.getElementById("featureCount").innerHTML =
                    "<b>Showing attributes for " +
                    graphics.length.toString() + " features </b>"
                } else {
                  gridDiv.style.zIndex = 80;
                  infoDiv.style.zIndex = 90;
                }
                
                // get the attributes to display in the grid
                const data = graphics.map(function(feature, i) {
                  return Object.keys(feature.attributes)
                    .filter(function(key) {
                      // get fields that exist in the grid
                      return (gridFields.indexOf(key) !== -1);
                    })
                    // need to create key value pairs from the feature
                    // attributes so that info can be displayed in the grid
                    .reduce(function(obj, key) {
                      obj[key] = feature.attributes[key];
                      return obj;
                    }, {});
                });

                console.log(data);
                // set the datastore for the grid using the
                // attributes we got for the query results
                dataStore.objectStore.data = data;
                grid.set("collection", dataStore);
              })

            .catch(errorCallback);
          }
        }
            
        /************************************************
         * fires when user clicks a row in the grid
         * get the corresponding graphic and select it
         *************************************************/
        function selectFeatureFromGrid(event) {
          // close view popup if it is open
          view.popup.close();
          // get the ObjectID value from the clicked row
          const row = event.rows[0]
          const id = row.data.__OBJECTID;

          // setup a query by specifying objectIds
          const query = {
            objectIds: [parseInt(id)],
            outFields: ["*"],
            returnGeometry: true,
            outSpatialReference: view.SpatialReference
          };

          // query the csvLayerView using the query set above
          csvLayerView.queryFeatures(query).then(function(results) {
              const graphics = results.features;
              console.log(graphics);

              // remove all graphics to make sure no selected graphics
              view.graphics.removeAll();
              view.goTo(graphics[0].geometry);

              // create a new selected graphic
              const selectedGraphic = new Graphic({
                geometry: graphics[0].geometry,
                symbol: {
                  type: "simple-marker",
                  style: "circle",
                  color: "orange",
                  size: "12px", // pixels
                  outline: { // autocasts as new SimpleLineSymbol()
                    color: [255, 255, 0],
                    width: 2 // points
                  }
                }
              });

              // add the selected graphic to the view
              // this graphic corresponds to the row that was clicked
              view.graphics.add(selectedGraphic);
            })
            .catch(errorCallback);
        }


      /************************************************
       * Creates a new grid. Loops through poverty
       * csvLayer's fields and creates grid columns
       * Grid with selection and columnhider extensions
       *************************************************/
        function createGrid(fields) {
        var columns = fields.filter(function(field, i) {
          if (gridFields.indexOf(field.name) !== -1) {
            return field;
          }
        }).map(function(field) {
          if (field.name === "__OBJECTID") {
            return {
              field: field.name,
              label: field.name,
              sortable: true,
              hidden: true
            };
          } else {
              return {
                field: field.name,
                label: field.alias,
                sortable: true
              };
            }
          });

          // create a new onDemandGrid with its selection and columnhider
          // extensions. Set the columns of the grid to display attributes
          // the hurricanes cvslayer
          grid = new(OnDemandGrid.createSubclass([Selection, ColumnHider]))({
            columns: columns
          }, "grid");

          // add a row-click listener on the grid. This will be used
          // to highlight the corresponding feature on the view
          grid.on("dgrid-select", selectFeatureFromGrid);
        }

     function setupTheView() {
      map = new Map({ basemap: "gray"});

      
    

    //-----------------------------------------
    // Layer
    //-----------------------------------------
    const url = "https://developers.arcgis.com/javascript/latest/sample-code/layers-csv/live/earthquakes.csv";

    const template = {
          title: "Earthquake Info",
          content: "Magnitude {mag} {type} hit {place} on {time}."
        };

    csvLayer = new CSVLayer({
        url: url,
        copyright: "USGS Earthquakes",
        popupTemplate: template,
        timeInfo: {
            startField: "time"
        },
        outFields: "*"
    });

    view = new MapView({
        container: "viewDiv",
        map: map,
        zoom: 3,
        extent: csvLayer.fullExtent,
        constraints: {
          geometry: csvLayer.fullExten
        }
      });
    
    map.add(csvLayer);

    console.log("finished!");


    

    //-----------------------------------------
    // Widgets 
    //-----------------------------------------

    // BaseMapGallery
    var bgExpand = new Expand({
    view: view,
    content: new BasemapGallery({
    view: view,
    container: document.createElement("div")
    })
    });

    // LayerList mit Legende
    const llExpand = new Expand({
        view: view, 
        content: new LayerList({
          view: view,
          listItemCreatedFunction: function (event) {
            const item = event.item;
            if (item.layer.type != "group") {
              // don't show legend twice
              item.panel = {
                content: "legend",
                open: true
              };
            }
          }
        })
    });

    // TimeSlider
    // time slider widget initialization
    const timeSlider = new TimeSlider({
          container: document.createElement("div"),
          view: view,
          timeVisible: true, // show the time stamps on the timeslider
          loop: true
        });

        view.whenLayerView(csvLayer).then(function (lv) {
          // around up the full time extent to full hour
          timeSlider.fullTimeExtent = csvLayer.timeInfo.fullTimeExtent.expandTo(
            "days"
          );
        });

        let timeSliderDropExpand = new Expand({
        collapsedIconClass: "esri-icon-collapse",
        expandIconClass: "esri-icon-time-clock",
        expandTooltip: "Zeitschieberegler",
        view: view,
        content: timeSlider.container,
        expanded: false
        });

        // TableList



    //Button Tabelle
    node_table = document.getElementById("Table");

	// Create a <button> element
    node_table.innerHTML ="<div class='esri-widget--button esri-widget esri-interactive' role='button';><span aria-hidden='true' role='presentation' class='esri-icon esri-icon-table'></span></div>";
    node_table.id = "TableChange" ; 
    node_table.title="Tabelle ausblenden";
    
    

          const TableChange = document.getElementById("TableChange");
	        TableChange.addEventListener("click", tabelleFunktion);
        

    // Add widget to the top right corner of the view
    view.ui.add([bgExpand, llExpand, timeSliderDropExpand, node_table], {
    position: "top-right"
    });

  }
      
    
    function errorCallback(error) {
          console.log("error:", error)
        }


    function tabelleFunktion() {  
	
      if (tableContainer.style.display !== 'none') {
        tableContainer.style.display = 'none';
        node_table.title ="Tabelle einblenden"
      }
      else{
        tableContainer.style.display = 'block';
        node_table.title ="Tabelle ausblenden"}
    }   
  });
  </script>

</head>
<body>
  <div id="Table"></div>
  <div class="wrapper">
    <div class="box header" id="titleDiv">Vorlage CSVViewer</div>
    <div class="map" id="viewDiv"></div>
    <div id="tableContainer" class="containerT">
    <div id = "tableDiv">
      <div id="info">
        <span class="info">
          <b>Tabelle wird geladen...</b>
        </span>
        <br />
      </div>
      <div id="gridDisplay">
        <span class="info" id="featureCount"></span>
        <div id="grid" class="dgrid dgrid-grid ui-widget"></div>
      </div>
      </div>
      </div>
      </div>
</body>
</html>
0 Kudos
0 Replies