Legend for Graphics Layer

7850
15
Jump to solution
02-21-2012 10:50 AM
SaraSecunda
New Contributor
Hello,

I have a graphics layer with a classbreaks renderer.  The breaks are computed mathematically based on the attribute values.  How can I show a legend for this graphics layer?

Thanks.

Sara S.
0 Kudos
1 Solution

Accepted Solutions
derekswingley1
Frequent Contributor
If applyUpdates is your bottleneck, an alternative approach would be to add your features to your feature collection before you create the actual feature layer. Our sample doesn't do this because the data returned from flickr does not have an object id. By using applyEdits, the feature layer automatically inserts an object id.

I've modified our sample to manually populate an object id attribute when creating a feature set. The end result is the same??? you get a feature layer representing geotagged photos from flickr but the feature layer's features are specified as part of the feature collection creation rather than using applyEdits:

On JSFiddle:  http://jsfiddle.net/ynm6W/

<!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>       Flickr     </title>     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/dojo/dijit/themes/claro/claro.css"/>     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/esri/dijit/css/Popup.css"/>     <style>       html, body { height: 100%; width: 100%; margin: 0; padding: 0; } .esriScalebar{       padding: 20px 20px; } #map{ padding:0;}     </style>     <script type="text/javascript">       var dojoConfig = {         parseOnLoad: true       };     </script>     <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.7">     </script>     <script type="text/javascript">       dojo.require("dijit.layout.BorderContainer");       dojo.require("dijit.layout.ContentPane");       dojo.require("esri.map");       dojo.require("esri.layers.FeatureLayer");       dojo.require("esri.dijit.Popup");         var map, featureLayer;        function init() {         //setup the map's initial extent          var initExtent = new esri.geometry.Extent({"xmin":-16305479,"ymin":-635073,"xmax":5884495,"ymax":8307447,"spatialReference":{"wkid":102100}});          //create a popup to replace the map's info window         var popup = new esri.dijit.Popup(null, dojo.create("div"));         map = new esri.Map("map", {           extent: initExtent,           infoWindow: popup         });         dojo.connect(map, 'onLoad', function(theMap) {           //resize the map when the browser resizes           dojo.connect(dijit.byId('map'), 'resize', map,map.resize);            // get photos from flickr then create a feature layer           requestPhotos();         });          //Add the imagery layer 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_Imagery/MapServer");         map.addLayer(basemap);       }        function requestPhotos(){         //get geotagged photos from flickr         //tags=flower&tagmode=all         var requestHandle = esri.request({           url: "http://api.flickr.com/services/feeds/geo?&format=json",           callbackParamName: "jsoncallback",           load: requestSucceeded,           error: requestFailed         }, {           useProxy: false         });       }              function requestSucceeded(response, io) {         //loop through the items and add to the feature layer         var features = [];         dojo.forEach(response.items, function(item, idx) {           var attr = {};           attr["description"] = item.description;           attr["title"] = item.title ? item.title : "Flickr Photo";           attr["ObjectID"] = idx;            var geometry = esri.geometry.geographicToWebMercator(new esri.geometry.Point(item.longitude, item.latitude, map.spatialReference));            var graphic = new esri.Graphic(geometry);           graphic.setAttributes(attr);           features.push(graphic);         });          //create a feature collection for the flickr photos         var featureCollection = {           "layerDefinition": null,           "featureSet": {             "features": features,             "geometryType": "esriGeometryPoint"           }         };                  featureCollection.layerDefinition = {           "geometryType": "esriGeometryPoint",           "objectIdField": "ObjectID",           "drawingInfo": {             "renderer": {               "type": "simple",               "symbol": {                 "type": "esriPMS",                 "url": "http://dl.dropbox.com/u/2654618/flickr.png",                 "contentType": "image/png",                 "width": 15,                 "height": 15               }             }           },           "fields": [{             "name": "ObjectID",             "alias": "ObjectID",             "type": "esriFieldTypeOID"           },{             "name": "description",             "alias": "Description",             "type": "esriFieldTypeString"           },{             "name": "title",             "alias": "Title",             "type": "esriFieldTypeString"           }]         };          //define a popup template         var popupTemplate = new esri.dijit.PopupTemplate({           title: "{title}",           description:"{description}"         });          //create a feature layer based on the feature collection         featureLayer = new esri.layers.FeatureLayer(featureCollection, {           id: 'flickrLayer',           infoTemplate: popupTemplate         });          map.addLayer(featureLayer);                  //associate the features with the popup on click         dojo.connect(featureLayer,"onClick",function(evt){            map.infoWindow.setFeatures([evt.graphic]);         });       }        function requestFailed(error) {         console.log('failed');       }       dojo.ready(init);     </script>   </head>   <body class="claro">     <div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'headline'"     style="width: 100%; height: 100%; margin: 0;">       <div id="map" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center'"       style="border:1px solid #000;padding:0;">       </div>     </div>   </body>  </html>

