Looking for the right event to hook into for feature deselect

1794
12
Jump to solution
08-08-2014 10:22 AM
SteveCole
Frequent Contributor

I'm currently developing a basic web map app for showing various projects. I'm using v3.10 of the API and started with the "Popup content in side panel" sample. Instead of a static side panel for a selected feature's information, I decided to use a jQuery slide panel that appears when the user clicks on a feature (see the screenshot). I have added a close button within my slide panel which will close the panel and fire map.graphics.clear() to remove the graphic of the currently selected item. This all works just fine.

What I want to do (can can't figure out the best way to do it) is close my side panel if the user clicks someplace on the map (but not on another feature). I tried to account for this using the following:

map.on("click", function() {

     if(map.graphics.graphics.length == 0) {

          //Close my side panel here

     }

}

but the problem is that the click event fires before the selected graphic is removed and so map.graphics.graphics.length never equals zero. I've also thought about trying to tie into the map's graphicLayer and it's "graphics-clear" event but I can't seem to do it. The following returns null:

theGraphicsLayer = map.graphics;

So what am I missing? The app isn't public facing yet so I can't link to a live example.

Thanks!

Steve

Screenshot:

tipMapFeatSelect.jpg

0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Steve,

  Here is a full working sample with sliding panel (no JQuery, just dojo).

<!DOCTYPE html>

<html>

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  <!--The viewport meta tag is used to improve the presentation and behavior of the samples

      on iOS devices-->

  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">

  <title>Sliding Info Panel</title>

  <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.10/js/dojo/dijit/themes/tundra/tundra.css">

  <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">

  <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Open Sans">

  <style type="text/css">

    html,

    body {

      height: 100%;

      width: 100%;

      margin: 0;

      padding: 0;

      margin: 0;

      font-family: "Open Sans";

    }

    #leftPane {

      width: 20%;

      margin: 10px;

      -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      background-color: white;

      border: solid 1px gray;

    }

    #map {

      padding: 0;

      -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      border: solid 1px gray;

      margin: 10px;

      overflow: hidden;

      position: relative;

    }

    #header {

      text-align: center;

      height: 40px;

      margin: 10px;

      background-color: whitesmoke;

    }

    #footer {

      -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      border: solid 1px gray;

      border-radius: 8px;

      text-align: center;

      margin: 10px;

      height: 50px;

      background-color: white;

    }

    #sliderDiv {

      top: 0;

      left: -420px;

      background-color: steelblue;

      position: absolute;

      z-index: 9999;

      -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.6);

      box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.6);

      border: solid 1px gray;

      color: white;

      padding: 5px;

    }

    #mainWindow {

      width: 100%;

      height: 100%;

      background-color: whitesmoke;

    }

  </style>

  <script src="http://js.arcgis.com/3.10/"></script>

  <script>

    var map;

    require([

        "esri/map", "esri/layers/FeatureLayer",

        "esri/tasks/query", "esri/geometry/Circle",

        "esri/graphic", "esri/InfoTemplate", "esri/symbols/SimpleMarkerSymbol",

        "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleFillSymbol", "esri/renderers/SimpleRenderer",

        "esri/config", "esri/Color", "dojo/dom", "dojo/_base/connect", "dojo/parser", "dijit/registry",

        'dojo/_base/html', "esri/domUtils", "dojo/fx", "dijit/layout/BorderContainer",

        "dijit/layout/ContentPane", "dojo/domReady!"

      ], function (

      Map, FeatureLayer,

      Query, Circle,

      Graphic, InfoTemplate, SimpleMarkerSymbol,

      SimpleLineSymbol, SimpleFillSymbol, SimpleRenderer,

      esriConfig, Color, dom, connect, parser, registry, html, domUtils, fx

    ) {

      // 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 = "http://gislap183/Proxy/proxy.ashx";

      parser.parse();

      map = new Map("map", {

        basemap: "streets",

        center: [-95.249, 38.954],

        zoom: 14,

        slider: false

      });

      map.infoWindow.set("popupWindow", false);

      //add the census block points in on demand mode. Note that an info template has been defined so when

      //selected features are clicked a popup window will appear displaying the content defined in the info template.

      var featureLayer = new FeatureLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0", {

        infoTemplate: new InfoTemplate("Block: ${BLOCK}", "${*}"),

        outFields: ["POP2000", "HOUSEHOLDS", "HSE_UNITS", "TRACT", "BLOCK"]

      });

      function displayPopupContent(feature) {

        if (feature) {

          if (dojo.marginBox("sliderDiv").l < 0) {

            slideIt(420);

          }

          var content = feature.getContent();

          dom.byId("sliderDiv").innerHTML = content;

        }

      }

      function slideIt(amt) {

        var slideArgs = {

          node: "sliderDiv",

          top: (dojo.marginBox("sliderDiv").t).toString(),

          left: (dojo.marginBox("sliderDiv").l + amt).toString(),

          unit: "px"

        };

        var animation = fx.slideTo(slideArgs);

        animation.play();

      }

      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);

      map.addLayer(featureLayer);

      var popup = map.infoWindow;

      //when the selection is cleared remove the popup content from the side panel.

      connect.connect(popup, "onClearFeatures", function () {

        setTimeout(function () {

          var graphic = popup.getSelectedFeature();

          if (graphic) {

            displayPopupContent(popup.getSelectedFeature());

          } else {

            slideIt(-420);

            dom.byId("sliderDiv").innerHTML = "";

          }

        }, 500);

      });

    });

  </script>

