Legend with Visible Layers - how to modify for sublayers?

11963
28
07-12-2012 04:55 AM
CurtWalker
Deactivated User
I'm using this tutorial to create a map with legend and checkboxes for turning layers on and off.  Currently it only gives one checkbox per map service if you are using a Dynamic Map Service (which I am because I need labels and Feature Layers do not support labels).

How can I modify this code so it gives a checkbox for every sublayer in the Dynamic Map Service instead of just one checkbox that turns everything on/off?
0 Kudos
28 Replies
BrettGreenfield__DNR_
Frequent Contributor
Try this tutorial.  I was trying to do what you're doing and this sample helped me put something together.
0 Kudos
CurtWalker
Deactivated User
Thanks, I tried that one and it did give me a checkbox for each sublayer, but the problem is the legend doesn't update when you toggle layers on and off.  It seems load once when the maps loads and never refreshes.  I tired looking for another event for it to listen on that's fired when you toggle a sublayer's checkbox but I couldn't make it work.  How did you do it?
0 Kudos
BrettGreenfield__DNR_
Frequent Contributor
Actually, I ran into that same problem!  I pored over a lot of the help topics and they all claimed that the legend is supposed to update automatically when the layer visibility changed, but that never worked for me.  If anyone has an answer to it, I'd love to know!
0 Kudos
CurtWalker
Deactivated User
Ok, I just discovered that my legend will update if I zoom the map in or out after toggling a checkbox.  Better but still not great.  The user shouldn't have to do that.  So whatever even is fired with the map zooms in or out is also refreshing the legend.  If we can figure out what that is, or otherwise set that function to do a small zoom automatically when a checkbox is toggled, then I guess I could live with that.  I'm still working on it....
0 Kudos
SiqiLi
by Esri Contributor
Esri Contributor
To change the visibility of each individual layer of a map service, you need to work with the ArcGISDynamicMapServiceLayer.setVisibleLayers() method.

Here is a sample I put together to demonstrate how to toggle the visibility of each individual layer of a map service by using check box. Hope this helps to get you start.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
    <!--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>Updating the legend to display visible layers</title>
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.0/js/dojo/dijit/themes/claro/claro.css">
    <style>
      html, body { height: 98%; width: 98%; margin: 0; padding: 5px; }
      #rightPane{
        width:20%;
      }
      #legendPane{
        border: solid #97DCF2 1px;
      }
     
    </style>
    <script type="text/javascript">var djConfig = {parseOnLoad: true};</script>
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.0"></script>
    <script type="text/javascript">
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require("dijit.layout.AccordionContainer");
      dojo.require("esri.map");
      dojo.require("esri.dijit.Legend");
      dojo.require("esri.arcgis.utils");
      dojo.require("dijit.form.CheckBox");
     
      var map;
      var legendLayers = [];
      var legendLayer;
 
      function init() {
        var initialExtent = new esri.geometry.Extent({"xmin":-117.98,"ymin":33.95,"xmax":-116.92,"ymax":34.44,"spatialReference":{"wkid":4326}});
        map = new esri.Map("map", { extent: esri.geometry.geographicToWebMercator(initialExtent)});
       
        //Add the terrain service to the map. View the ArcGIS Online site for services http://arcgisonline/home/search.html?t=content&f=typekeywords:service    
        var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer");
        map.addLayer(basemap);

        var quakeLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/EarthquakesFromLastSevenDays/MapServer",{id:'quakes'});

        legendLayers.push({layer:quakeLayer,title:'Earthquakes'});
       
        var fireLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Fire/Sheep/MapServer",{id:'fire'});

        legendLayers.push({layer:fireLayer,title:"Fire"});
        dojo.connect(map,'onLayersAddResult',function(results){
          var legend = new esri.dijit.Legend({
            map:map,
            layerInfos:legendLayers
          },"legendDiv");
          legend.startup();
        });
        map.addLayers([fireLayer,quakeLayer]);

       dojo.connect(map,'onLayersAddResult',function(results){
          var layerLists=[];
          dojo.forEach(legendLayers,function(layer){     
         layerLists.push(buildLayerList(layer));
          });
          
          dojo.byId("layer_list").innerHTML = layerLists.join('');
        });
       
        dojo.connect(map, 'onLoad', function(theMap) {
          //resize the map when the browser resizes
          dojo.connect(dijit.byId('map'), 'resize', map,map.resize);
        });
      }

      function buildLayerList(layer) {
       var visible = [];
        var items = dojo.map(layer.layer.layerInfos,function(info,index){
       if (info.defaultVisibility) {
           visible.push(info.id);
       }
          return "<input type='checkbox' class='" + layer.title + "' checked='true' id='" + info.id + "' onclick='updateLayerVisibility();' /><label for='" + info.id + "'>" + info.name + "</label><br>";
        });
        
        layer.layer.setVisibleLayers(visible);
        return items.join(' ');
      }
      
      function updateLayerVisibility() {
       dojo.forEach(legendLayers,function(layer){   
         var inputs = dojo.query("."+ layer.title), input;
          var visible = [];
          dojo.forEach(inputs,function(input){
            if (input.checked) {
               visible.push(input.id);
            }
         });
         //if there aren't any layers visible set the array to be -1
         if(visible.length === 0){
            visible.push(-1);
         }
         layer.layer.setVisibleLayers(visible);   
        });
      }

      dojo.addOnLoad(init);
      
    </script>
  </head>
 
  <body class="claro">
    <div id="content" dojotype="dijit.layout.BorderContainer" design="headline" gutters="true" style="width: 100%; height: 100%; margin: 0;">
      <div id="rightPane" dojotype="dijit.layout.ContentPane" region="right">
        <div dojoType="dijit.layout.AccordionContainer">
          <div dojoType="dijit.layout.ContentPane" id="legendPane" title="Legend"  selected="true">
            <div id="legendDiv"></div>
          </div>
          <div dojoType="dijit.layout.ContentPane" title="Natural Disasters" >
            <span style="padding:10px 0;" id="layer_list"></span>
            <div id="toggle" style="padding: 2px 2px;"></div>
          </div>
        </div>
      </div>
      <div id="map" dojotype="dijit.layout.ContentPane" region="center" style="overflow:hidden;">
      </div>
    </div>
  </body>
 