View solution in original post

0 Kudos
15 Replies
derekswingley1
Frequent Contributor
Unfortunately, the legend dijit only supports tiled, dynamic, kml and feature layers.

Can you move to using a feature layer? Here's sample that shows using the legend dijit with feature layers:  http://help.arcgis.com/en/webapi/javascript/arcgis/help/jssamples/widget_legend.html
0 Kudos
SaraSecunda
New Contributor
Derek,

Thank  you for your reply.  I unfortunately do not think I can use a feature layer.  I am getting my attributes for States from an oracle stored procedure which I put in an array.  I do a query on the States layer and put the geometry in a graphic and add the attribute data which I use for the classbreaks renderer.  I'm don't think I can add the attribute information to a feature layer from the array, can I?  If not I guess I have to build the legend with dojo?
0 Kudos
NianweiLiu
Occasional Contributor II
Derek,

I'm don't think I can add the attribute information to a feature layer from the array, can I? 


You can create a feature layer using "featureCollection". http://help.arcgis.com/en/webapi/javascript/arcgis/demos/fl/fl_featureCollection.html

It works with Legend. Make sure all async callbacks are in right order.
0 Kudos
derekswingley1
Frequent Contributor
nliu's recommendation is the path you should take- create a feature layer from a feature collection and you'll be able to use that with the legend dijit.
0 Kudos
SaraSecunda
New Contributor
Thank you swingley and Derek!
0 Kudos
SaraSecunda
New Contributor
I have created a feature layer from a feature collection as suggested.  The problem is it is really slow.  In the code below I have an array of items from an Oracle stored procedure and a feature set from a States Layer.  I add this States data to the feature collection and update the collection.  It slows down at line
featureLayer.applyEdits(features, null, null);  Is there anything I'm doing wrong, or is it just slow with 50+ updates?  Thanks!

               //Create featurelayer from feature collection
                var layerDefinition = {
                    "geometryType": "esriGeometryPolygon",
                    "objectIdField": "ObjectID",
                    "fields": [{
                        "name": "ObjectID",
                        "alias": "ObjectID",
                        "type": "esriFieldTypeOID"
                    },
                    {
                        "name": "STATE_NAME",
                        "type": "esriFieldTypeString",
                        "alias": "State Name"
                    },
                    {
                        "name": "NUMB",
                        "alias": "VALUE",
                        "type": "esriFieldTypeInteger"
                    }]
                }
                var featureCollection = {
                    layerDefinition: layerDefinition,
                    featureSet: null
                };

                var content = "<b>State Name</b>: ${STATE_NAME}" +
                      "<br><b>Value</b>: ${NUMB}";
                var infoTemplate = new esri.InfoTemplate("Attributes", content);

                featureLayer = new esri.layers.FeatureLayer(featureCollection, {
                    mode: esri.layers.FeatureLayer.MODE_SNAPSHOT, infoTemplate: infoTemplate
                });

                var features = [];
                var resultFeatures = featureSet.features;  //featureSet is 51 States with State_Name attribute
                var attrs;
                for (var j = 0, il = resultFeatures.length; j < il; j++) {
                    //Get the current feature from the featureSet.
                    var stName = resultFeatures.attributes["STATE_NAME"];
                    var iNumb = findPosition(stName, arrStateList);                 //arrStateList - array with State_name and NUMB attributes
                    atts = { "STATE_NAME": stName, "NUMB": parseInt(iNumb) };
                    graphic = resultFeatures;
                    graphic.setAttributes(atts);
                    features.push(graphic);
                }
                featureLayer.applyEdits(features, null, null);
                featureLayer.setRenderer(renderer);
                map.addLayers([featureLayer]);        
                }
            }

           function findPosition(value, dataArray) {
                var a;
                var b;
                for (var i = 0; i < dataArray.length; i++) {
                    a = dataArray;
                    b = a["StateName"];
                    if (value == b) {
                        return a["TheNumber"];
                    }
                }
             }
