Hide Table of Contents
View Geoprocessing - Population zonal statistics sample in sandbox
Geoprocessing - Population zonal statistics

Description

This sample uses geoprocessing to estimate the number of people within a polygon you draw on the map. Click Summarize Population, then hold down the mouse button and drag a polygon outline. When you release the button, the polygon will auto-complete and you'll see how many people are estimated to live within the polygon boundaries.

The population calculation is done through an ArcGIS Server geoprocessing service, which gives access to a model running on the server. In this sample, the model contains one tool, Zonal Statistics as Table. The tool sums the population of each cell within the polygon that you drew.

Depending on the complexity of the polygon, it's possible that your request for information will exceed the 2000 character limit imposed by some web browsers. For this reason, the following lines are included to reference a proxy page:

esriConfig.defaults.io.proxyUrl = "/proxy";
esriConfig.defaults.io.alwaysUseProxy = false;

The proxy page receives the request and then forwards it to the server. When you click the "View the live sample" link, the sample works because there's a proxy page configured on the ESRI sample web server. If you want to run this sample on your own machine, you need to set up a proxy page on your web server.

Notice that the Geoprocessor constructor requires the URL to the geoprocessing service. You can enter this URL in a Web browser (http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/GPServer/PopulationSummary) to see the Services Directory page containing information about the model's parameters.

This is a relatively simple model with just one input parameter, a GPFeatureRecordSetLayer, which you can represent with a FeatureSet in the ArcGIS JavaScript API. This sample uses a draw toolbar to help draw and capture the polygon. Notice that when you click the Summarize Population button, the toolbar is activated and the zoom level slider is hidden so that it won't interfere with the drawing.

<div data-dojo-type="dijit.form.Button" id="drawPoly" onclick="app.toolbar.activate(esri.toolbars.Draw.FREEHAND_POLYGON);app.map.hideZoomSlider();">Summarize Population</div>

It takes several lines of code to get this polygon into the feature set required by the model. First, the polygon starts as geometry captured by the toolbar. Then this geometry is used to create a graphic. The graphic is then added to an array of features, which is designated as the features in the FeatureSet.

The results are returned as an array of ParameterValue objects. In this model, there is only one return parameter, which is a FeatureSet. One of the attributes of the items in the feature set is the sum of the population in the polygon.

This sample uses a Dojo Dialog Dijit to display the result, a more aesthetic alternative to a typical alert box.

Code

<!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>GP Task Population Zonal Stats</title>

    <link rel="stylesheet" href="https://js.arcgis.com/3.21/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="https://js.arcgis.com/3.21/esri/css/esri.css">
    <style>
      html, body, #mapDiv {
        height: 100%;
        margin: 0;
        padding: 0;
        width: 100%;
      }
      #info {
        bottom: 20px;
        color: #444;
        height: auto;
        font-family: arial;
        left: 20px;
        margin: 5px;
        padding: 10px;
        position: absolute;
        text-align: left;
        width: 200px;
        z-index: 40;
      }
    </style>

    <script>var dojoConfig = { parseOnLoad: true };</script>
    <script src="https://js.arcgis.com/3.21/"></script>
    <script>
      var app;

    require(["esri/Color",
      "dojo/string",
      "dijit/registry",

      "esri/config",
      "esri/map",
      "esri/layers/ArcGISDynamicMapServiceLayer",
      "esri/graphic",
      "esri/tasks/Geoprocessor",
      "esri/tasks/FeatureSet",
      "esri/toolbars/draw",
      "esri/symbols/SimpleLineSymbol",
      "esri/symbols/SimpleFillSymbol"
      ],
    function(Color, string, registry, esriConfig, Map, ArcGISDynamicMapServiceLayer, Graphic, Geoprocessor, FeatureSet, Draw, SimpleLineSymbol, SimpleFillSymbol){

      var map, gp, toolbar;

      app = {
        "map": map,
        "toolbar": toolbar
      };

      /*Initialize map, GP & image params*/
        app.map = map = new Map("mapDiv", { 
          basemap: "streets", 
          center: [-87.572, 33.329],
          zoom: 6
        });
        
        map.on("load", initTools);

        var populationMap = new ArcGISDynamicMapServiceLayer("https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer");
        populationMap.setOpacity(0.5);
        map.addLayer(populationMap);

        //identify proxy page to use if the toJson payload to the geoprocessing service is greater than 2000 characters.
        //If this null or not available the gp.execute operation will not work.  Otherwise it will do a http post to the proxy.
        esriConfig.defaults.io.proxyUrl = "/proxy/";
        esriConfig.defaults.io.alwaysUseProxy = false;

      function initTools(evtObj) {
        gp = new Geoprocessor("https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/GPServer/PopulationSummary");
        gp.setOutputSpatialReference({wkid:102100}); 
        gp.on("execute-complete", displayResults);

        app.toolbar = toolbar = new Draw(evtObj.map);
        toolbar.on("draw-end", computeZonalStats);
      }

      function computeZonalStats(evtObj) {
        var geometry = evtObj.geometry;
        /*After user draws shape on map using the draw toolbar compute the zonal*/
        map.showZoomSlider();
        map.graphics.clear();
        
        var symbol = new SimpleFillSymbol("none", new SimpleLineSymbol("dashdot", new Color([255,0,0]), 2), new Color([255,255,0,0.25]));
        var graphic = new Graphic(geometry,symbol);

        map.graphics.add(graphic);
        toolbar.deactivate();

        var features= [];
        features.push(graphic);

        var featureSet = new FeatureSet();
        featureSet.features = features;
        
        var params = { "inputPoly":featureSet };
        gp.execute(params);
      }

      function displayResults(evtObj) {
        var results = evtObj.results;
        var content = string.substitute("<h4>The population in the user defined polygon is ${number:dojo.number.format}.</h4>",{number:results[0].value.features[0].attributes.SUM});

        registry.byId("dialog1").setContent(content);
        registry.byId("dialog1").show();
      }

    });
    </script>
  </head>

  <body class="claro">
    <div id="mapDiv"></div>
    <div id="info" class="esriSimpleSlider">
      <div data-dojo-type="dijit.form.Button" id="drawPoly" onclick="app.toolbar.activate(esri.toolbars.Draw.FREEHAND_POLYGON);app.map.hideZoomSlider();">
        Summarize Population
      </div>
      Click Summarize Population and draw a polygon on the map. A GP task will be called to summarize the population within the polygon.
    </div>

    <div data-dojo-type="dijit.Dialog" id="dialog1" title="Population Summary"></div>

  </body>
</html>