Measurement and now we have Dojo

Blog Post created by csergent08 Champion on Jan 13, 2015

Since I started this blog, all the widgets have been pretty basic. This one has a little more to it code wise and CSS. Let's start with the simple stuff first, the HTML. The HTML consists of the following:

<!-- Measurement Tool Begin -->
            <div id="titlePane" data-dojo-type="dijit/TitlePane" data-dojo-props="title:' Measurement',open:false">
                <div id="measurementDiv">
                <span style="font-size:smaller;padding:5px 5px;">Press <b>CTRL</b> to enable snapping.</span>
            <!-- Measurement Tool End -->

Now wait a second, there is a little more than just HTML this time. What's all that stuff about dojo? If you don't know what that means already, I'm going to tell you. We have made a few more references to dojo since we added our measurement tool. You will see that in the JavaScript. Let's take a look at the titlePane div. It provides data-dojo-type. What is that. It just telling the dojo parser what type of widget it is. It's a Title pane widget. In dojo widgets are called dijits. Okay, now we know what kind of dijit it is, we know that title panes can be opened and closed. Read more about a title pane here. So what is data-dojo-props? This happens to be widget parameters. In this case there  are two of them. "title" and "open". "title is to display the title which is "Measurement" in this case and "open" tells dojo whether the widget should be opened are closed when the page renders. In this case, our measurement title bar will be closed, meaning we will not see the measurement widget as it is inside of the the "titlePane". And that provides us with all of the HTML that we need for this widget. Next step is to decide how we want it to look.


You have to be careful here. Esri sample usually use claro as their dojo style for their sites. I am fond of soria. If you would like to see the different themes you can use, check it out here. Now remember, we called this a titlePane. You may want to call it something different like titleMeasurePane or something as you may have more than one titlePane to style. For me I'm not worried about it. I also want my measurement widget at the bottom of the screen towards the left instead of covering my map, so you will see that I set the left to 30% and bottome to 0% to make that happen. Last, I don't want my titlePane to take up more window that it has to at any time so I also set my titlePane width to auto. This will make it narrower until we open the measurement tool. I also add background color of whit and a border color of black. Since Esri uses claro, the measurement tool might have been built with that in mind, so performed a CSS override. Here is the CSS to get this done.

/* Measurement tool style begin */
.soria  .dijitTitlePaneTitle {
    background: #fff;
    border: none;
    border-bottom:solid 1px #29201A;
    border-top:solid 1px #29201A;
.soria .dijitTitlePaneTitleHover
.soria .dijitTitlePaneTitleActive
.soria .dijitTitlePaneContentOuter
    border-right: none;
    border-bottom: none;
    border-left: none;
/* Measurement tool style end */


Now we are ready for the measurement widget itself. Two things, you may need a proxy for this tool and you should publish your own geometry service to be used. I won't write the code for geometry service, but rest assured that you can get all of the code from github at the end of this post.


Starting off, I like to group my require statements and you can see where I referenced items that could be taken away if I were not using the measure tool.

// Get references to modules to be used
require(["esri/map",                                // mapSection
         "esri/config",                             // The default values for all JS API configuration options. 
         "esri/Color",  // measurementDiv
         "esri/dijit/HomeButton",                   // homeButton
         "esri/dijit/LocateButton",                 // locateButton
         "esri/dijit/Measurement", // measurementDiv
         "esri/dijit/OverviewMap", // Overview Map
         "esri/dijit/Scalebar",  // Scalebar
         "esri/geometry/Extent", // The minimum and maximum X- and Y- coordinates of a bounding box. Used to set custom extent
         "esri/layers/LayerDrawingOptions", // measurementDiv
         "esri/renderers/SimpleRenderer", // measurementDiv
         "esri/SnappingManager", // measurementDiv    -add snapping capability
         "esri/sniff", // measurementDiv
         "esri/symbols/SimpleFillSymbol", // measurementDiv
         "esri/symbols/SimpleLineSymbol", // measurementDiv
         "esri/tasks/GeometryService",    // Represents a geometry service resource exposed by the ArcGIS Server REST API.

         "dojo/dom",                            // It is used for code like - dom.byId("someNode")
         "dojo/on",                             // This module is used based on an even such as on("click")
         "dojo/parser",                         // The Dojo Parser is an optional module.
         "dojo/domReady!"],    // An AMD loaded plugin that will wait until the DOM has finished loading before returning.

After that, we just add the code for the measurement widget. Don't forget your variables in the function following the require statement. And then we can start up the measurement widget:


// start measurement tool - the current layer we are measuring is the operational layer

             // defining the lines that will be drawn for measurement
             var layerDrawingOptions = [];
             var layerDrawingOption = new LayerDrawingOptions();
             var sfs = new SimpleFillSymbol(
                                    new SimpleLineSymbol("solid", new Color([195, 176, 23]), 2),

             layerDrawingOption.renderer = new SimpleRenderer(sfs);

             // change 1 to the layer index that you want to modify:
             layerDrawingOptions[1] = layerDrawingOption;

             //dojo.keys.copyKey maps to CTRL on windows and Cmd on Mac., but has wrong code for Chrome on Mac
             var snapManager = map.enableSnapping({
                 snapKey: has("mac") ? keys.META : keys.CTRL

             // layer used for measuring tool. Your tool wont' show up without it.
             var layerInfos = [{
                 layer: operationalLayer

             // enables snapping

             // looks for the domID of measurementDiv and starts the measurement tool there
             var measurement = new Measurement({
                 map: map
             }, dom.byId("measurementDiv"));

             // end measurement tool


And there you have it. As usual, you can check out the Esri based sample, the or one of the custom samples, gisWeb or gisMobile.


Next up, an extended version of  Esri sample for the print widget.