</html>
0 Kudos
SiqiLi
by Esri Contributor
Esri Contributor
To change the visibility of each individual layer in the map, you need to work with the ArcGISDynamicMapServiceLayer.setVisibleLayers() method.

To change the visibility of each individual layer in the legend control, you need to work with the Legend.hideLayers property. Then follow by calling Legend.fefresh() method.

Here is a sample I put together to demonstrate how to toggle the visibility of each individual layer of a map service by using check box. The corresponding legend will auto-update itself in the legend control. Hope this helps.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
    <!--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>Updating the legend to display visible layers</title>
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.0/js/dojo/dijit/themes/claro/claro.css">
    <style>
      html, body { height: 98%; width: 98%; margin: 0; padding: 5px; }
      #rightPane{
        width:20%;
      }
      #legendPane{
        border: solid #97DCF2 1px;
      }
     
    </style>
    <script type="text/javascript">var djConfig = {parseOnLoad: true};</script>
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.0"></script>
    <script type="text/javascript">
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require("dijit.layout.AccordionContainer");
      dojo.require("esri.map");
      dojo.require("esri.dijit.Legend");
      dojo.require("esri.arcgis.utils");
      dojo.require("dijit.form.CheckBox");
     
      var map;
      var legendLayers = [];
      var legendLayer;
      var legend;
 
      function init() {
        var initialExtent = new esri.geometry.Extent({"xmin":-117.98,"ymin":33.95,"xmax":-116.92,"ymax":34.44,"spatialReference":{"wkid":4326}});
        map = new esri.Map("map", { extent: esri.geometry.geographicToWebMercator(initialExtent)});
       
        //Add the terrain service to the map. View the ArcGIS Online site for services http://arcgisonline/home/search.html?t=content&f=typekeywords:service    
        var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer");
        map.addLayer(basemap);

        var quakeLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Earthquakes/EarthquakesFromLastSevenDays/MapServer",{id:'quakes'});

        legendLayers.push({layer:quakeLayer,title:'Earthquakes'});
       
        var fireLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Fire/Sheep/MapServer",{id:'fire'});

        legendLayers.push({layer:fireLayer,title:"Fire"});
        dojo.connect(map,'onLayersAddResult',function(results){
          legend = new esri.dijit.Legend({
            map:map,
            layerInfos:legendLayers
          },"legendDiv");
          legend.startup();
        });
        map.addLayers([fireLayer,quakeLayer]);

       dojo.connect(map,'onLayersAddResult',function(results){
          var layerLists=[];
          dojo.forEach(legendLayers,function(layer){     
         layerLists.push(buildLayerList(layer));
          });
          
          dojo.byId("layer_list").innerHTML = layerLists.join('');
        });
       
        dojo.connect(map, 'onLoad', function(theMap) {
          //resize the map when the browser resizes
          dojo.connect(dijit.byId('map'), 'resize', map,map.resize);
        });
      }

      function buildLayerList(layer) {
       var visible = [];
       var hide=[];
        var items = dojo.map(layer.layer.layerInfos,function(info,index){
       if (info.defaultVisibility) 
           visible.push(info.id);
       else
              hide.push(input.id);
          return "<input type='checkbox' class='" + layer.title + "' checked='true' id='" + info.id + "' onclick='updateLayerVisibility();' /><label for='" + info.id + "'>" + info.name + "</label><br>";
        });
        
        layer.layer.setVisibleLayers(visible);
        legend.hidLayers=hide;
        legend.refresh();
        return items.join(' ');
      }
      
      function updateLayerVisibility() {
       dojo.forEach(legendLayers,function(layer){   
         var inputs = dojo.query("."+ layer.title), input;
          var visible = [];
          var hide=[];
          dojo.forEach(inputs,function(input){
            if (input.checked) 
               visible.push(input.id);
            else
               hide.push(input.id);
         });
         //if there aren't any layers visible set the array to be -1
         if(visible.length === 0){
            visible.push(-1);
         }
         layer.layer.setVisibleLayers(visible);  
         legend.hidLayers=hide;
         legend.refresh();
         
        });
      }

      dojo.addOnLoad(init);
      
    </script>
  </head>
 
  <body class="claro">
    <div id="content" dojotype="dijit.layout.BorderContainer" design="headline" gutters="true" style="width: 100%; height: 100%; margin: 0;">
      <div id="rightPane" dojotype="dijit.layout.ContentPane" region="right">
        <div dojoType="dijit.layout.AccordionContainer">
          <div dojoType="dijit.layout.ContentPane" id="legendPane" title="Legend"  selected="true">
            <div id="legendDiv"></div>
          </div>
          <div dojoType="dijit.layout.ContentPane" title="Natural Disasters" >
            <span style="padding:10px 0;" id="layer_list"></span>
            <div id="toggle" style="padding: 2px 2px;"></div>
          </div>
        </div>
      </div>
      <div id="map" dojotype="dijit.layout.ContentPane" region="center" style="overflow:hidden;">
      </div>
    </div>
  </body>
 