0 Kudos
derekswingley1
Frequent Contributor
How long does it take for your features to be returned to the client?

The feature layer from feature collection sample gets data from flickr which takes roughly 1s in my testing. How long does your feature layer take to display? How slow is slow?
0 Kudos
derekswingley1
Frequent Contributor
If applyUpdates is your bottleneck, an alternative approach would be to add your features to your feature collection before you create the actual feature layer. Our sample doesn't do this because the data returned from flickr does not have an object id. By using applyEdits, the feature layer automatically inserts an object id.

I've modified our sample to manually populate an object id attribute when creating a feature set. The end result is the same??? you get a feature layer representing geotagged photos from flickr but the feature layer's features are specified as part of the feature collection creation rather than using applyEdits:

On JSFiddle:  http://jsfiddle.net/ynm6W/

<!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>       Flickr     </title>     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/dojo/dijit/themes/claro/claro.css"/>     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/esri/dijit/css/Popup.css"/>     <style>       html, body { height: 100%; width: 100%; margin: 0; padding: 0; } .esriScalebar{       padding: 20px 20px; } #map{ padding:0;}     </style>     <script type="text/javascript">       var dojoConfig = {         parseOnLoad: true       };     </script>     <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.7">     </script>     <script type="text/javascript">       dojo.require("dijit.layout.BorderContainer");       dojo.require("dijit.layout.ContentPane");       dojo.require("esri.map");       dojo.require("esri.layers.FeatureLayer");       dojo.require("esri.dijit.Popup");         var map, featureLayer;        function init() {         //setup the map's initial extent          var initExtent = new esri.geometry.Extent({"xmin":-16305479,"ymin":-635073,"xmax":5884495,"ymax":8307447,"spatialReference":{"wkid":102100}});          //create a popup to replace the map's info window         var popup = new esri.dijit.Popup(null, dojo.create("div"));         map = new esri.Map("map", {           extent: initExtent,           infoWindow: popup         });         dojo.connect(map, 'onLoad', function(theMap) {           //resize the map when the browser resizes           dojo.connect(dijit.byId('map'), 'resize', map,map.resize);            // get photos from flickr then create a feature layer           requestPhotos();         });          //Add the imagery layer 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_Imagery/MapServer");         map.addLayer(basemap);       }        function requestPhotos(){         //get geotagged photos from flickr         //tags=flower&tagmode=all         var requestHandle = esri.request({           url: "http://api.flickr.com/services/feeds/geo?&format=json",           callbackParamName: "jsoncallback",           load: requestSucceeded,           error: requestFailed         }, {           useProxy: false         });       }              function requestSucceeded(response, io) {         //loop through the items and add to the feature layer         var features = [];         dojo.forEach(response.items, function(item, idx) {           var attr = {};           attr["description"] = item.description;           attr["title"] = item.title ? item.title : "Flickr Photo";           attr["ObjectID"] = idx;            var geometry = esri.geometry.geographicToWebMercator(new esri.geometry.Point(item.longitude, item.latitude, map.spatialReference));            var graphic = new esri.Graphic(geometry);           graphic.setAttributes(attr);           features.push(graphic);         });          //create a feature collection for the flickr photos         var featureCollection = {           "layerDefinition": null,           "featureSet": {             "features": features,             "geometryType": "esriGeometryPoint"           }         };                  featureCollection.layerDefinition = {           "geometryType": "esriGeometryPoint",           "objectIdField": "ObjectID",           "drawingInfo": {             "renderer": {               "type": "simple",               "symbol": {                 "type": "esriPMS",                 "url": "http://dl.dropbox.com/u/2654618/flickr.png",                 "contentType": "image/png",                 "width": 15,                 "height": 15               }             }           },           "fields": [{             "name": "ObjectID",             "alias": "ObjectID",             "type": "esriFieldTypeOID"           },{             "name": "description",             "alias": "Description",             "type": "esriFieldTypeString"           },{             "name": "title",             "alias": "Title",             "type": "esriFieldTypeString"           }]         };          //define a popup template         var popupTemplate = new esri.dijit.PopupTemplate({           title: "{title}",           description:"{description}"         });          //create a feature layer based on the feature collection         featureLayer = new esri.layers.FeatureLayer(featureCollection, {           id: 'flickrLayer',           infoTemplate: popupTemplate         });          map.addLayer(featureLayer);                  //associate the features with the popup on click         dojo.connect(featureLayer,"onClick",function(evt){            map.infoWindow.setFeatures([evt.graphic]);         });       }        function requestFailed(error) {         console.log('failed');       }       dojo.ready(init);     </script>   </head>   <body class="claro">     <div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'headline'"     style="width: 100%; height: 100%; margin: 0;">       <div id="map" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center'"       style="border:1px solid #000;padding:0;">       </div>     </div>   </body>  </html>
0 Kudos
SaraSecunda
New Contributor
Derek,

