JS API 3.X and FeatureLayer.setSelectionSymbol

453
3
07-07-2021 11:05 AM
NathanHeickLACSD
Occasional Contributor III

When using setSelectionSymbol and selectFeatures on a FeatureLayer, do you have to call setSelectionSymbol before the layer is added to the map?  I tried setting it right before making the selection and nothing is happening.

0 Kudos
3 Replies
KenBuja
MVP Honored Contributor

No, you can add it anywhere. For example, the code (based on the Select with Feature Layer sample, changes the select symbology three seconds (lines 129-141) after showing the selection. I also reset it on each selection (line 124).

 

<!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="https://js.arcgis.com/3.37/dijit/themes/tundra/tundra.css">
  <link rel="stylesheet" href="https://js.arcgis.com/3.37/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="https://js.arcgis.com/3.37/"></script>
  <script>
    var map;
    require([
      "esri/map", "esri/layers/FeatureLayer",
      "esri/tasks/query", "esri/geometry/Circle",
      "esri/graphic", "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, 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: [-95.249, 38.954],
        zoom: 14,
        slider: false
      });

      // Add the census block points in on demand mode. An outfield is specified since it is used when calculating   the total population falling within the one mile radius.
      var featureLayer = new FeatureLayer("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0", {
        outFields: ["POP2000"]
      });

      // 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: 1,
          radiusUnit: "esriMiles"
        });
        map.graphics.clear();
        var graphic = new Graphic(circle, circleSymb);
        map.graphics.add(graphic);

        var query = new Query();
        query.geometry = circle.getExtent();
        // Use a fast bounding box query. It 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[i];
          if (circle.contains(feature.geometry)) {
            inBuffer.push(feature.attributes[featureLayer.objectIdField]);
          }
        }
        var query = new Query();
        query.objectIds = inBuffer;
        // Use an objectIds selection query (should not need to go to the server)
        featureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function (results) {
          featureLayer.setSelectionSymbol(symbol);
          var totalPopulation = sumPopulation(results);
          var r = "";
          r = "<b>The total Census Block population within the buffer is <i>" + totalPopulation + "</i>.</b>";
          dom.byId("messages").innerHTML = r;
          setTimeout(function () {
            var symbol1 = new SimpleMarkerSymbol(
              SimpleMarkerSymbol.STYLE_CIRCLE,
              12,
              new SimpleLineSymbol(
                SimpleLineSymbol.STYLE_NULL,
                new Color([247, 34, 101, 0.9]),
                1
              ),
              new Color([255, 0, 0, 1])
            );
            featureLayer.setSelectionSymbol(symbol1);
          }, 3000);
        });
      }

      function sumPopulation(features) {
        var popTotal = 0;
        for (var x = 0; x < features.length; x++) {
          popTotal = popTotal + features[x].attributes["POP2000"];
        }
        return popTotal;
      }
    });
  </script>
</head>

<body>
  <span id="messages">Click on the map to select census block points within 1 mile.</span>
  <div id="mapDiv"></div>
</body>
</html>

 

 

0 Kudos
NathanHeickLACSD
Occasional Contributor III

Thanks Ken for confirming that this should work.  I am having a lot of difficulty from within the _onSelectResult event handler of the Search widget.  I need to be able to make a query based on the selected result and select related features on the map.  I added the following code to the beginning of the function just for testing:

 

var layer = this.map.getLayer("Pipes");
var symbol = new SimpleLineSymbol(
  SimpleLineSymbol.STYLE_SOLID,
  new Color([255, 0, 0]),
  2
);

layer.setSelectionSymbol(symbol);

var query = new FeatureQuery();
query.objectIds = [1];
layer.selectFeatures(query, FeatureLayer.SELECTION_NEW);

return;

 

 What is strange is that I don't see any selected features on the map, but if I go into the Attribute Table widget, the feature with OBJECTID = 1 has been selected.  Then, if I double-click on a record in the Attribute Table widget, it selects it, zooms to it, and highlights it in the symbol I specified.  I really don't know why calling selectFeatures doesn't highlight them.  I can see the feature in the attribute _selectedFeatures of the feature layer and I can see the selection symbol in _selectionSymbol as well.

0 Kudos
NathanHeickLACSD
Occasional Contributor III

Thanks Ken for confirming that this should be doable.  Your sample worked just fine and another sample from the documentation worked just fine.  I'm trying to customize the Search widget to select features related to the search result.  If I set the selection symbol and select features, the features show up in the Attribute Table widget, but they do not highlight on the map.  When I select another feature in the Attribute Table, it highlights it on the map with the selection symbol that I specified.  For some reason, I'm having a hard time getting the selection I made using selectFeatures to show up on the map.

0 Kudos