</html>

0 Kudos
CurtWalker
Deactivated User
Shuping,

Thanks for the code.  It does as you say and adds checkboxes for all sublayers.  But did you notice that the legend is tripled?  It puts the same layers in the legend three times in a row.  I think this is a step in the right direction regarding the checkboxes though.
0 Kudos
SiqiLi
by Esri Contributor
Esri Contributor
Shuping,

Thanks for the code.  It does as you say and adds checkboxes for all sublayers.  But did you notice that the legend is tripled?  It puts the same layers in the legend three times in a row.  I think this is a step in the right direction regarding the checkboxes though.


I tested my sample again, however I don't see the tripled legend issue. It runs correctly in both Firefox, Chrome, and IE. Please see the attached screenshot 1->2->3->4.

[ATTACH=CONFIG]16035[/ATTACH]
[ATTACH=CONFIG]16036[/ATTACH]
[ATTACH=CONFIG]16037[/ATTACH]
[ATTACH=CONFIG]16038[/ATTACH]

Please feel free to let me know if I overlooked any detail. Thanks.
0 Kudos
CurtWalker
Deactivated User
That's really weird. I just tried your code again to make sure.  I pasted your code into a fresh document and hit it with IE and FF.  In FF the legend appears normal, but in IE9 I get the tripled legend.  Here's a screenshot.

[ATTACH=CONFIG]16063[/ATTACH]
0 Kudos