Source: widget/MapWidget.js

/**
 * Widget that renders the map and the Esri widgets on the map
 * @module app/widget/MapWidget
 * @author David Kristiansen <david.kristiansen@nscc.ca>
 * @copyright Nova Scotia Community College 2017
 */

define([
    "dojo/dom",
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/on",
    "dojo/topic",
    "dojo/json",
    "dijit/registry",

    "esri/domUtils",
    "esri/layers/ArcGISDynamicMapServiceLayer",
    "esri/layers/FeatureLayer",
    "esri/map",
    "esri/SpatialReference",
    "esri/geometry/Extent",
    "esri/geometry/Point",
    "esri/dijit/Scalebar",
    "esri/dijit/HomeButton",
    "esri/tasks/QueryTask",
    "esri/tasks/query",

    "esri/graphic",
    "esri/lang",
    "dojo/dom-style",
    "dijit/TooltipDialog",
    "dijit/popup",

    "app/widget/FloodLvlWidget",

    "dojo/text!../Layers.json"
], function (
    dom,
    declare,
    lang,
    on,
    topic,
    JSON,
    registry,

    domUtils,
    ArcGISDynamicMapServiceLayer,
    FeatureLayer,
    Map,
    SpatialReference,
    Extent,
    Point,
    Scalebar,
    HomeButton,
    QueryTask,
    Query,

Graphic, esriLang,
domStyle,
    TooltipDialog, dijitPopup,

    FloodLvlWidget,

    jsonLayers
) {
    return declare([], {
        map: null,
        homeButton: null,
        scalebar: null,
        ovLayer: "//agrgims.cogs.nscc.ca/arcgis/rest/services/mcfm_pro/sa_flood/MapServer/0",
        options: {
            extent: null,
            center: null,
            zoom: null,
            basemap: null
        },
            /** @constructor
             * @param {object} args Object of properties to mixin
             * @param {object} srcRefNode Dom node for the widget to attach to
             **/
        constructor: function (param, srcRefNode) {
                            /** mix in settings and defaults
                 * @mixin args
                 */
            declare.safeMixin(this.options, param);
            /** Dom widget node */
            this.domNode = srcRefNode;
            // properties
            this.extent = this.options.extent || null;
            this.center = this.options.center || null;
            this.zoom = this.options.zoom || 13;
            this.basemap = this.options.basemap || "topo";
        },
        /**
        * Starts the widget after the dom has been constructed.
        * Calls createMap and sets up the map widgets and calls addlayers: scalebar, homebutton and flood level slider
        **/
        startup: function () {
//            console.log("MapWidget::startup");
            this.createMap();

            var floodlvl = new FloodLvlWidget();
            floodlvl.startup();

            this.scalebar = new Scalebar({
                map: this.map,
                // "dual" displays both miles and kilmometers
                // "english" is the default, which displays miles
                // use "metric" for kilometers
                scalebarUnit: "dual",
                //                scalebarStyle: "ruler",
                //                attachTo: "bottom-right"
            });

            this.homeButton = new HomeButton({
                map: this.map
            }, "homebutton");
            this.homeButton.startup();
            this.addLayers();
        },
        /**
        * Creates the map per Esri JSAPI
        * Checks extent and sets it accordingly
        **/
        createMap: function () {
//            console.log("MapWidget::createMap");
            if (this.extent === null) {
                if (this.center === null) {
                    console.error("No center or extent for map. Defaulting to Halifax, NS.");
                    this.map = new Map("mapDiv", {
                        center: [-63.60, 44.65],
                        zoom: this.zoom,
                        basemap: this.basemap
                    });
                } else {
                    this.map = new Map("mapDiv", {
                        center: this.center,
                        zoom: this.zoom,
                        basemap: this.basemap
                    });
                }

            } else {

                this.map = new Map("mapDiv", {
                    extent: new Extent(this.extent),
                    basemap: this.basemap
                });
            }
        },
        /**
        * Parses the JSON files of Layers.json and adds them to the map.
        * Adds the feature layer used as the overview.
        * Sets up map events and popups.
        **/
        addLayers: function () {
//            console.log("MapWidget::addLayers");

            var dialog;
            var map = this.map;
            var homeButton = this.homeButton;
            var overViewMap = new FeatureLayer(this.ovLayer, {
                mode: FeatureLayer.MODE_AUTO,
                outFields: ["said","name","default_stn_id","survey_year"]
            });

            dialog = new TooltipDialog({
                id: "tooltipDialog",
                style: "position: absolute; width: 250px; font: normal normal normal 10pt Helvetica;z-index:100"
            });
            dialog.startup();

            this.map.addLayer(overViewMap);

            //listen for when the onMouseOver event fires on the countiesGraphicsLayer
            //when fired, create a new graphic with the geometry from the event.graphic and add it to the maps graphics layer
            overViewMap.on("mouse-over", openDialog);
            overViewMap.on("mouse-out", closeDialog);
            overViewMap.on("click", function (evt) {
                registry.byId("fsbLCA").set('value', evt.graphic.attributes.said);
                topic.publish("fsb/Zoom", evt.graphic.attributes.said);
            });

            on(map, "update-end", hideLoading);
            on(map, "update-start", showLoading);

            var loading = dom.byId("loadingImg");

            function showLoading() {
                domUtils.show(loading);
            }

            function hideLoading(error) {
                domUtils.hide(loading);
            }

            var oLayers = JSON.parse(jsonLayers);
            console.log(oLayers);
            var aLayers = [];
            for (var i = 0; i < oLayers.layers.length; i++) {
                var temp = new ArcGISDynamicMapServiceLayer(oLayers.layers[i].url, {
                    id: oLayers.layers[i].id,
                    visible: oLayers.layers[i].visible,
                    opacity: oLayers.layers[i].opacity
                });
                var tmpLegend = oLayers.layers[i].legend;
                lang.mixin(temp, {
                    title: oLayers.layers[i].title,
                    legend: tmpLegend
                });
                aLayers.push(temp);
            }
            this.map.addLayers(aLayers);
//            console.log("MapWidget::addLayers done!");

            topic.subscribe("fsb/LCA", lang.hitch(this, function (top, location) {
                var lvl = registry.byId('twlSlider').value;
                var floodLyrDefinition = [];
                floodLyrDefinition[location.said] = "level_cm = " + lvl;
                var floodlayer = map.getLayer("floodlayer");
                floodlayer.setVisibleLayers([location.said], true);
                floodlayer.setLayerDefinitions(floodLyrDefinition);
            }));
            topic.subscribe("floodUpdate/slider", function (val, source) {
                var floodlayer = map.getLayer("floodlayer");
                var locationList = floodlayer.visibleLayers;
                var location = locationList.pop();
                var floodLyrDefinition = [];
                floodLyrDefinition[location] = "level_cm = " + val;
                floodlayer.setVisibleLayers([location], true);
                floodlayer.setLayerDefinitions(floodLyrDefinition);

            });

            topic.subscribe("fsb/Zoom", lang.hitch(this, function (said) {
                showLoading();
                if (overViewMap.loaded) {
                    for (i = 0; i < overViewMap.graphics.length; i++) {
                        var OMSaid = overViewMap.graphics[i].attributes.said;
                        if (overViewMap.graphics[i].attributes.said === said) {
                            gotoStudyArea(overViewMap.graphics[i]);
                            return;
                        }
                    }
                    var queryTask = new QueryTask(this.ovLayer);
                    var query = new Query();
                    query.where = "said=" + said;
                    query.returnGeometry = true;
                    queryTask.execute(query, function (fs) {
                        var geo = fs.features[0];
                        gotoStudyArea(geo);
                    });
                } else {
                    console.error("Not all features are loaded yet.");
                }
            }));

            function openDialog(evt) {
                var t = "Study Area: ${name}</br>Survey Year: ${survey_year}";
                var content = esriLang.substitute(evt.graphic.attributes, t);
                dialog.setContent(content);
                domStyle.set(dialog.domNode, "opacity", 0.85);
                dijitPopup.open({
                    popup: dialog,
                    x: evt.pageX,
                    y: evt.pageY
                });
                map.setMapCursor("pointer");
            }

            function closeDialog(evt) {
                dijitPopup.close(dialog);
                map.setMapCursor("default");
            }

            function gotoStudyArea(evt) {
                var feat;
                if (evt.geometry) {
                    feat = evt.geometry;
                } else if (evt.graphic.geometry) {
                    feat = evt.graphic.geometry;
                } else {
                    console.error("Cannot zoom to exent beacuse geometry is missing",evt);
                    return;
                }
                if (feat.type === 'polygon') {
                    var featExt = feat.getExtent();
                    map.setExtent(featExt);
                } else if (feat.type === 'point') {
                    var saPt = new Point(evt.graphic.attributes.X, evt.graphic.attributes.Y, new SpatialReference({
                        wkid: 3857
                    }));
                    map.centerAndZoom(saPt, 13);
                }
                hideLoading();
            }
        }
    });
});