Hide Table of Contents
View Class breaks renderer with dynamic layer sample in sandbox
Class breaks renderer with dynamic layer

Description

This functionality requires an ArcGIS Server 10.1 service.

Dynamic layers provide the ability to change the renderer(s) for layers in a dynamic map service. In this sample, when the range specified by the slider changes, a new map images is requested and the map updates to show features that fall within the new range. This functionality was previously possible using feature layers and renderers. The advantage to using a dynamic layer as opposed to a feature layer is that dynamic layers perform much better when a layer has thousands of features.

Code

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Class breaks renderer with dynamic layer</title>
    <link rel="stylesheet" href="https://js.arcgis.com/3.21/dijit/themes/tundra/tundra.css">
    <link rel="stylesheet" href="https://js.arcgis.com/3.21/dojox/form/resources/RangeSlider.css">
    <link rel="stylesheet" href="https://js.arcgis.com/3.21/esri/css/esri.css">
    <style>
      html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
      h3 { margin: 0 0 5px 0; border-bottom: 1px solid #444; text-align: center }
      .shadow {
        -moz-box-shadow: 0 0 5px #888;
        -webkit-box-shadow: 0 0 5px #888;
        box-shadow: 0 0 5px #888;
      }
      #map{ margin: 0; padding: 0; }
      #feedback {
        background: #fff;
        color: #444;
        position: absolute;
        font-family: arial;
        height: 210px;
        left: 30px;
        margin: 5px;
        padding: 10px;
        bottom: 30px;
        width: 320px;
        z-index: 40;
      }
      .note { font-size: 80%; padding: 0 0 10px 0; }
      #slider {
        color: #666;
        margin: 5px auto;
        padding: 3px;
      }
      #appSliderLabel { padding: 0 0 10px 0; }
      #maxLabel { display: inline-block; margin: 0 0 0 -30px;}
      #minLabel { display: inline-block; margin: 0 0 0 30px;}
      #breakInfo { padding: 20px 0 0 0; }
    </style>

    <script>var dojoConfig = { parseOnLoad: true };</script>
    <script src="https://js.arcgis.com/3.21/"></script>
    <script>
      dojo.require("dijit.layout.BorderContainer");
      dojo.require("dijit.layout.ContentPane");
      dojo.require("dijit.form.HorizontalRuleLabels");
      dojo.require("dojox.form.RangeSlider");
      dojo.require("esri.map");
      dojo.require("esri.layers.FeatureLayer");
      dojo.require("esri.renderer");
      dojo.require("esri.dijit.Legend");

      // one global for persistent app variables
      var app = {};

      function init() {
        var ext, basemap, usaUrl;

        esri.config.defaults.io.proxyUrl = "/proxy/";

        app.map = new esri.Map("map", {
          basemap: "oceans",
          center: [-100.626, 36.408],
          zoom: 5,
          slider: false
        });
        dojo.connect(app.map, "onClick", queryCounties);
        dojo.connect(app.map, "onKeyDown", escClosesPopup);

        // set up a layer to show counties as a dynamic map service
        // set visible layers to [2]
        usaUrl = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer";
        app.usaLayer = new esri.layers.ArcGISDynamicMapServiceLayer(usaUrl, {
          "id": "usa",
          "opacity": 0.7
        });
        app.usaLayer.setVisibleLayers([2]);

        // query for the max average household size
        getMaxAvgHH();
        // create a renderer with one class > 2 and < 3 and add counties to the map
        showCounties(dijit.byId("appSlider").get("value"));
        // listen to slider changes and update the counties layer
        dojo.connect(dijit.byId("appSlider"), "onChange", updateCounties);
      }

      function getMaxAvgHH() {
        var countiesUrl, outFields, queryTask, query, statDef;
        // query to get max value
        countiesUrl = "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/2";
        outFields = ["AVE_HH_SZ", "STATE_NAME", "NAME"];
        queryTask = new esri.tasks.QueryTask(countiesUrl);
        query = new esri.tasks.Query();
        query.outFields = outFields;
        statDef = new esri.tasks.StatisticDefinition();
        statDef.statisticType = "max";
        statDef.onStatisticField = "AVE_HH_SZ";
        statDef.outStatisticName = "max_avg_hh_size";

        query.returnGeometry = false;
        query.where = "1=1";
        query.outStatistics = [ statDef ];
        queryTask.execute(query, handleQueryResult, errorHandler);
      }

      function handleQueryResult(results) {
        if ( ! results.hasOwnProperty("features") ||
             results.features.length === 0 ) {
          return; // no features, something went wrong
        }

        var maxSize = results.features[0].attributes.MAX_AVE_HH_SZ;
        console.log("max size: ", maxSize, results.features);
        dojo.byId("maxLabel").innerHTML = dojo.number.format(maxSize, { "places": 2 });
      }

      function showCounties(vals) {
        // create the default renderer for the app
        var outlineColor = new dojo.Color([220, 220, 220, 1]);
        app.symLine = new esri.symbol.SimpleLineSymbol().setColor(outlineColor);
        app.symHighlight = new esri.symbol.SimpleFillSymbol(
          "solid",
          app.symLine,
          new dojo.Color([55, 255, 102, 0.9])
        ); // neon green fill, no outline
        app.symDefault = new esri.symbol.SimpleFillSymbol( // gray, no outline
          "solid",
          app.symLine,
          new dojo.Color(outlineColor)
        );
        app.renderer = new esri.renderer.ClassBreaksRenderer(app.symDefault, "AVE_HH_SZ");
        addClassBreaks(vals);

        // set up the parameters for the dynamic layer
        var optionsArray = [];
        var drawingOptions = new esri.layers.LayerDrawingOptions();
        drawingOptions.renderer = app.renderer;
        optionsArray[2] = drawingOptions;
        app.usaLayer.setLayerDrawingOptions(optionsArray);
        // add the layer to the map
        app.map.addLayer(app.usaLayer);
      }

      function updateCounties(vals) {
        console.log("slider changed", vals, app.renderer.infos[0].minValue, app.renderer.infos[0].maxValue);
        // remove current breaks
        var breakInfo = dojo.map(app.renderer.infos, function(info) {
          return [info.minValue, info.maxValue];
        });
        dojo.forEach(breakInfo, function(info) {
          app.renderer.removeBreak(info[0], info[1]);
        });
        // add the new break
        // app.renderer.addBreak(vals[0], vals[1], app.symHighlight);
        addClassBreaks(vals);
        var optionsArray = [];
        var drawingOptions = new esri.layers.LayerDrawingOptions();
        drawingOptions.renderer = app.renderer;
        optionsArray[2] = drawingOptions;
        app.usaLayer.setLayerDrawingOptions(optionsArray);
        // show the new breaks
        dojo.byId("minBreak").innerHTML = dojo.number.format(vals[0], { "places": 2 });
        dojo.byId("maxBreak").innerHTML = dojo.number.format(vals[1], { "places": 2 });
      }

      function addClassBreaks(vals) {
        if ( vals[0] > 0 ) {
          app.renderer.addBreak(0, vals[0], app.symDefault);
        }
        app.renderer.addBreak(vals[0], vals[1], app.symHighlight);
        if ( vals[1] < 4.40 ) {
          app.renderer.addBreak(vals[1], 4.40, app.symDefault);
        }
      }

      function queryCounties(e) {
        console.log("query counties");
        var mp, pad, queryGeom, q, vals;

        mp = e.mapPoint;
        vals = dijit.byId("appSlider").get("value");
        // save copy of the click event
        app.click = e;
        // build an extent around the click point
        pad = app.map.extent.getWidth() / app.map.width * 3;
        queryGeom = new esri.geometry.Extent(mp.x - pad, mp.y - pad, mp.x + pad, mp.y + pad, app.map.spatialReference);
        q = new esri.tasks.Query();
        q.outSpatialReference = app.map.spatialReference;
        q.returnGeometry = true;
        q.where = "AVE_HH_SZ >= " + vals[0] + " AND AVE_HH_SZ <= " + vals[1];
        q.outFields = ["STATE_NAME", "NAME", "AVE_HH_SZ"];
        q.geometry = queryGeom;
        console.log("done with query...", q.where);

        var qt = new esri.tasks.QueryTask("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/2");
        qt.execute(q, handleCounties);
      }

      function handleCounties(result) {
        // make sure a feature was clicked
        if ( result.features.length === 0 ) {
          app.map.infoWindow.hide();
          return;
        }
        var popupTemplate = new esri.dijit.PopupTemplate({
          title: "{NAME} County",
          fieldInfos: [
            { fieldName: "AVE_HH_SZ", visible: true, label: "Average Household Size: " },
            { fieldName: "STATE_NAME", visible: true, label: "State: " }
          ]
        });
        dojo.forEach(result.features, function(f) {
          f.setInfoTemplate(popupTemplate);
        });
        app.map.infoWindow.setFeatures(result.features);
        app.map.infoWindow.show(app.click.screenPoint, app.map.getInfoWindowAnchor(app.click.screenPoint));
      }

      function escClosesPopup(key) {
        if ( key.keyCode == 27 ) {
          app.map.infoWindow.hide();
        }
      }

      function errorHandler(err) {
        console.log('Oops, error: ', err);
      }

      dojo.ready(init);
    </script>
  </head>

  <body class="tundra">
    <div data-dojo-type="dijit.layout.BorderContainer"
         data-dojo-props="design:'headline',gutters:false"
         style="width: 100%; height: 100%; margin: 0;">
      <div id="map"
           data-dojo-type="dijit.layout.ContentPane"
           data-dojo-props="region:'center'">

        <div id="feedback" class="shadow">
          <h3>Filter Counties by Average Household Size</h3>
          <div id="info">
            <div class="note">
              Note:  This sample requires an ArcGIS Server version 10.1 map service to generate a renderer.
            </div>

            <div id="slider">
              <div id="appSliderLabel">
                Filter On Average Household Size:
              </div>
              <div id="appSlider"
                data-dojo-type="dojox.form.HorizontalRangeSlider"
                data-dojo-props="value:[3,4], minimum:2, maximum:4.4, intermediateChanges:false, showButtons:false">

                
                <ol id="sliderLabels"
                  data-dojo-type="dijit.form.HorizontalRuleLabels"
                  data-dojo-props="container:'bottomDecoration'"
                  style="height:1em;font-size:75%;color:#666;">
                  <li>
                    <span id="minLabel">2.00</span>
                  </li>
                  <li id="maxLabel">
                    <span id="maxLabel"></span>
                  </li>
                </ol>

              </div>
            </div> 

            <div class="note" id="breakInfo">
              Showing Counties with between <span id="minBreak">2</span>
               and <span id="maxBreak">3</span> average household size.
            </div>

          </div>
        </div>
      </div>
    </div>
  </body>
</html>