Thank you for your reply.  When I run the code with applyedits it takes over 10 seconds to draw and sometimes I get a message regarding a slow script running on the page.

I tried running it the way you describe, creating the featurecollection before the feature layer.  It didn't work properly, nothing displayed.  It looks like when I do it the first way I get 51 graphics, but when I create the featurecollection first, the feature layer then shows one graphic with a 51 count.  I'm using a classbreaks renderer and it doesn't have all the States graphics to draw.  I don't know why the feature layer does have 51 graphics.

               var features = [];
                var resultFeatures = featureSet.features;
                var attrs;
                for (var j = 0, il = resultFeatures.length; j < il; j++) {
                    //Get the current feature from the featureSet.
                    var stName = resultFeatures.attributes["STATE_NAME"];
                    var iNumb = findPosition(stName, arrStateList);
                    atts = { "STATE_NAME": stName, "NUMB": parseInt(iNumb) };
                    graphic = resultFeatures;
                    graphic.setAttributes(atts);
                    features.push(graphic);
                }
                //Create featurelayer from feature collection
                var layerDefinition = {
                    "geometryType": "esriGeometryPolygon",
                    "objectIdField": "ObjectID",
                    "fields": [{
                        "name": "ObjectID",
                        "alias": "ObjectID",
                        "type": "esriFieldTypeOID"
                    },
                    {
                        "name": "STATE_NAME",
                        "type": "esriFieldTypeString",
                        "alias": "State Name"
                    },
                    {
                        "name": "NUMB",
                        "alias": "VALUE",
                        "type": "esriFieldTypeInteger"
                    }]
                }
                var featureCollection = {
                    "layerDefinition": layerDefinition,
                    "featureSet": {
                        "features": features,
                        "geometryType": "esriGeometryPolygon"
                    }
                }

                var content = "<b>State Name</b>: ${STATE_NAME}" +
                      "<br><b>Value</b>: ${NUMB}";
                var infoTemplate = new esri.InfoTemplate("Attributes", content);

                featureLayer = new esri.layers.FeatureLayer(featureCollection, {
                    mode: esri.layers.FeatureLayer.MODE_SNAPSHOT, infoTemplate: infoTemplate
                });

                featureLayer.setRenderer(renderer);
                map.addLayers([featureLayer]);
0 Kudos