</head>

<body class="tundra">

  <div id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">

    <div id="header" dojotype="dijit.layout.ContentPane" region="top">

      The project shown below are those identified

    </div>

    <div id="leftPane" dojotype="dijit.layout.ContentPane" region="left">

      This is left section stuff

    </div>

    <div id="map" dojotype="dijit.layout.ContentPane" region="center">

      <div id="sliderDiv" style="height: 98%; width: 400px;"></div>

    </div>

    <div id="footer" dojotype="dijit.layout.ContentPane" region="bottom">

      this is your legend

    </div>

  </div>

</body>

</html>

View solution in original post

12 Replies
RobertScheitlin__GISP
MVP Emeritus

Steve,

  In the sample you started with the contents of the side panel are only populated if.

          function displayPopupContent(feature){

                if(feature){

                    var content = feature.getContent();

                    registry.byId("leftPane").set("content", content);

                }

            }

Could you not use this if and add an else > hide your panel.

0 Kudos
SteveCole
Frequent Contributor

Thanks for the reply, Robert.

My app is loosely based on the sample.

I moved away from some of the logic in the sampel and the actual display of the panels in my app are handled by the traditional click event on the relevant featureLayers:

theFeatureLayer.on("click",function(evt) {

......

});

I just went back to the sample and tried incorporating the "onClearFeatures" event based on the popup but now the panel won't open because this event is triggered during the course of selecting a feature. Basically, it gets closed as it's supposed to open. That's a no-go as well..

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Steve,

   What about using "onSelectionChange" instead and if your featurelayers selection count is zero than hide the panel

0 Kudos
SteveCole
Frequent Contributor

No- that doesn't work. It actually prevents the panel from opening by hiding it prematurely.

[side note- I REALLY hate these new forums. Why is it so friggin hard to paste in JS code? Argh]

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Steve,

   Conceptually I don't know why this does not work for you. It is hard to diagnose with out seeing your code.

0 Kudos
SteveCole
Frequent Contributor

Ok, now that I can finally post code correctly, lemme reply.

The best I can do since it's not public facing at this time is post all the relevant code so here goes..

Starting here:

        //Set the infoWindow to not display since the content is going to the slideout panel

        map.infoWindow.set("popupWindow", false);

The click event for one of the featureLayers:

        tipLines.on("click", function(evt) {

            if($("#tipPointPanel").is(":visible") ) {

                        $("#tipPointPanel").hide();

            }

          

            attrib = evt.graphic.attributes;

          

            document.getElementById("lnTipType").innerHTML = getTipCatType(attrib.tipType);

            document.getElementById("lnPrjName").innerHTML = attrib.prjName;

            document.getElementById("lnPrjStart").innerHTML = attrib.prjStart;

            document.getElementById("lnPrjEnd").innerHTML = attrib.prjEnd;

            document.getElementById("lnCouncilDist").innerHTML = attrib.councilDist;

            document.getElementById("lnOnAcp").innerHTML = attrib.onACP;          

            document.getElementById("lnImpType").innerHTML = getImprovementType(attrib.impType);

            document.getElementById("lnPrjDesc").innerHTML = attrib.prjDescr;

            document.getElementById("lnPrjPhase").innerHTML = attrib.prjPhase;

            document.getElementById("lnTipID").innerHTML = attrib.TIPID;          

            if(attrib.prjURL == null) {

                $("#showLnPrjLink").css("display","none");

                $("#hideLnPrjLink").css("display","inherit");

                $("#lnPrjUrlLink").prop("href", "javascript:void(0)");

            } else {

                $("#showLnPrjLink").css("display","inherit");

                $("#hideLnPrjLink").css("display","none");  

                $("#lnPrjUrlLink").prop("href", attrib.prjURL + "/#structuralContainer12");

            }

          

            curColors = getTipCatColor(attrib.tipType);

            document.getElementById("lnTipTypeBackground").style.background = curColors[0].toString();

            document.getElementById("lnTipTypeBackground").style.color = curColors[1].toString();

            $("#tipLinePanel").animate({ "width": "25%", "display": "inline" }, "fast" );

        });

Here's where I'm trying to respond to a few situations where the panel should close:

        //when the selection is cleared remove the popup content from the side panel.

        connect.connect(tipLines, "onSelectionClear", function(){

            $("#tipLinePanel").animate({ "width": "0%"}, "fast", "swing", function() {$("#tipLinePanel").hide();} );

        });

      

        connect.connect(tipLines, "onSelectionComplete", function (features,selMethod) {

            if (features.length == 0) {

                $("#tipLinePanel").animate({ "width": "0%"}, "fast", "swing", function() {$("#tipLinePanel").hide();} );

            }

        });

Finally, that brings me to my original post and my attempts to respond to a mouse click elsewhere on the map which unselects a feature and should close my panel:

        map.on("click", function() {

            console.log("debugging!");

          

            if(map.graphics.graphics.length == 0) {

                if($("#tipLinePanel").is(":visible") ) {

                    $("#tipLinePanel").hide();

                }

                if($("#tipPointPanel").is(":visible") ) {

                    $("#tipPointPanel").hide();

                }

            }

        });

That's all the code as it relates to interacting with the featureLayer that populates a side panel.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Steve,

  OK now I see that you really don't have much left from the original sample. Why did you choose to go with the click event on the feature layer? Well after some testing on POUP events NOT feature events, I have found that when onSetFeatures is fired so is onClearFeatures so all I can come up with is that you add a timer to your onClearFeatures function to wait a half second or so and then check the number of selected features before you hide your panel.

        connect.connect(popup, "onClearFeatures", function(){

          setTimeout(function(){

            var graphic = popup.getSelectedFeature();

            if(graphic){

              console.info("a feature is selected");

            }else{

              console.info("No feature is selected");

            }

          },500)

        });

Using this I am able to successfully determine if a feature is actually selected or not. Let me know if there was some underlying reason you choose to go with FeatureLayer click instead of the PopUp stuff.

0 Kudos
OwenEarley
Occasional Contributor III

Hi Steve,

Check out my last post on this thread: How to save the user's graphic to feature class?

A new map instance already has a map.graphics.graphics.length > 0 so this may be messing with your visibility setting code.

Not sure why there is a single graphic but you could test for it as it has the coordinates 0, 0:

new-map-gr.png

It would be good if someone from ESRI could elaborate on this.

Owen

Spatial XP

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Steve,

  Here is a full working sample with sliding panel (no JQuery, just dojo).

<!DOCTYPE html>

<html>

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  <!--The viewport meta tag is used to improve the presentation and behavior of the samples

      on iOS devices-->

  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">

  <title>Sliding Info Panel</title>

  <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.10/js/dojo/dijit/themes/tundra/tundra.css">

  <link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">

  <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Open Sans">

  <style type="text/css">

    html,

    body {

      height: 100%;

      width: 100%;

      margin: 0;

      padding: 0;

      margin: 0;

      font-family: "Open Sans";

    }

    #leftPane {

      width: 20%;

      margin: 10px;

      -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      background-color: white;

      border: solid 1px gray;

    }

    #map {

      padding: 0;

      -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      border: solid 1px gray;

      margin: 10px;

      overflow: hidden;

      position: relative;

    }

    #header {

      text-align: center;

      height: 40px;

      margin: 10px;

      background-color: whitesmoke;

    }

    #footer {

      -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);

      border: solid 1px gray;

      border-radius: 8px;

      text-align: center;

      margin: 10px;

      height: 50px;

      background-color: white;

    }

    #sliderDiv {

      top: 0;

      left: -420px;

      background-color: steelblue;

      position: absolute;

      z-index: 9999;

      -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.6);

      -moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.6);

      box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.6);

      border: solid 1px gray;

      color: white;

      padding: 5px;

    }

    #mainWindow {

      width: 100%;

      height: 100%;

      background-color: whitesmoke;

    }

  </style>

  <script src="http://js.arcgis.com/3.10/"></script>

  <script>

    var map;

    require([

        "esri/map", "esri/layers/FeatureLayer",

        "esri/tasks/query", "esri/geometry/Circle",

        "esri/graphic", "esri/InfoTemplate", "esri/symbols/SimpleMarkerSymbol",

        "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleFillSymbol", "esri/renderers/SimpleRenderer",

        "esri/config", "esri/Color", "dojo/dom", "dojo/_base/connect", "dojo/parser", "dijit/registry",

        'dojo/_base/html', "esri/domUtils", "dojo/fx", "dijit/layout/BorderContainer",

        "dijit/layout/ContentPane", "dojo/domReady!"

      ], function (

      Map, FeatureLayer,

      Query, Circle,

      Graphic, InfoTemplate, SimpleMarkerSymbol,

      SimpleLineSymbol, SimpleFillSymbol, SimpleRenderer,

      esriConfig, Color, dom, connect, parser, registry, html, domUtils, fx

    ) {

      // 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 = "http://gislap183/Proxy/proxy.ashx";

      parser.parse();

      map = new Map("map", {

        basemap: "streets",

        center: [-95.249, 38.954],

        zoom: 14,

        slider: false

      });

      map.infoWindow.set("popupWindow", false);

      //add the census block points in on demand mode. Note that an info template has been defined so when

      //selected features are clicked a popup window will appear displaying the content defined in the info template.

      var featureLayer = new FeatureLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0", {

        infoTemplate: new InfoTemplate("Block: ${BLOCK}", "${*}"),

        outFields: ["POP2000", "HOUSEHOLDS", "HSE_UNITS", "TRACT", "BLOCK"]

      });

      function displayPopupContent(feature) {

        if (feature) {

          if (dojo.marginBox("sliderDiv").l < 0) {

            slideIt(420);

          }

          var content = feature.getContent();

          dom.byId("sliderDiv").innerHTML = content;

        }

      }

      function slideIt(amt) {

        var slideArgs = {

          node: "sliderDiv",

          top: (dojo.marginBox("sliderDiv").t).toString(),

          left: (dojo.marginBox("sliderDiv").l + amt).toString(),

          unit: "px"

        };

        var animation = fx.slideTo(slideArgs);

        animation.play();

      }

      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);

      map.addLayer(featureLayer);

      var popup = map.infoWindow;

      //when the selection is cleared remove the popup content from the side panel.

      connect.connect(popup, "onClearFeatures", function () {

        setTimeout(function () {

          var graphic = popup.getSelectedFeature();

          if (graphic) {

            displayPopupContent(popup.getSelectedFeature());

          } else {

            slideIt(-420);

            dom.byId("sliderDiv").innerHTML = "";

          }

        }, 500);

      });

    });

  </script>

</head>

<body class="tundra">

  <div id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">

    <div id="header" dojotype="dijit.layout.ContentPane" region="top">

      The project shown below are those identified

    </div>

    <div id="leftPane" dojotype="dijit.layout.ContentPane" region="left">

      This is left section stuff

    </div>

    <div id="map" dojotype="dijit.layout.ContentPane" region="center">

      <div id="sliderDiv" style="height: 98%; width: 400px;"></div>

    </div>

    <div id="footer" dojotype="dijit.layout.ContentPane" region="bottom">

      this is your legend

    </div>

  </div>

</body>

</html>