diff --git a/.brackets.json b/.brackets.json
new file mode 100644
index 0000000..a612e90
--- /dev/null
+++ b/.brackets.json
@@ -0,0 +1,5 @@
+{
+ "jscodehints.detectedExclusions": [
+ "D:/Projects/WebAppBuilder/arcgis-web-appbuilder-1.0beta2/client/stemapp/widgets/solutions-webappbuilder-widgets/ImageMensuration/nls/strings.js"
+ ]
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b0d39b6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,195 @@
+# Defense Template specific ignores
+application/
+data/
+maps/
+scratch/
+log/
+arc.dir
+#*.pyt.xml -- We cannot ignore these files... these are documentation
+*.zip
+*.zip
+*.7z
+*-old.*
+*-old
+*-sav
+*-sav.*
+*Copy.*
+*.log
+*.sav
+*.pyproj
+*.sln
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+#################
+## Visual Studio
+#################
+
+# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
+[Bb]in/
+[Oo]bj/
+
+#################
+## Eclipse
+#################
+
+# General
+.metadata
+bin/
+tmp/
+dist/
+*.tmp
+*.bak
+*.swp
+*~.nib
+
+# Eclipse
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+# mstest test results
+TestResults
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+x64/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.log
+*.vspscc
+*.vssscc
+.builds
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+packages
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+[Tt]est[Rr]esult*
+*.Cache
+ClientBin
+[Ss]tyle[Cc]op.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+############
+## Windows
+############
+
+# Windows image file caches
+Thumbs.db
+
+# Folder config file
+Desktop.ini
+
+*.lock
diff --git a/.jscsrc b/.jscsrc
new file mode 100644
index 0000000..b4d5c01
--- /dev/null
+++ b/.jscsrc
@@ -0,0 +1,26 @@
+{
+ "requireOperatorBeforeLineBreak": true,
+ "maximumLineLength": {
+ "value": 100,
+ "allowComments": true,
+ "allowRegex": true
+ },
+ "validateIndentation": 2,
+ "disallowMultipleLineStrings": true,
+ "disallowMixedSpacesAndTabs": true,
+ "disallowTrailingWhitespace": true,
+ "requireSpaceAfterKeywords": [
+ "return"
+ ],
+ "requireSpaceBeforeBinaryOperators": ["=",
+ "+",
+ "-",
+ "/",
+ "*",
+ "==",
+ "===",
+ "!=",
+ "!=="
+],
+ "requireSpaceAfterBinaryOperators": true
+}
\ No newline at end of file
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..ba37a5c
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,100 @@
+{
+ // JSHint Configuration, esri jsapi
+ // Modified from [jshint web defaults][1].
+ // Differences between the default and our file are noted
+ // Options that are commented out completely are uneccesary or problematic for our codebase
+ // [1] : https://github.com/jshint/jshint/blob/2.x/examples/.jshintrc
+ // See http://jshint.com/docs/ for more details
+
+ "maxerr" : 5000, // {int} Maximum error before stopping ** Get ALL the errors **
+
+ // Enforcing - true = enforce this rule, false = don't enforce this rule
+ "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
+ "camelcase" : true, // true: Identifiers must be in camelCase
+ "curly" : true, // true: Require {} for every new block or scope
+ "freeze" : true, // prevents modification to of native objects. Generally a bad iadea unless you know what you are doing.
+ "eqeqeq" : true, // true: Require triple equals (===) for comparison ** Just use triples with undefined, null, false, 0 and 1 **
+ "es3" : true, // true: Adhere to ECMAScript 3 specification ** Still needed until IE8 support is dropped **
+ "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() ** Still needed until IE8 support is dropped **
+ "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` ** Avoids confusion and minification errors **
+ "latedef" : false, // true: Require variables/functions to be defined before being used
+ "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` ** Coding style enforcement **
+ "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
+ "noempty" : true, // true: Prohibit use of empty blocks
+ "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) ** Coding style enforcement **
+ "plusplus" : false, // true: Prohibit use of `++` & `--`
+ "quotmark" : true, // Quotation mark consistency: ** Use the same style. Single should be used in most cases **
+ // false : do nothing (default)
+ // true : ensure whatever is used is consistent
+ // "single" : require single quotes
+ // "double" : require double quotes
+ "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
+ "unused" : "vars", // true: Require all defined variables be used
+ "strict" : false, // true: Requires all functions run in ES5 Strict Mode ** Dojo style and existing codebase conflicts **
+ "trailing" : false, // true: Prohibit trailing whitespaces
+ "indent" : 2, // {int} Number of spaces to use for indentation
+ //"maxparams" : false, // {int} Max number of formal params allowed per function
+ "maxdepth" : 3, // {int} Max depth of nested blocks (within functions)
+ "maxstatements" : 15, // {int} Max number statements per function
+ //"maxcomplexity" : false, // {int} Max cyclomatic complexity per function
+ "maxlen" : 120, // {int} Max number of characters per line
+
+ // Relaxing - false = continue to enforce this rule, true = don't enforce this rule (relax it)
+ "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
+ "boss" : false, // true: Tolerate assignments where comparisons would be expected
+ "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
+ "eqnull" : true, // true: Tolerate use of `== null`
+ "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
+ "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
+ "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
+ // (ex: `for each`, multiple try/catch, function expression…)
+ "evil" : false, // true: Tolerate use of `eval` and `new Function()`
+ "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
+ "funcscope" : true, // true: Tolerate defining variables inside control statements ** Other variable checks keep use from abusing this **
+ "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
+ "iterator" : false, // true: Tolerate using the `__iterator__` property
+ "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
+ "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
+ "laxcomma" : false, // true: Tolerate comma-first style coding
+ "loopfunc" : true, // true: Tolerate functions being defined in loops ** Almost required in some callback & promise style code **
+ "multistr" : false, // true: Tolerate multi-line strings
+ "proto" : false, // true: Tolerate using the `__proto__` property
+ "scripturl" : true, // true: Tolerate script-targeted URLs ** If this is being used, there is probably a good reason **
+ "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
+ "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
+ "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
+ "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
+ "validthis" : true, // true: Tolerate using this in a non-constructor function ** We don't run in `strict mode` & coding style conflicts **
+
+ // Environments
+ "browser" : true, // Web Browser (window, document, etc)
+ "devel" : true, // Development/debugging (alert, confirm, etc)
+ "couch" : false, // CouchDB
+ "dojo" : false, // Dojo Toolkit ** Don't use global dojo objects. Use AMD style coding **
+ "jquery" : false, // jQuery
+ "mootools" : false, // MooTools
+ "node" : false, // Node.js
+ "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
+ "prototypejs" : false, // Prototype and Scriptaculous
+ "rhino" : false, // Rhino
+ "worker" : false, // Web Workers ** Make a jshint comment when this is `true` **
+ "wsh" : false, // Windows Scripting Host
+ "yui" : false, // Yahoo User Interface
+
+ // Legacy ** According to jshint docs, these options are NOT to be used or relied on. Removing them.
+ //"nomen" : false, // true: Prohibit dangling `_` in variables
+ //"onevar" : false, // true: Allow only one `var` statement per function
+ //"passfail" : false, // true: Stop on first error
+ //"white" : false, // true: Check against strict whitespace and indentation rules
+
+ // Custom Globals - additional predefined global variables
+ // Using both `predef` and `globals` to support tools with older jshint parsers
+ "predef" : [
+ "define",
+ "require"
+ ],
+ "globals" : { // ** `false` = don't allow variable to be redefined locally
+ "define": false,
+ "require": false
+ }
+}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..5d145ec
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,49 @@
+Contributing to the GRG Widget Repository
+=========================================
+
+Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](https://github.com/esri/contributing).
+
+- ***All development work is to be performed in a branch and when ready for release committed to master.***
+- ***Your code is required to adhere to coding rules using [JS Hint](http://www.jshint.com/) and [JSCS](http://jscs.info/). There is a .jshintrc file and .jscs file included in the root folder which enforces these styles.***
+
+Issues
+------
+Feel free to submit issues and enhancement requests.
+
+Contributing
+------------
+Please refer to each project's style guidelines and guidelines for submitting patches and additions. In general, we follow the "fork-and-pull" Git workflow.
+
+ 1. **Fork** the repo on GitHub
+ 2. **Clone** the project to your own machine
+ 3. **Commit** changes to your own branch
+ 4. **Push** your work back up to your fork
+ 5. Submit a **Pull request** so that we can review your changes
+
+NOTE: Be sure to merge the latest from "upstream" before making a pull request!
+
+Copyright and Licensing
+-----------------------
+Most Esri open source projects are licensed under the Apache 2.0 license.
+
+Esri does not require you to assign the copyright of your contributions, you retain the copyright. Esri does require that you make your contributions available under the Apache license in order to be included in the main repo.
+
+If appropriate, include the Apache 2.0 license summary at the top of each file along with the copyright info. If you are adding a new file that you wrote, include your name in the copyright notice in the license summary at the top of the file.
+
+Contributing code written by others
+-----------------------------------
+Please do not contribute code you did not write yourself, unless you are certain you have the legal ability to do so. Also ensure all code contributed can be licensed under the Apache License 2.0.
+
+Copyright 2017 by Esri
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/GRG/Widget.html b/GRG/Widget.html
new file mode 100644
index 0000000..a4d164b
--- /dev/null
+++ b/GRG/Widget.html
@@ -0,0 +1,461 @@
+
+
+
+
+
+
+
+
+
+ ${nls.newGRGFromAreaButtonLabel}
+
+
+
+
+
+
+
+
+
+ ${nls.newGRGBySizeButtonLabel}
+
+
+
+
+
+
+ ${nls.newGRGFromRefSystemButtonLabel}
+
+
+
+
+
+
+
+
+
+
+ ${nls.newGRGFromPointButtonLabel}
+
+
+
+
+
+
+
+
+
+ ${nls.newGRGBySizeButtonLabel}
+
+
+
+
+
+
+ ${nls.newGRGFromRefSystemButtonLabel}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/Widget.js b/GRG/Widget.js
new file mode 100644
index 0000000..f89c4aa
--- /dev/null
+++ b/GRG/Widget.js
@@ -0,0 +1,2034 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'jimu/BaseWidget',
+ 'dojo/_base/array',
+ 'dojo/_base/lang',
+ 'dojo/dom-class',
+ 'dojo/dom-attr',
+ 'dojo/dom-construct',
+ 'dojo/dom-style',
+ 'dojo/on',
+ 'dojo/keys',
+ 'dojo/query',
+ 'dojo/string',
+ 'dojo/topic',
+ 'dojo/_base/html',
+
+ 'dijit/_WidgetBase',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dijit/registry',
+ 'dijit/TooltipDialog',
+ 'dijit/popup',
+ 'dijit/Menu',
+ 'dijit/MenuItem',
+ 'dijit/MenuSeparator',
+
+ 'jimu/dijit/Message',
+ 'jimu/dijit/LoadingIndicator',
+ 'jimu/LayerInfos/LayerInfos',
+ 'jimu/utils',
+
+ 'esri/IdentityManager',
+ 'esri/arcgis/OAuthInfo',
+ 'esri/arcgis/Portal',
+ 'esri/config',
+ 'esri/Color',
+ 'esri/dijit/util/busyIndicator',
+ 'esri/graphic',
+ 'esri/geometry/geometryEngine',
+ 'esri/geometry/Extent',
+ 'esri/geometry/Point',
+ 'esri/geometry/Polyline',
+ 'esri/geometry/webMercatorUtils',
+ 'esri/layers/FeatureLayer',
+ 'esri/layers/GraphicsLayer',
+ 'esri/layers/LabelClass',
+ 'esri/SpatialReference',
+ 'esri/symbols/Font',
+ 'esri/symbols/SimpleMarkerSymbol',
+ 'esri/symbols/SimpleFillSymbol',
+ 'esri/symbols/TextSymbol',
+ 'esri/toolbars/draw',
+ 'esri/toolbars/edit',
+ 'esri/renderers/SimpleRenderer',
+ 'esri/tasks/query',
+ 'esri/request',
+
+ './js/GridSettings',
+ './js/CoordinateInput',
+ './js/drawGRG',
+ './js/DrawFeedBack',
+ './js/EditOutputCoordinate',
+ './js/geometry-utils',
+ './js/geometryUtils',
+ './js/mgrs-utils',
+ './js/mgrs',
+ 'dijit/form/NumberTextBox',
+ 'dijit/form/RadioButton',
+ 'dijit/form/NumberSpinner',
+],
+ function (
+ declare,
+ BaseWidget,
+ array,
+ lang,
+ domClass,
+ domAttr,
+ domConstruct,
+ domStyle,
+ on,
+ keys,
+ query,
+ dojoString,
+ topic,
+ html,
+ dijitWidgetBase,
+ dijitWidgetsInTemplate,
+ dijitRegistry,
+ dijitTooltipDialog,
+ dijitPopup,
+ Menu,
+ MenuItem,
+ MenuSeparator,
+ Message,
+ LoadingIndicator,
+ jimuLayerInfos,
+ utils,
+ esriId,
+ esriOAuthInfo,
+ esriPortal,
+ esriConfig,
+ Color,
+ busyIndicator,
+ Graphic,
+ GeometryEngine,
+ Extent,
+ Point,
+ Polyline,
+ WebMercatorUtils,
+ FeatureLayer,
+ GraphicsLayer,
+ LabelClass,
+ SpatialReference,
+ Font,
+ SimpleMarkerSymbol,
+ SimpleFillSymbol,
+ TextSymbol,
+ Draw,
+ Edit,
+ SimpleRenderer,
+ Query,
+ esriRequest,
+ GridSettings,
+ coordInput,
+ drawGRG,
+ drawFeedBackPoint,
+ editOutputCoordinate,
+ gridGeomUtils,
+ geometryUtils,
+ mgrsUtils,
+ mgrs
+ ) {
+ return declare([BaseWidget, dijitWidgetBase, dijitWidgetsInTemplate], {
+ baseClass: 'jimu-widget-GRGDrafter',
+ _lastOpenPanel: "mainPage", //Flag to hold last open panel, default will be main page
+ _currentOpenPanel: "mainPage", //Flag to hold last open panel, default will be main page
+ _gridSettingsInstance: null, //Object to hold Grid Settings instance
+ _cellShape: "default", //Current selected grid cell shape
+ _labelStartPosition: "lowerLeft", //Current selected label start position
+ _cellUnits: "meters", //Current selected cell units
+ _labelType: "alphaNumeric", //Current selected label type
+ _labelDirection: "horizontal", //Current selected label direction
+ _gridOrigin: "center", //Current selected grid origin
+ _referenceSystem: 'MGRS', //Current selected reference system
+ _showLabels: true, //flag to hold whether labels should be shown
+ _GRGAreaFillSymbol: null, //Fill symbol used for GRG cells
+ _cellTextSymbol: null, //Text symbol used for GRG labeling
+ angle: 0, //angle of GRG
+ featureLayerInfo: null,
+ centerPoint: [], //Current center point of the GRG extent
+ geodesicGrid: true, //Flag for if the GRG is to be created geodesically
+
+ postMixInProperties: function () {
+ //mixin default nls with widget nls
+ this.nls.common = {};
+ lang.mixin(this.nls.common, window.jimuNls.common);
+ },
+
+ constructor: function (args) {
+ declare.safeMixin(this, args);
+ },
+
+ postCreate: function () {
+ //modify String's prototype so we can format a string using .format
+ if (!String.prototype.format) {
+ String.prototype.format = function() {
+ var args = arguments;
+ return this.replace(/{(\d+)}/g, function(match, number) {
+ return typeof args[number] != 'undefined'
+ ? args[number]
+ : match
+ ;
+ });
+ };
+ }
+
+ this.inherited(arguments);
+
+ //set up the symbology used for the interactive polygon draw tools
+ this.extentAreaFillSymbol = {
+ type: 'esriSFS',
+ style: 'esriSFSSolid',
+ color: [155,155,155,0],
+ outline: {
+ color: [0, 0, 255, 255],
+ width: 1.25,
+ type: 'esriSLS',
+ style: 'esriSLSSolid'
+ }
+ };
+
+ //set up the symbology used for the interactive point draw tools
+ this.pointSymbol = {
+ 'color': [255, 0, 0, 255],
+ 'size': 8,
+ 'type': 'esriSMS',
+ 'style': 'esriSMSCircle',
+ 'outline': {
+ 'color': [255, 0, 0, 255],
+ 'width': 1,
+ 'type': 'esriSLS',
+ 'style': 'esriSLSSolid'
+ }
+ };
+
+ //create graphics layer for grid extent and add to map
+ this._graphicsLayerGRGExtent = new GraphicsLayer({id: "graphicsLayerGRGExtent"});
+
+ //set up symbology for polygon input
+ this._extentSym = new SimpleFillSymbol(this.extentAreaFillSymbol);
+
+ //set up symbology for point input
+ this._ptSym = new SimpleMarkerSymbol(this.pointSymbol);
+
+ //create a feature collection for the drawn GRG to populate
+ var featureCollection = {
+ "layerDefinition": {
+ "geometryType": "esriGeometryPolygon",
+ "objectIdField": "ObjectID",
+ "fields": [{
+ "name": "ObjectID",
+ "alias": "ObjectID",
+ "type": "esriFieldTypeOID"
+ }, {
+ "name": "grid",
+ "alias": "grid",
+ "type": "esriFieldTypeString"
+ }],
+ "drawingInfo": {
+ "renderer": {
+ "type": "simple",
+ "symbol": this.gridSymbol
+ },
+ "transparency": 0,
+ "labelingInfo": [{
+ "labelExpression": "[grid]",
+ "labelExpressionInfo": {"value": "{grid}"},
+ "format": null,
+ "fieldInfos": null,
+ "useCodedValues": false,
+ "maxScale": 0,
+ "minScale": 0,
+ "where": null,
+ "sizeInfo": null,
+ "labelPlacement": "esriServerPolygonPlacementAlwaysHorizontal",
+ "symbol": this._cellTextSymbol
+ }]
+ },
+ "extent": {
+ "xmin":-18746028.312877923,
+ "ymin":-6027547.894280539,
+ "xmax":18824299.82984192,
+ "ymax":12561937.384669386,
+ "spatialReference":{
+ "wkid":102100
+ }
+ },
+ }
+ };
+
+ //create a the GRG feature layer
+ this.GRGArea = new FeatureLayer(featureCollection,{
+ id: "Gridded-Reference-Graphic",
+ outFields: ["*"],
+ showLabels: true
+ });
+
+ //add the GRG feature layer and the GRG extent graphics layer to the map
+ this.map.addLayers([this.GRGArea,this._graphicsLayerGRGExtent]);
+
+ //set up coordinate input dijit for GRG Point by Size
+ this.grgPointBySizeCoordTool = new coordInput({nls: this.nls, appConfig: this.appConfig}, this.newGRGPointBySizeOriginCoords);
+ this.grgPointBySizeCoordTool.inputCoordinate.formatType = 'DD';
+ this.grgPointBySizeCoordinateFormat = new dijitTooltipDialog({
+ content: new editOutputCoordinate({nls: this.nls}),
+ style: 'width: 400px'
+ });
+
+ //we need an extra class added the the coordinate format node for the Dart theme
+ if(this.appConfig.theme.name === 'DartTheme')
+ {
+ domClass.add(this.grgPointBySizeCoordinateFormat.domNode, 'dartThemeClaroDijitTooltipContainerOverride');
+ }
+
+ //set up coordinate input dijit for GRG Point by Ref System
+ this.grgPointByRefSystemCoordTool = new coordInput({nls: this.nls, appConfig: this.appConfig}, this.newGRGPointByRefSystemOriginCoords);
+ this.grgPointByRefSystemCoordTool.inputCoordinate.formatType = 'DD';
+ this.grgPointByRefSystemCoordinateFormat = new dijitTooltipDialog({
+ content: new editOutputCoordinate({nls: this.nls}),
+ style: 'width: 400px'
+ });
+
+ //we need an extra class added the the coordinate format node for the Dart theme
+ if(this.appConfig.theme.name === 'DartTheme')
+ {
+ domClass.add(this.grgPointByRefSystemCoordinateFormat.domNode, 'dartThemeClaroDijitTooltipContainerOverride');
+ }
+
+ // add toolbar for drawing GRG Area by Extent
+ this.dt_AreaBySize = new Draw(this.map);
+
+ // add extended toolbar for drawing GRG Point by Size
+ this.dt_PointBySize = new drawFeedBackPoint(this.map,this.grgPointBySizeCoordTool.inputCoordinate.util);
+
+ // add extended toolbar for drawing GRG Point by Reference System
+ this.dt_PointByRefSystem = new drawFeedBackPoint(this.map,this.grgPointByRefSystemCoordTool.inputCoordinate.util);
+
+ // add toolbar for drawing GRG MGRS
+ this.dt_AreaByRefSystem = new Draw(this.map);
+
+ // add edit toolbar that will be used for rotating grid
+ this.editToolbar = new Edit(this.map,{uniformScaling:true,allowAddVertices:true,allowDeleteVertices:true});
+
+ this._initLoading();
+
+ //set up all the handlers for the different click events
+ this._handleClickEvents();
+
+ this._createGridSettings();
+ },
+
+ startup: function () {
+ this.inherited(arguments);
+ this.busyIndicator = busyIndicator.create({target: this.domNode.parentNode.parentNode.parentNode, backgroundOpacity: 0});
+ this._setTheme();
+ },
+
+ /**
+ * Performs activities like resizing widget components, connect map click etc on widget open
+ * @memberOf widgets/GRG/Widget
+ */
+ onOpen: function () {
+ console.log('widget opened');
+ },
+
+ /**
+ * Performs activities like disconnect map handlers, close popup etc on widget close
+ * @memberOf widgets/GRG/Widget
+ */
+ onClose: function () {
+ console.log('widget closed');
+ },
+
+ /**
+ * This function used for loading indicator
+ * @memberOf widgets/GRG/Widget
+ */
+ _initLoading: function () {
+ this.loading = new LoadingIndicator({hidden: true});
+ this.loading.placeAt(this.domNode);
+ this.loading.startup();
+ },
+
+ /**
+ * Handle click events for different controls
+ * @memberOf widgets/GRG/Widget
+ **/
+ _handleClickEvents: function () {
+ /**
+ * Main menu panel buttons
+ **/
+ //handle new GRG Area button click
+ this.own(on(this.newGRGAreaButton, "click", lang.hitch(this, function () {
+ if(domClass.contains(this.newGRGAreaButton,'GRGDrafterLabelSettingsDownButton')) {
+ //in closed state - so open and change arrow to up
+ html.removeClass(this.fromAreaContainer, 'controlGroupHidden');
+ html.removeClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsDownButton');
+ html.addClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsUpButton');
+ //close grg by point dropdown if open
+ html.addClass(this.fromPointContainer, 'controlGroupHidden');
+ html.removeClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsUpButton');
+ html.addClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsDownButton');
+ } else {
+ //in open state - so close and change arrow to down
+ html.addClass(this.fromAreaContainer, 'controlGroupHidden');
+ html.addClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsUpButton');
+ }
+ })));
+
+ //handle new GRG Point button click
+ this.own(on(this.newGRGPointButton, "click", lang.hitch(this, function () {
+ if(domClass.contains(this.newGRGPointButton,'GRGDrafterLabelSettingsDownButton')) {
+ //in closed state - so open and change arrow to up
+ html.removeClass(this.fromPointContainer, 'controlGroupHidden');
+ html.removeClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsDownButton');
+ html.addClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsUpButton');
+ //close grg by area dropdown if open
+ html.addClass(this.fromAreaContainer, 'controlGroupHidden');
+ html.removeClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsUpButton');
+ html.addClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsDownButton');
+ } else {
+ //in open state - so close and change arrow to down
+ html.addClass(this.fromPointContainer, 'controlGroupHidden');
+ html.addClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsUpButton');
+ }
+ })));
+
+ //Handle click event new GRG by size button
+ this.own(on(this.newAreaGRGBySizeButton, 'click', lang.hitch(this, function () {
+ this._showPanel("grgAreaBySize");
+ })));
+
+ //Handle click event new GRG by reference system button
+ this.own(on(this.newAreaGRGFromRefSystemButton, 'click', lang.hitch(this, function () {
+ this._showPanel("grgAreaByRefSystem");
+ })));
+
+ //Handle click event new GRG from non standard grid button
+ // not implemented yet
+ //this.own(on(this.newAreaGRGFromNonStandardButton, 'click', lang.hitch(this, function () {
+ //this._showPanel("grgAreaFromNonStandard");
+ //})));
+
+ //Handle click event new GRG by size button
+ this.own(on(this.newPointGRGBySizeButton, 'click', lang.hitch(this, function () {
+ this._showPanel("grgPointBySize");
+ })));
+
+ //Handle click event new GRG by reference system button
+ this.own(on(this.newPointGRGFromRefSystemButton, 'click', lang.hitch(this, function () {
+ this._showPanel("grgPointByRefSystem");
+ })));
+
+ /**
+ * GRG from Area by Size panel
+ **/
+ //Handle click event of back button
+ this.own(on(this.grgAreaBySizePanelBackButton, 'click', lang.hitch(this, function () {
+ this._resetOnBackToMainPage();
+ })));
+
+ //handle Grid Settings button
+ if(!this.config.grg.lockSettings) {
+ this.own(on(this.grgAreaBySizeSettingsButton, "click", lang.hitch(this, function () {
+ this._updateSettingsPage(this._currentOpenPanel);
+ this._showPanel("settingsPage");
+ })));
+ } else {
+ this.grgAreaBySizeSettingsButton.title = this.nls.lockSettings;
+ //html.addClass(this.grgAreaBySizeSettingsButton, 'controlGroupHidden');
+ }
+
+ //Handle click event of Add GRG Area by Polygon button
+ this.own(on(this.grgAreaBySizeDrawPolygonIcon, 'click', lang.hitch(this,
+ this._grgAreaBySizeDrawPolygonIconClicked)));
+
+ //Handle click event of Add GRG Area by Extent button
+ this.own(on(this.grgAreaBySizeDrawExtentIcon, 'click', lang.hitch(this,
+ this._grgAreaBySizeDrawExtentIconClicked)));
+
+ //Handle completion of GRG area drawing
+ this.own(on(this.dt_AreaBySize, 'draw-complete', lang.hitch(this,
+ this._dt_AreaBySizeComplete)));
+
+ //Handle click event of create GRG Area button
+ this.own(on(this.grgAreaBySizeCreateGRGButton, 'click', lang.hitch(this,
+ this._grgAreaBySizeCreateGRGButtonClicked)));
+
+ //Handle click event of clear GRG Area button
+ this.own(on(this.grgAreaBySizeClearGRGButton, 'click', lang.hitch(this, function () {
+ this._clearLayers(true);
+ })));
+
+ //Handle click event of number of row / columns checkbox
+ this.own(on(this.setNumberRowsColumns, 'click', lang.hitch(this,
+ this._setNumberRowsColumnsCheckBoxChanged)));
+
+ //Handle number of horizontal cells change
+ this.own(on(this.cellHorizontal, 'blur', lang.hitch(this, function () {
+ if(this.cellHorizontal.isValid()) {
+ if(this._graphicsLayerGRGExtent.graphics[0]) {
+ if(this.angle === 0) {
+ this._calculateCellWidthAndHeight(gridGeomUtils.extentToPolygon(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent()));
+ } else {
+ this._calculateCellWidthAndHeight(this._graphicsLayerGRGExtent.graphics[0].geometry);
+ }
+ }
+ }
+ })));
+
+ //Handle number of vertical cells change
+ this.own(on(this.cellVertical, 'blur', lang.hitch(this, function () {
+ if(this.cellVertical.isValid()) {
+ if(this._graphicsLayerGRGExtent.graphics[0]) {
+ if(this.angle === 0) {
+ this._calculateCellWidthAndHeight(gridGeomUtils.extentToPolygon(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent()));
+ } else {
+ this._calculateCellWidthAndHeight(this._graphicsLayerGRGExtent.graphics[0].geometry);
+ }
+ }
+ }
+ })));
+
+ //Handle rotation number change
+ this.own(on(this.grgAreaBySizeRotation, 'keyup', lang.hitch(this, function () {
+ //set time out needed to give chance for the the input validation to occur
+ setTimeout(lang.hitch(this, function(){
+ this.grgAreaBySizeRotation.setValue(parseFloat(this.grgAreaBySizeRotation.displayedValue));
+ if (this.grgAreaBySizeRotation.isValid() && !isNaN(this.grgAreaBySizeRotation.value) && this._graphicsLayerGRGExtent.graphics[0]){
+ var rotateBy = this.grgAreaBySizeRotation.getValue() - this.angle;
+ var geom = GeometryEngine.rotate(this._graphicsLayerGRGExtent.graphics[0].geometry, rotateBy*-1);
+ this._graphicsLayerGRGExtent.clear();
+ var graphic = new Graphic(geom, this._extentSym);
+ this._graphicsLayerGRGExtent.add(graphic);
+ this.angle = this.grgAreaBySizeRotation.getValue();
+ this.editToolbar.deactivate();
+ }}), 1000);
+ })));
+
+ /**
+ * GRG from Area by Reference System panel
+ **/
+ //Handle click event of back button
+ this.own(on(this.grgAreaByRefSystemPanelBackButton, 'click', lang.hitch(this, function () {
+ this._resetOnBackToMainPage();
+ })));
+
+ //handle Grid Settings button
+ if(!this.config.grg.lockSettings) {
+ this.own(on(this.grgAreaByRefSystemSettingsButton, "click", lang.hitch(this, function () {
+ this._updateSettingsPage(this._currentOpenPanel);
+ this._showPanel("settingsPage");
+ })));
+ } else {
+ this.grgAreaByRefSystemSettingsButton.title = this.nls.lockSettings;
+ //html.addClass(this.grgAreaByRefSystemSettingsButton, 'controlGroupHidden');
+ }
+
+ //Handle click event of draw extent icon
+ this.own(on(this.grgAreaByRefSystemDrawIcon, 'click', lang.hitch(this,
+ this._grgAreaByRefSystemDrawIconClicked)));
+
+ //Handle click event of create GRG button
+ this.own(on(this.grgAreaByRefSystemCreateGRGButton, 'click', lang.hitch(this,
+ this._grgAreaByRefSystemCreateGRGButtonClicked)));
+
+ //Handle click event of clear GRG button
+ this.own(on(this.grgAreaByRefSystemClearGRGButton, 'click', lang.hitch(this, function () {
+ this._clearLayers(true);
+ })));
+
+ //Handle completion of extent drawing
+ this.own(on(this.dt_AreaByRefSystem, 'draw-complete', lang.hitch(this,
+ this._dt_AreaByRefSystemComplete)));
+
+ //Handle grid size dropdown change
+ this.own(on(this.grgAreaByRefSystemGridSize, 'change', lang.hitch(this, function () {
+ switch(this.grgAreaByRefSystemGridSize.getValue()){
+ case 'UTM':
+ this.grgAreaByRefLabelFormat.value = 'Z';
+ break;
+ case '100000':
+ this.grgAreaByRefLabelFormat.value = 'ZS';
+ break;
+ default:
+ this.grgAreaByRefLabelFormat.value = 'ZSXY';
+ break;
+ }
+ })));
+
+ /**
+ * GRG from Area by Non Standard Grid panel
+ NOT IMPLEMENTED YET
+
+ //Handle click event of back button
+ this.own(on(this.grgAreaByNonStandardPanelBackButton, 'click', lang.hitch(this, function () {
+ this._resetOnBackToMainPage();
+ })));
+
+ //handle Grid Settings button
+ if(!this.config.grg.lockSettings) {
+ //handle Grid Settings button
+ this.own(on(this.grgAreaByNonStandardSettingsButton, "click", lang.hitch(this, function () {
+ this._updateSettingsPage(this._currentOpenPanel);
+ this._showPanel("settingsPage");
+ })));
+ } else {
+ this.grgAreaByNonStandardSettingsButton.title = this.nls.lockSettings;
+ //html.addClass(this.grgAreaByNonStandardSettingsButton, 'controlGroupHidden');
+ }
+ **/
+
+ /**
+ * GRG from Point by Size panel
+ **/
+ //Handle click event of back button
+ this.own(on(this.grgPointBySizePanelBackButton, 'click', lang.hitch(this, function () {
+ this._resetOnBackToMainPage();
+ })));
+
+ //handle Grid Settings button
+ if(!this.config.grg.lockSettings) {
+ //handle Grid Settings button
+ this.own(on(this.grgPointBySizeSettingsButton, "click", lang.hitch(this, function () {
+ this._updateSettingsPage(this._currentOpenPanel);
+ this._showPanel("settingsPage");
+ })));
+ } else {
+ this.grgPointBySizeSettingsButton.title = this.nls.lockSettings;
+ //html.addClass(this.grgPointBySizeSettingsButton, 'controlGroupHidden');
+ }
+
+ //Handle click event of create GRG point button
+ this.own(on(this.grgPointBySizeCreateGRGButton, 'click', lang.hitch(this,
+ this._grgPointBySizeCreateGRGButtonClicked)));
+
+ //Handle click event of clear GRG Point button
+ this.own(on(this.grgPointBySizeClearGRGButton, 'click', lang.hitch(this, function () {
+ this._clearLayers(true);
+ })));
+
+ //Handle click event of Add GRG Point draw button
+ this.own(on(this.grgPointBySizeAddPointBtn, 'click', lang.hitch(this,
+ this._grgPointBySizeDrawButtonClicked)));
+
+
+ //Handle completion of GRG point drawing
+ this.own(on(this.dt_PointBySize, 'draw-complete', lang.hitch(this,
+ this._dt_PointBySizeComplete)));
+
+ //Handle change in coord input
+ this.own(this.grgPointBySizeCoordTool.inputCoordinate.watch('outputString', lang.hitch(this,
+ function (r, ov, nv) {
+ if(!this.grgPointBySizeCoordTool.manualInput){
+ this.grgPointBySizeCoordTool.set('value', nv);
+ }
+ }
+ )));
+
+ //Handle change in start point and update coord input
+ this.own(this.dt_PointBySize.watch('startPoint', lang.hitch(this,
+ function (r, ov, nv) {
+ this.grgPointBySizeCoordTool.inputCoordinate.set('coordinateEsriGeometry', nv);
+ this.dt_PointBySize.addStartGraphic(nv, this._ptSym, this._graphicsLayerGRGExtent);
+ }
+ )));
+
+ //Handle key up events in coord input
+ this.own(on(this.grgPointBySizeCoordTool, 'keyup', lang.hitch(this,
+ this._grgPointBySizeCoordToolKeyWasPressed)));
+
+ //Handle click event on coord format button
+ this.own(on(this.grgPointBySizeCoordFormatButton, 'click', lang.hitch(this,
+ this._grgPointBySizeCoordFormatButtonClicked)));
+
+ //Handle click event on apply button of the coord format popup
+ this.own(on(this.grgPointBySizeCoordinateFormat.content.applyButton, 'click', lang.hitch(this,
+ this._grgPointBySizeCoordFormatPopupApplyButtonClicked)));
+
+ //Handle click event on cancel button of the coord format popup
+ this.own(on(this.grgPointBySizeCoordinateFormat.content.cancelButton, 'click', lang.hitch(this,
+ function () {
+ dijitPopup.close(this.grgPointBySizeCoordinateFormat);
+ }
+ )));
+
+ /**
+ * GRG from Point by Reference System panel
+ **/
+ //Handle click event of back button
+ this.own(on(this.grgPointByRefSystemPanelBackButton, 'click', lang.hitch(this, function () {
+ this._resetOnBackToMainPage();
+ })));
+
+ //handle Grid Settings button
+ if(!this.config.grg.lockSettings) {
+ //handle Grid Settings button
+ this.own(on(this.grgPointByRefSystemSettingsButton, "click", lang.hitch(this, function () {
+ this._updateSettingsPage(this._currentOpenPanel);
+ this._showPanel("settingsPage");
+ })));
+ } else {
+ this.grgPointByRefSystemSettingsButton.title = this.nls.lockSettings;
+ //html.addClass(this.grgPointByRefSystemSettingsButton, 'controlGroupHidden');
+ }
+
+ //Handle click event of create GRG point button
+ this.own(on(this.grgPointByRefSystemCreateGRGButton, 'click', lang.hitch(this,
+ this._grgPointByRefSystemCreateGRGButtonClicked)));
+
+ //Handle click event of clear GRG Point button
+ this.own(on(this.grgPointByRefSystemClearGRGButton, 'click', lang.hitch(this, function () {
+ this._clearLayers(true);
+ })));
+
+ //Handle click event of Add GRG Point draw button
+ this.own(on(this.grgPointByRefSystemAddPointBtn, 'click', lang.hitch(this,
+ this._grgPointByRefSystemDrawButtonClicked)));
+
+ //Handle completion of GRG point drawing
+ this.own(on(this.dt_PointByRefSystem, 'draw-complete', lang.hitch(this,
+ this._dt_PointByRefSystemComplete)));
+
+ //Handle change in coord input
+ this.own(this.grgPointByRefSystemCoordTool.inputCoordinate.watch('outputString', lang.hitch(this,
+ function (r, ov, nv) {
+ if(!this.grgPointByRefSystemCoordTool.manualInput){
+ this.grgPointByRefSystemCoordTool.set('value', nv);
+ }
+ }
+ )));
+
+ //Handle change in start point and update coord input
+ this.own(this.dt_PointByRefSystem.watch('startPoint', lang.hitch(this,
+ function (r, ov, nv) {
+ this.grgPointByRefSystemCoordTool.inputCoordinate.set('coordinateEsriGeometry', nv);
+ this.dt_PointByRefSystem.addStartGraphic(nv, this._ptSym, this._graphicsLayerGRGExtent);
+ }
+ )));
+
+ //Handle key up events in coord input
+ this.own(on(this.grgPointByRefSystemCoordTool, 'keyup', lang.hitch(this,
+ this._grgPointByRefSystemCoordToolKeyWasPressed)));
+
+ //Handle click event on coord format button
+ this.own(on(this.grgPointByRefSystemCoordFormatButton, 'click', lang.hitch(this,
+ this._grgPointByRefSystemCoordFormatButtonClicked)));
+
+ //Handle click event on apply button of the coord format popup
+ this.own(on(this.grgPointByRefSystemCoordinateFormat.content.applyButton, 'click', lang.hitch(this,
+ this._grgPointByRefSystemCoordFormatPopupApplyButtonClicked)));
+
+ //Handle click event on cancel button of the coord format popup
+ this.own(on(this.grgPointByRefSystemCoordinateFormat.content.cancelButton, 'click', lang.hitch(this,
+ function () {
+ dijitPopup.close(this.grgPointByRefSystemCoordinateFormat);
+ }
+ )));
+
+ //Handle grid size dropdown change
+ this.own(on(this.grgPointByRefSystemGridSize, 'change', lang.hitch(this, function () {
+ switch(this.grgPointByRefSystemGridSize.getValue()){
+ case 'UTM':
+ this.grgPointByRefLabelFormat.value = 'Z';
+ break;
+ case '100000':
+ this.grgPointByRefLabelFormat.value = 'ZS';
+ break;
+ default:
+ this.grgPointByRefLabelFormat.value = 'ZSXY';
+ break;
+ }
+ })));
+
+ /**
+ * Settings panel
+ **/
+ //Handle click event of Grid settings back button
+ this.own(on(this.gridSettingsPanelBackButton, "click", lang.hitch(this, function () {
+ this._gridSettingsInstance.onClose();
+ this._showPanel(this._lastOpenPanel);
+ })));
+
+ /**
+ * Publish panel
+ **/
+ //Handle click event of Grid settings back button
+ this.own(on(this.publishPanelBackButton, "click", lang.hitch(this, function () {
+ //remove any messages
+ this.publishMessage.innerHTML = '';
+ //clear layer name
+ this.addGRGNameArea.setValue('');
+ this._graphicsLayerGRGExtent.show();
+ this._showPanel(this._lastOpenPanel);
+ })));
+
+ //Handle click event of publish GRG to portal button
+ this.own(on(this.grgAreaBySizePublishGRGButton, 'click', lang.hitch(this, function () {
+ if(this.addGRGNameArea.isValid()) {
+ this.publishMessage.innerHTML = '';
+ this._initSaveToPortal(this.addGRGNameArea.value)
+ } else {
+ // Invalid entry
+ this.publishMessage.innerHTML = this.nls.missingLayerNameMessage;
+ }
+ })));
+
+ //Handle click event of show labels toggle button
+ this.own(on(this.settingsShowLabelsToggle, 'click', lang.hitch(this, function () {
+ var featureLayerInfo = jimuLayerInfos.getInstanceSync().getLayerInfoById("Gridded-Reference-Graphic");
+ this._showLabels = this.settingsShowLabelsToggle.checked;
+ if(this.settingsShowLabelsToggle.checked) {
+ featureLayerInfo.showLabels();
+ } else {
+ featureLayerInfo.hideLabels();
+ }
+ })));
+
+ /**
+ * Toolbar events
+ **/
+ //Handle graphic moved
+ this.own(on(this.editToolbar, "graphic-move-stop", lang.hitch(this,function(evt){
+ this.centerPoint = evt.graphic.geometry.getCentroid();
+ })));
+
+ //Handle graphic rotated
+ this.own(on(this.editToolbar, "rotate-stop", lang.hitch(this,function(evt){
+ this.angle = this.angle + parseFloat(evt.info.angle.toFixed(1));
+ this.grgAreaBySizeRotation.setValue(this.angle);
+ })));
+
+ //Handle graphic vertices changed
+ this.own(on(this.editToolbar, "vertex-move-stop", lang.hitch(this,function(evt){
+ this.centerPoint = evt.graphic.geometry.getCentroid();
+ this._calculateCellWidthAndHeight(gridGeomUtils.extentToPolygon(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent()));
+ })));
+
+ //Handle graphic scaled
+ this.own(on(this.editToolbar, "scale-stop", lang.hitch(this,function(evt){
+ this.centerPoint = evt.graphic.geometry.getCentroid();
+ this._calculateCellWidthAndHeight(evt.graphic.geometry);
+ })));
+ },
+
+ /**
+ * Update the settings panel depending on which other panel the
+ * settings are entered from
+ * @memberOf widgets/GRG/Widget
+ **/
+ _updateSettingsPage: function (panelName) {
+ //reset the grid settings to show all
+ html.removeClass(this._gridSettingsInstance.gridShapeContainer, 'controlGroupHidden');
+ html.removeClass(this._gridSettingsInstance.gridUnitsContainer, 'controlGroupHidden');
+ html.removeClass(this._gridSettingsInstance.labelStyleContainer, 'controlGroupHidden');
+ html.removeClass(this._gridSettingsInstance.labelStartPositionContainer, 'controlGroupHidden');
+ html.removeClass(this._gridSettingsInstance.labelDirectionContainer, 'controlGroupHidden');
+
+ //hide the grid origin and reference system settings (these are not common to all settings)
+ html.addClass(this._gridSettingsInstance.gridOriginContainer, 'controlGroupHidden');
+ html.addClass(this._gridSettingsInstance.gridRefSystemContainer, 'controlGroupHidden');
+
+ switch (panelName) {
+ case "grgAreaBySize":
+ break;
+ case "grgAreaFromNonStandard":
+ break;
+ case "grgPointBySize":
+ //when creating point by size the grid orign can be used so remove the hidden class
+ html.removeClass(this._gridSettingsInstance.gridOriginContainer, 'controlGroupHidden');
+ break;
+ case "grgAreaByRefSystem":
+ case "grgPointByRefSystem":
+ //hide elements that are not relevant to creating by reference system
+ html.addClass(this._gridSettingsInstance.gridShapeContainer, 'controlGroupHidden');
+ html.addClass(this._gridSettingsInstance.gridUnitsContainer, 'controlGroupHidden');
+ html.addClass(this._gridSettingsInstance.labelStyleContainer, 'controlGroupHidden');
+ html.addClass(this._gridSettingsInstance.labelStartPositionContainer, 'controlGroupHidden');
+ html.addClass(this._gridSettingsInstance.labelDirectionContainer, 'controlGroupHidden');
+ html.addClass(this._gridSettingsInstance.labelDirectionContainer, 'controlGroupHidden');
+ //when creating by reference system give the user a choice of which one by removing the hidden class
+ html.removeClass(this._gridSettingsInstance.gridRefSystemContainer, 'controlGroupHidden');
+ break;
+ }
+ },
+
+ /**
+ * Get panel node from panel name
+ * @param {string} panel name
+ * @memberOf widgets/GRG/Widget
+ **/
+ _getNodeByName: function (panelName) {
+ var node;
+ switch (panelName) {
+ case "mainPage":
+ node = this.mainPageNode;
+ break;
+ case "grgAreaBySize":
+ node = this.grgAreaBySizePageNode;
+ break;
+ case "grgAreaByRefSystem":
+ node = this.grgAreaByRefSystemPageNode;
+ break;
+ case "grgAreaFromNonStandard":
+ node = this.grgAreaFromNonStandardPageNode;
+ break;
+ case "grgPointBySize":
+ node = this.grgPointBySizePageNode;
+ break;
+ case "grgPointByRefSystem":
+ node = this.grgPointByRefSystemPageNode;
+ break;
+ case "settingsPage":
+ node = this.settingsPageNode;
+ break;
+ case "publishPage":
+ node = this.publishPageNode;
+ break;
+ }
+ return node;
+ },
+
+ /**
+ * This function resets everything on navigating back to main page
+ * @memberOf widgets/GRG/Widget
+ */
+ _resetOnBackToMainPage: function () {
+ //reset the tools
+ this._showPanel("mainPage");
+ this._reset();
+ },
+
+ _reset: function () {
+ this._clearLayers(true);
+
+ //ensure all toolbars are deactivated
+ this.dt_AreaBySize.deactivate();
+ this.dt_PointBySize.deactivate();
+ this.dt_PointByRefSystem.deactivate();
+ this.dt_AreaByRefSystem.deactivate();
+
+ //enable map navigation if disabled due to a tool being in use
+ this.map.enableMapNavigation();
+
+ //remove any active classes from the tool icons
+ dojo.removeClass(this.grgAreaBySizeDrawPolygonIcon, 'jimu-polygon-active');
+ dojo.removeClass(this.grgAreaBySizeDrawExtentIcon, 'jimu-extent-active');
+ dojo.removeClass(this.grgPointBySizeAddPointBtn, 'jimu-edit-active');
+ dojo.removeClass(this.grgPointByRefSystemAddPointBtn, 'jimu-edit-active');
+
+ //reset the two dropdown menus on the main page
+ html.addClass(this.fromAreaContainer, 'controlGroupHidden');
+ html.addClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.newGRGAreaButton, 'GRGDrafterLabelSettingsUpButton');
+ html.addClass(this.fromPointContainer, 'controlGroupHidden');
+ html.addClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.newGRGPointButton, 'GRGDrafterLabelSettingsUpButton');
+ },
+
+ _clearLayers: function (includeExtentLayer) {
+ this.GRGArea.clear();
+ //refresh GRG layer to make sure any labels are removed
+ this.GRGArea.refresh();
+ //ensure the edit toolbar is deactived
+ this.editToolbar.deactivate();
+
+ //sometimes we only want to clear the GRGArea layer and not the graphic layer
+ if(includeExtentLayer) {
+ this._graphicsLayerGRGExtent.clear();
+ this.dt_PointBySize.removeStartGraphic(this._graphicsLayerGRGExtent);
+ this.dt_PointByRefSystem.removeStartGraphic(this._graphicsLayerGRGExtent);
+ //reset the angle
+ this.angle = 0;
+ this.grgAreaBySizeRotation.setValue(this.angle);
+ this.grgAreaBySizeRotation.set('disabled', true);
+ this.grgAreaBySizeCellHeight.set('disabled', true);
+ this.grgAreaBySizeCellWidth.set('disabled', true);
+ }
+ },
+
+ /**
+ * Creates grid settings
+ * @memberOf widgets/GRG/Widget
+ **/
+ _createGridSettings: function () {
+ //Create GridSettings Instance
+ this._gridSettingsInstance = new GridSettings({
+ nls: this.nls,
+ config: this.config,
+ appConfig: this.appConfig
+ }, domConstruct.create("div", {}, this.gridSettingsNode));
+
+ //add a listener for a change in settings
+ this.own(this._gridSettingsInstance.on("gridSettingsChanged",
+ lang.hitch(this, function (updatedSettings) {
+ this._cellShape = updatedSettings.cellShape;
+ this._labelStartPosition = updatedSettings.labelStartPosition;
+ this._cellUnits = updatedSettings.cellUnits;
+ this._labelType = updatedSettings.labelType;
+ this._labelDirection = updatedSettings.labelDirection;
+ this._gridOrigin = updatedSettings.gridOrigin;
+ this._referenceSystem = updatedSettings.referenceSystem;
+
+ // show or hide labels
+ featureLayerInfo = jimuLayerInfos.getInstanceSync().getLayerInfoById("Gridded-Reference-Graphic");
+ featureLayerInfo.enablePopup();
+ if(this._showLabels) {
+ featureLayerInfo.showLabels();
+ } else {
+ featureLayerInfo.hideLabels();
+ }
+
+ //disable or enable the cell height input depending on the cell shape
+ //(hexagon does not need a height input)
+ if(this._cellShape === "default") {
+ this.grgAreaBySizeCellHeight.setValue(this.grgAreaBySizeCellWidth.value);
+ this.grgPointBySizeCellHeight.set('disabled', false);
+ this.grgPointBySizeCellHeight.setValue(this.grgPointBySizeCellWidth.value);
+ } else {
+ this.grgAreaBySizeCellHeight.set('disabled', true);
+ this.grgAreaBySizeCellHeight.setValue(0);
+ this.grgPointBySizeCellHeight.set('disabled', true);
+ this.grgPointBySizeCellHeight.setValue(0);
+ }
+
+ //set grid colours
+ var fillColor = new Color(updatedSettings.gridFillColor);
+ fillColor.a = 1 - updatedSettings.gridFillTransparency;
+
+ var outlineColor = new Color(updatedSettings.gridOutlineColor);
+ outlineColor.a = 1 - updatedSettings.gridOutlineTransparency;
+
+ this._GRGAreaFillSymbol = {
+ type: 'esriSFS',
+ style: 'esriSFSSolid',
+ color: fillColor,
+ outline: {
+ color: outlineColor,
+ width: 2,
+ type: 'esriSLS',
+ style: 'esriSLSSolid'
+ }
+ };
+
+ // create a renderer for the grg layer to override default symbology
+ var gridSymbol = new SimpleFillSymbol(this._GRGAreaFillSymbol);
+ var gridRenderer = new SimpleRenderer(gridSymbol);
+ this.GRGArea.setRenderer(gridRenderer);
+
+ //set label properties
+ var textColor = new Color(updatedSettings.fontSettings.textColor);
+ var labelTrans = (1 - updatedSettings.fontSettings.labelTransparency) * 255;
+
+ if(updatedSettings.fontSettings.haloOn){
+ var haloSize = parseInt(updatedSettings.fontSettings.haloSize);
+ } else {
+ var haloSize = 0;
+ }
+
+ var haloColor = new Color(updatedSettings.fontSettings.haloColor);
+
+ //override the text symbol with the new settings
+ this._cellTextSymbol = {
+ "type": "esriTS",
+ "color": [
+ textColor.r,
+ textColor.g,
+ textColor.b,
+ labelTrans
+ ],
+ "haloSize": haloSize,
+ "haloColor": [
+ haloColor.r,
+ haloColor.g,
+ haloColor.b,
+ labelTrans
+ ],
+ "horizontalAlignment": "center",
+ "font": {
+ "size": parseInt(updatedSettings.fontSettings.fontSize),
+ "style": updatedSettings.fontSettings.font.italic?"italic":"normal",
+ "weight": updatedSettings.fontSettings.font.bold?"bold":"normal",
+ "family": updatedSettings.fontSettings.font.fontFamily,
+ "decoration" : updatedSettings.fontSettings.font.underline?"underline":"none"
+ }
+ };
+
+ // create a text symbol to define the style of labels
+ var json = {"labelExpressionInfo": {"value" : "{grid}"}};
+ var labelClass = new LabelClass(json);
+ labelClass.symbol = new TextSymbol(this._cellTextSymbol);
+ this.GRGArea.setLabelingInfo([labelClass]);
+
+ //refresh the layer to apply the settings
+ this.GRGArea.refresh();
+ })));
+ this._gridSettingsInstance.startup();
+ },
+
+ /**
+ * Displays selected panel
+ * @param {string} panel name
+ * @memberOf widgets/GRG/Widget
+ **/
+ _showPanel: function (currentPanel) {
+ var prevNode, currentNode;
+ //check if previous panel exist and hide it
+ if (this._currentOpenPanel) {
+ prevNode = this._getNodeByName(this._currentOpenPanel);
+ domClass.add(prevNode, "GRGDrafterHidden");
+ }
+ //get current panel to be displayed and show it
+ currentNode = this._getNodeByName(currentPanel);
+ domClass.remove(currentNode, "GRGDrafterHidden");
+ //set the current panel and previous panel
+ this._lastOpenPanel = this._currentOpenPanel;
+ this._currentOpenPanel = currentPanel;
+ },
+
+ /**
+ * Handle the draw polygon icon being clicked on the GRG Area by Size Panel
+ * @memberOf widgets/GRG/Widget
+ **/
+ _grgAreaBySizeDrawPolygonIconClicked: function () {
+ this._clearLayers(true);
+ // deactive the other tool if active
+ if(domClass.contains(this.grgAreaBySizeDrawExtentIcon,'jimu-extent-active')) {
+ //this tool is already selected so deactivate
+ this.dt_AreaBySize.deactivate();
+ domClass.toggle(this.grgAreaBySizeDrawExtentIcon, 'jimu-extent-active');
+ }
+ if(domClass.contains(this.grgAreaBySizeDrawPolygonIcon,'jimu-polygon-active')) {
+ //already selected so deactivate draw tool
+ this.dt_AreaBySize.deactivate();
+ this.map.enableMapNavigation();
+ } else {
+ this.map.disableMapNavigation();
+ this.dt_AreaBySize.activate('polygon');
+ //depending on what draw option is used we want different edit functionality
+ this.own(on(this._graphicsLayerGRGExtent, "click", lang.hitch(this, function(evt) {
+ this.editToolbar._defaultOptions.uniformScaling = true;
+ this.editToolbar.activate(Edit.MOVE|Edit.EDIT_VERTICES, evt.graphic);
+ })));
+ }
+ domClass.toggle(this.grgAreaBySizeDrawPolygonIcon, 'jimu-polygon-active');
+ },
+
+ /**
+ * Handle the draw extent icon being clicked on the GRG Area by Size Panel
+ * @memberOf widgets/GRG/Widget
+ **/
+ _grgAreaBySizeDrawExtentIconClicked: function () {
+ this._clearLayers(true);
+ // deactive the other tool if active
+ if(domClass.contains(this.grgAreaBySizeDrawPolygonIcon,'jimu-polygon-active')) {
+ //this tool is already selected so deactivate
+ this.dt_AreaBySize.deactivate();
+ domClass.toggle(this.grgAreaBySizeDrawPolygonIcon, 'jimu-polygon-active');
+ }
+ if(domClass.contains(this.grgAreaBySizeDrawExtentIcon,'jimu-extent-active')) {
+ //already selected so deactivate draw tool
+ this.dt_AreaBySize.deactivate();
+ this.map.enableMapNavigation();
+ } else {
+ this.map.disableMapNavigation();
+ this.dt_AreaBySize.activate('extent');
+ //depending on what draw option is used we want different edit functionality
+ this.own(on(this._graphicsLayerGRGExtent, "click", lang.hitch(this, function(evt) {
+ this.editToolbar._defaultOptions.uniformScaling = true;
+ this.editToolbar.activate(Edit.MOVE|Edit.ROTATE|Edit.SCALE, evt.graphic);
+ })));
+ }
+ domClass.toggle(this.grgAreaBySizeDrawExtentIcon, 'jimu-extent-active');
+ },
+
+ /**
+ * Handle the draw point icon being clicked on the GRG Point by Size Panel
+ * @memberOf widgets/GRG/Widget
+ **/
+ _grgPointBySizeDrawButtonClicked: function () {
+ if(domClass.contains(this.grgPointBySizeAddPointBtn,'jimu-edit-active')) {
+ //already selected so deactivate draw tool
+ this.dt_PointBySize.deactivate();
+ this.map.enableMapNavigation();
+ } else {
+ this.dt_PointBySize.removeStartGraphic(this._graphicsLayerGRGExtent);
+ this._clearLayers(true);
+ this.grgPointBySizeCoordTool.manualInput = false;
+ this.dt_PointBySize._setTooltipMessage(0);
+ this.map.disableMapNavigation();
+ this.dt_PointBySize.activate('point');
+ var tooltip = this.dt_PointBySize._tooltip;
+ if (tooltip) {
+ tooltip.innerHTML = this.nls.drawPointToolTip;
+ }
+ }
+ domClass.toggle(this.grgPointBySizeAddPointBtn, 'jimu-edit-active');
+ },
+
+ /**
+ * Handle the draw point icon being clicked on the GRG Point by Reference System
+ * @memberOf widgets/GRG/Widget
+ **/
+ _grgPointByRefSystemDrawButtonClicked: function () {
+ if(domClass.contains(this.grgPointByRefSystemAddPointBtn,'jimu-edit-active')) {
+ //already selected so deactivate draw tool
+ this.dt_PointByRefSystem.deactivate();
+ this.map.enableMapNavigation();
+ } else {
+ this.dt_PointByRefSystem.removeStartGraphic(this._graphicsLayerGRGExtent);
+ this._clearLayers(true);
+ this.grgPointByRefSystemCoordTool.manualInput = false;
+ this.dt_PointByRefSystem._setTooltipMessage(0);
+ this.map.disableMapNavigation();
+ this.dt_PointByRefSystem.activate('point');
+ var tooltip = this.dt_PointByRefSystem._tooltip;
+ if (tooltip) {
+ tooltip.innerHTML = this.nls.drawPointToolTip;
+ }
+ }
+ domClass.toggle(this.grgPointByRefSystemAddPointBtn, 'jimu-edit-active');
+ },
+
+ /**
+ * Handle the draw extent icon being clicked on the GRG Area by Reference System
+ * @memberOf widgets/GRG/Widget
+ **/
+ _grgAreaByRefSystemDrawIconClicked: function () {
+ if(domClass.contains(this.grgAreaByRefSystemDrawIcon,'jimu-extent-active')) {
+ //already selected so deactivate draw tool
+ this.dt_AreaByRefSystem.deactivate();
+ this.map.enableMapNavigation();
+ } else {
+ this._graphicsLayerGRGExtent.clear();
+ this.grgPointBySizeCoordTool.manualInput = false;
+ this.map.disableMapNavigation();
+ this.dt_AreaByRefSystem.activate('extent');
+ this.editToolbar.deactivate();
+ //depending on what draw option is used we want different edit functionality
+ this.own(on(this._graphicsLayerGRGExtent, "click", lang.hitch(this, function(evt) {
+ this.editToolbar._defaultOptions.uniformScaling = false;
+ this.editToolbar.activate(Edit.MOVE|Edit.SCALE, evt.graphic);
+ })));
+ }
+ domClass.toggle(this.grgAreaByRefSystemDrawIcon, 'jimu-extent-active');
+ },
+
+ /**
+ * Handle the completion of the draw tool on the GRG Area by Size
+ * @memberOf widgets/GRG/Widget
+ **/
+ _dt_AreaBySizeComplete: function (evt) {
+ this.map.enableMapNavigation();
+ this.dt_AreaBySize.deactivate();
+ if(evt.geometry.type === 'extent'){
+ evt.geometry = gridGeomUtils.extentToPolygon(evt.geometry);
+ var graphic = new Graphic(evt.geometry, this._extentSym);
+ this.grgAreaBySizeRotation.set('disabled', false);
+ domClass.toggle(this.grgAreaBySizeDrawExtentIcon, 'jimu-extent-active');
+ } else {
+ var graphic = new Graphic(evt.geometry, this._extentSym);
+ evt.geometry = gridGeomUtils.extentToPolygon(evt.geometry.getExtent());
+ domClass.toggle(this.grgAreaBySizeDrawPolygonIcon, 'jimu-polygon-active');
+ }
+ if(this._cellShape === "default") {
+ this.grgAreaBySizeCellHeight.set('disabled', false);
+ }
+ this.grgAreaBySizeCellWidth.set('disabled', false);
+ this._graphicsLayerGRGExtent.add(graphic);
+ this.centerPoint = evt.geometry.getCentroid();
+ this._calculateCellWidthAndHeight(evt.geometry);
+ },
+
+ /**
+ * Calulate the width and height from the drawn feature
+ * @memberOf widgets/GRG/Widget
+ **/
+ _calculateCellWidthAndHeight: function (geometry) {
+ //if the input id geographics project the geometry to WMAS
+ if (geometry.spatialReference.wkid === 4326) {
+ // if the geographic point can be projected the map spatial reference do so
+ geometry = WebMercatorUtils.geographicToWebMercator(geometry);
+ }
+
+ //calculate the geodesic width and height of the required grid cells
+ var calculatedCellWidth = ((GeometryEngine.geodesicLength(new Polyline({
+ paths: [[[geometry.getPoint(0,0).x, geometry.getPoint(0,0).y], [geometry.getPoint(0,1).x, geometry.getPoint(0,1).y]]],
+ spatialReference: geometry.spatialReference
+ }), this._cellUnits))/this.cellHorizontal.value);
+
+ var calculatedCellHeight = ((GeometryEngine.geodesicLength(new Polyline({
+ paths: [[[geometry.getPoint(0,0).x, geometry.getPoint(0,0).y], [geometry.getPoint(0,3).x, geometry.getPoint(0,3).y]]],
+ spatialReference: geometry.spatialReference
+ }), this._cellUnits))/this.cellVertical.value);
+
+ //convert the width and height into meters
+ var cellWidthMeters = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(calculatedCellWidth, this._cellUnits);
+ var cellHeightMeters = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(calculatedCellHeight, this._cellUnits);
+
+ //if the width or height of a grid cell is over 20000m we need to use a planar grid
+ //so recalculate the width and height using a planar measurement
+ if((cellWidthMeters < 20000) && ((cellHeightMeters < 20000 && this._cellShape !== "hexagon") || this._cellShape === "hexagon")) {
+ this.geodesicGrid = true;
+ this.grgAreaBySizeCellWidth.setValue(calculatedCellWidth);
+ this._cellShape === "default"?this.grgAreaBySizeCellHeight.setValue(calculatedCellHeight):this.grgAreaBySizeCellHeight.setValue(0);
+ } else {
+ this.geodesicGrid = false;
+ this.grgAreaBySizeCellWidth.setValue(((GeometryEngine.distance(geometry.getPoint(0,0), geometry.getPoint(0,1), this._cellUnits))/this.cellHorizontal.value));
+ this._cellShape === "default"?this.grgAreaBySizeCellHeight.setValue(((GeometryEngine.distance(geometry.getPoint(0,0), geometry.getPoint(0,3), this._cellUnits))/this.cellVertical.value)):this.grgAreaBySizeCellHeight.setValue(0);
+ }
+ },
+
+ /**
+ * Handle the completion of the draw point tool on the GRG Point by Size
+ * @memberOf widgets/GRG/Widget
+ **/
+ _dt_PointBySizeComplete: function () {
+ domClass.remove(this.grgPointBySizeAddPointBtn, 'jimu-edit-active');
+ this.dt_PointBySize.deactivate();
+ this.map.enableMapNavigation();
+ },
+
+ /**
+ * Handle the completion of the draw point tool on the GRG Point by Reference System
+ * @memberOf widgets/GRG/Widget
+ **/
+ _dt_PointByRefSystemComplete: function () {
+ domClass.remove(this.grgPointByRefSystemAddPointBtn, 'jimu-edit-active');
+ this.dt_PointByRefSystem.deactivate();
+ this.map.enableMapNavigation();
+ },
+
+ /**
+ * Handle the completion of the draw extent tool on the GRG Area by Reference System
+ * @memberOf widgets/GRG/Widget
+ **/
+ _dt_AreaByRefSystemComplete: function (evt) {
+ domClass.remove(this.grgAreaByRefSystemDrawIcon, 'jimu-extent-active');
+ var graphic = new Graphic(gridGeomUtils.extentToPolygon(evt.geometry), this._extentSym);
+ this._graphicsLayerGRGExtent.add(graphic);
+ this.dt_AreaByRefSystem.deactivate();
+ this.map.enableMapNavigation();
+ },
+
+ /**
+ * catch key press in start point for GRG Point by Size
+ **/
+ _grgPointBySizeCoordToolKeyWasPressed: function (evt) {
+ this.grgPointBySizeCoordTool.manualInput = true;
+ if (evt.keyCode === keys.ENTER) {
+ this.grgPointBySizeCoordTool.inputCoordinate.getInputType().then(lang.hitch(this,
+ function (r) {
+ if(r.inputType === "UNKNOWN"){
+ var alertMessage = new Message({
+ message: this.nls.parseCoordinatesError
+ });
+ } else {
+ this._reset();
+ topic.publish(
+ 'grg-center-point-input',
+ this.grgPointBySizeCoordTool.inputCoordinate.coordinateEsriGeometry
+ );
+ this._grgPointBySizeSetCoordLabel(r.inputType);
+ var fs = this.grgPointBySizeCoordinateFormat.content.formats[r.inputType];
+ this.grgPointBySizeCoordTool.inputCoordinate.set('formatString', fs.defaultFormat);
+ this.grgPointBySizeCoordTool.inputCoordinate.set('formatType', r.inputType);
+ this.dt_PointBySize.addStartGraphic(r.coordinateEsriGeometry, this._ptSym, this._graphicsLayerGRGExtent);
+ }
+ }
+ ));
+ }
+ },
+
+ /**
+ * catch key press in start point for GRG Point by Size
+ **/
+ _grgPointByRefSystemCoordToolKeyWasPressed: function (evt) {
+ this.grgPointByRefSystemCoordTool.manualInput = true;
+ if (evt.keyCode === keys.ENTER) {
+ this.grgPointByRefSystemCoordTool.inputCoordinate.getInputType().then(lang.hitch(this,
+ function (r) {
+ if(r.inputType === "UNKNOWN"){
+ var alertMessage = new Message({
+ message: this.nls.parseCoordinatesError
+ });
+ } else {
+ this._reset();
+ topic.publish(
+ 'grg-center-point-input',
+ this.grgPointByRefSystemCoordTool.inputCoordinate.coordinateEsriGeometry
+ );
+ this._grgPointByRefSystemSetCoordLabel(r.inputType);
+ var fs = this.grgPointBySizeCoordinateFormat.content.formats[r.inputType];
+ this.grgPointByRefSystemCoordTool.inputCoordinate.set('formatString', fs.defaultFormat);
+ this.grgPointByRefSystemCoordTool.inputCoordinate.set('formatType', r.inputType);
+ this.dt_PointByRefSystem.addStartGraphic(r.coordinateEsriGeometry, this._ptSym, this._graphicsLayerGRGExtent);
+ }
+ }
+ ));
+ }
+ },
+
+ /**
+ * Reformat coordinate label depend on what reference system is chosen
+ * Point by Size Panel
+ **/
+ _grgPointBySizeSetCoordLabel: function (toType) {
+ this.grgPointBySizeCoordInputLabel.innerHTML = dojoString.substitute(
+ 'GRG Origin (${crdType})', {
+ crdType: toType
+ });
+ },
+
+ /**
+ * Reformat coordinate label depend on what reference system is chosen
+ * Point by Reference System Panel
+ **/
+ _grgPointByRefSystemSetCoordLabel: function (toType) {
+ this.grgPointByRefSystemCoordInputLabel.innerHTML = dojoString.substitute(
+ 'GRG Origin (${crdType})', {
+ crdType: toType
+ });
+ },
+
+ /**
+ * Handle the format coordinate input popup opening
+ * Point by Size Panel
+ **/
+ _grgPointBySizeCoordFormatButtonClicked: function () {
+ this.grgPointBySizeCoordinateFormat.content.set('ct', this.grgPointBySizeCoordTool.inputCoordinate.formatType);
+ dijitPopup.open({
+ popup: this.grgPointBySizeCoordinateFormat,
+ around: this.grgPointBySizeCoordFormatButton
+ });
+ },
+
+ /**
+ * Handle the format coordinate input popup opening
+ * Point by Reference System Panel
+ **/
+ _grgPointByRefSystemCoordFormatButtonClicked: function () {
+ this.grgPointByRefSystemCoordinateFormat.content.set('ct', this.grgPointByRefSystemCoordTool.inputCoordinate.formatType);
+ dijitPopup.open({
+ popup: this.grgPointByRefSystemCoordinateFormat,
+ around: this.grgPointByRefSystemCoordFormatButton
+ });
+ },
+
+ /**
+ * Handle the format coordinate input being applied
+ * Point by Size Panel
+ **/
+ _grgPointBySizeCoordFormatPopupApplyButtonClicked: function () {
+ var fs = this.grgPointBySizeCoordinateFormat.content.formats[this.grgPointBySizeCoordinateFormat.content.ct];
+ var cfs = fs.defaultFormat;
+ var fv = this.grgPointBySizeCoordinateFormat.content.frmtSelect.get('value');
+ if (fs.useCustom) {
+ cfs = fs.customFormat;
+ }
+ this.grgPointBySizeCoordTool.inputCoordinate.set(
+ 'formatPrefix',
+ this.grgPointBySizeCoordinateFormat.content.addSignChkBox.checked
+ );
+ this.grgPointBySizeCoordTool.inputCoordinate.set('formatString', cfs);
+ this.grgPointBySizeCoordTool.inputCoordinate.set('formatType', fv);
+ this._grgPointBySizeSetCoordLabel(fv);
+ dijitPopup.close(this.grgPointBySizeCoordinateFormat);
+ },
+
+ /**
+ * Handle the format coordinate input being applied
+ * Point by Reference System Panel
+ **/
+ _grgPointByRefSystemCoordFormatPopupApplyButtonClicked: function () {
+ var fs = this.grgPointByRefSystemCoordinateFormat.content.formats[this.grgPointByRefSystemCoordinateFormat.content.ct];
+ var cfs = fs.defaultFormat;
+ var fv = this.grgPointByRefSystemCoordinateFormat.content.frmtSelect.get('value');
+ if (fs.useCustom) {
+ cfs = fs.customFormat;
+ }
+ this.grgPointByRefSystemCoordTool.inputCoordinate.set(
+ 'formatPrefix',
+ this.grgPointByRefSystemCoordinateFormat.content.addSignChkBox.checked
+ );
+ this.grgPointByRefSystemCoordTool.inputCoordinate.set('formatString', cfs);
+ this.grgPointByRefSystemCoordTool.inputCoordinate.set('formatType', fv);
+ this._grgPointByRefSystemSetCoordLabel(fv);
+ dijitPopup.close(this.grgPointByRefSystemCoordinateFormat);
+ },
+
+ /**
+ * Handle the toggle for set number of row / columns changing
+ **/
+ _setNumberRowsColumnsCheckBoxChanged: function () {
+ if(this.setNumberRowsColumns.checked) {
+ this.grgAreaBySizeCellWidth.set('disabled', true);
+ this.grgAreaBySizeCellHeight.set('disabled', true);
+ this.cellHorizontal.set('disabled', false);
+ this.cellVertical.set('disabled', false);
+ } else {
+ this.cellHorizontal.set('disabled', true);
+ this.cellVertical.set('disabled', true);
+ }
+ this._clearLayers(true);
+ },
+
+ /**
+ * Handle create GRG button being clicked on the GRG Area by Size Panel
+ **/
+ _grgAreaBySizeCreateGRGButtonClicked: function () {
+ //check form inputs for validity
+ if (this._graphicsLayerGRGExtent.graphics[0] && this.grgAreaBySizeCellWidth.isValid() && this.grgAreaBySizeCellHeight.isValid() && this.grgAreaBySizeRotation.isValid()) {
+ this._clearLayers(false);
+
+ if(this.angle === 0) {
+ var geom = gridGeomUtils.extentToPolygon(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent());
+ } else {
+ var geom = this._graphicsLayerGRGExtent.graphics[0].geometry;
+ }
+
+ //if the input is geographics project the geometry to WMAS
+ if (geom.spatialReference.wkid === 4326) {
+ // if the geographic point can be projected the map spatial reference do so
+ geom = WebMercatorUtils.geographicToWebMercator(geom);
+ }
+
+ var GRGAreaWidth, GRGAreaHeight;
+ //work out width and height of AOI, method depends on if the grid is to be geodesic
+ if(this.geodesicGrid) {
+ GRGAreaWidth = GeometryEngine.geodesicLength(new Polyline({
+ paths: [[[geom.getPoint(0,0).x, geom.getPoint(0,0).y], [geom.getPoint(0,1).x, geom.getPoint(0,1).y]]],
+ spatialReference: geom.spatialReference
+ }), 'meters');
+ GRGAreaHeight = GeometryEngine.geodesicLength(new Polyline({
+ paths: [[[geom.getPoint(0,0).x, geom.getPoint(0,0).y], [geom.getPoint(0,3).x, geom.getPoint(0,3).y]]],
+ spatialReference: geom.spatialReference
+ }), 'meters');
+ } else {
+ GRGAreaWidth = GeometryEngine.distance(geom.getPoint(0,0), geom.getPoint(0,1), 'meters');
+ GRGAreaHeight = GeometryEngine.distance(geom.getPoint(0,0), geom.getPoint(0,3), 'meters');
+ }
+
+ var cellWidth = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgAreaBySizeCellWidth.value, this._cellUnits);
+ var cellHeight = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgAreaBySizeCellHeight.value,this._cellUnits);
+
+ //work out how many cells are needed horizontally & Vertically to cover the whole canvas area
+ var numCellsHorizontal = Math.round(GRGAreaWidth/cellWidth);
+
+ var numCellsVertical;
+ this._cellShape === "default"?numCellsVertical = Math.round(GRGAreaHeight/cellHeight):numCellsVertical = Math.round(GRGAreaHeight/(cellWidth)/Math.cos(30* Math.PI/180)) + 1;
+
+ if(drawGRG.checkGridSize(numCellsHorizontal,numCellsVertical))
+ {
+ var features = drawGRG.createGRG(
+ numCellsHorizontal,
+ numCellsVertical,
+ this.centerPoint,
+ cellWidth,
+ cellHeight,
+ this.angle,
+ this._labelStartPosition,
+ this._labelType,
+ this._labelDirection,
+ this._cellShape,
+ 'center',
+ this.geodesicGrid,
+ this.map,
+ esriConfig.defaults.geometryService);
+ //apply the edits to the feature layer
+ this.GRGArea.applyEdits(features, null, null);
+ this.map.setExtent(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent().expand(2),false);
+ this._graphicsLayerGRGExtent.clear();
+ this._showPanel("publishPage");
+ }
+ }
+ },
+
+ /**
+ * Handle create GRG button being clicked on the GRG Point by Size Panel
+ **/
+ _grgPointBySizeCreateGRGButtonClicked: function () {
+ //check form inputs for validity
+ if (this.dt_PointBySize.startGraphic && this.grgPointBySizeCellWidth.isValid() && this.grgPointBySizeCellHeight.isValid() && this.gridAnglePoint.isValid()) {
+
+ //get center point of AOI
+ var centerPoint = WebMercatorUtils.geographicToWebMercator(this.grgPointBySizeCoordTool.inputCoordinate.coordinateEsriGeometry);
+
+ var cellWidth = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgPointBySizeCellWidth.value,this._cellUnits);
+ var cellHeight = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgPointBySizeCellHeight.value,this._cellUnits);
+
+ // if the width or height of a grid cell is over 20000m we need to use a planar grid
+ if((cellWidth < 20000) && ((cellHeight < 20000 && this._cellShape !== "hexagon") || this._cellShape === "hexagon")) {
+ this.geodesicGrid = true;
+ } else {
+ this.geodesicGrid = false;
+ }
+
+ if(drawGRG.checkGridSize(this.grgPointBySizeCellHorizontal.value,this.grgPointBySizeCellVertical.value))
+ {
+ var features = drawGRG.createGRG(
+ this.grgPointBySizeCellHorizontal.value,
+ this.grgPointBySizeCellVertical.value,
+ centerPoint,
+ cellWidth,
+ cellHeight,
+ this.gridAnglePoint.value,
+ this._labelStartPosition,
+ this._labelType,
+ this._labelDirection,
+ this._cellShape,
+ this._gridOrigin,
+ this.geodesicGrid,
+ this.map,
+ esriConfig.defaults.geometryService);
+ //apply the edits to the feature layer
+ this.GRGArea.applyEdits(features, null, null);
+ this.dt_PointBySize.removeStartGraphic(this._graphicsLayerGRGExtent);
+ var geomArray = [];
+ for(var i = 0;i < features.length;i++){
+ geomArray.push(features[i].geometry);
+ }
+ var union = GeometryEngine.union(geomArray)
+ this.map.setExtent(union.getExtent().expand(2),false);
+ this._showPanel("publishPage");
+ }
+ } else {
+ // Invalid entry
+ var alertMessage = new Message({
+ message: this.nls.missingParametersMessage
+ });
+ }
+ },
+
+ /**
+ * Handle create GRG button being clicked on the GRG Point by Reference System Panel
+ **/
+ _grgPointByRefSystemCreateGRGButtonClicked: function () {
+ var width, height, cellBLPoint, extent, MGRS, offsets;
+ var geomArray = [];
+ this._clearLayers(false);
+ if(drawGRG.checkGridSize(this.grgPointByRefCellHorizontal.getValue(),this.grgPointByRefCellVertical.getValue())){
+ if (this.dt_PointByRefSystem.startGraphic && this.grgPointByRefCellHorizontal.isValid() && this.grgPointByRefCellVertical.isValid()) {
+ var gridOrigin = this.grgPointByRefSystemCoordTool.inputCoordinate.coordinateEsriGeometry;
+ switch(this.grgPointByRefSystemGridSize.getValue()){
+ case 'UTM':
+ if(gridOrigin.x < 0){
+ var tempLon = (gridOrigin.x - (gridOrigin.x % 6)) - 6;
+ } else {
+ var tempLon = gridOrigin.x - (gridOrigin.x % 6);
+ }
+ if(gridOrigin.y < 0){
+ var tempLat = (gridOrigin.y - (gridOrigin.y % 8)) - 8;
+ } else {
+ var tempLat = gridOrigin.y - (gridOrigin.y % 8);
+ }
+ break;
+ case '100000':
+ MGRS = mgrs.LLtoMGRS(gridOrigin.y,gridOrigin.x,5);
+ MGRS = MGRS.substring(0, MGRS.length - 10);
+ MGRS = MGRS + '0000000000';
+ break;
+ case '10000':
+ MGRS = mgrs.LLtoMGRS(gridOrigin.y,gridOrigin.x,1);
+ break;
+ case '1000':
+ MGRS = mgrs.LLtoMGRS(gridOrigin.y,gridOrigin.x,2);
+ break;
+ case '100':
+ MGRS = mgrs.LLtoMGRS(gridOrigin.y,gridOrigin.x,3);
+ break;
+ case '10':
+ MGRS = mgrs.LLtoMGRS(gridOrigin.y,gridOrigin.x,4);
+ break;
+ }
+ if(this.grgPointByRefSystemGridSize.getValue() === 'UTM') {
+ cellBLPoint = new Point(tempLon,tempLat);
+ width = this.grgPointByRefCellHorizontal.getValue() * 6;
+ height = this.grgPointByRefCellVertical.getValue() * 8;
+ extent = new Extent({
+ "xmin":cellBLPoint.x,"ymin":cellBLPoint.y,"xmax":cellBLPoint.x + width,"ymax":cellBLPoint.y + height,
+ "spatialReference":{"wkid":4326}
+ });
+ extent = WebMercatorUtils.geographicToWebMercator(extent);
+ } else {
+ cellBLPoint = mgrs.USNGtoPoint(MGRS);
+
+ width = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgPointByRefSystemGridSize.getValue(),this._cellUnits) * (this.grgPointByRefCellHorizontal.getValue());
+ height = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgPointByRefSystemGridSize.getValue(),this._cellUnits) * (this.grgPointByRefCellVertical.getValue());
+
+ var cellTLPoint = geometryUtils.getDestinationPoint(cellBLPoint, 90, width);
+ cellTLPoint = geometryUtils.getDestinationPoint(cellTLPoint, 0, height);
+
+ offset = this.grgPointBySizeCoordTool.inputCoordinate.util.convertToMeters(this.grgPointByRefSystemGridSize.getValue(),this._cellUnits) / 5;
+
+ //shrink the extent slightly so that we dont pick up extra cells around the edge
+ var cellBLPoint = geometryUtils.getDestinationPoint(cellBLPoint, 45, offset);
+ var cellTLPoint = geometryUtils.getDestinationPoint(cellTLPoint, 225, offset);
+
+ extent = new Extent({
+ "xmin":cellBLPoint.x,"ymin":cellBLPoint.y,"xmax":cellTLPoint.x,"ymax":cellTLPoint.y,
+ "spatialReference":{"wkid":4326}
+ });
+
+ extent = WebMercatorUtils.geographicToWebMercator(extent);
+ }
+
+ var zones = mgrsUtils.zonesFromExtent(extent,this.map);
+
+ var features = [];
+
+ switch(this.grgPointByRefSystemGridSize.getValue()){
+ case 'UTM':
+ for (i = 0; i < zones.length; i++) {
+ if (this.map.spatialReference.wkid !== 4326) {
+ var graphic = new Graphic(WebMercatorUtils.geographicToWebMercator(zones[i].gridPolygon.unclippedPolygon));
+ } else {
+ var graphic = new Graphic(zones[i].gridPolygon.unclippedPolygon);
+ }
+ var label = this.grgPointByRefLabelFormat.value
+ label = label.replace(/Z/, zones[i].gridPolygon.text);
+ graphic.setAttributes({'grid': label});
+ features.push(graphic);
+ geomArray.push(graphic.geometry);
+ }
+ break;
+ default:
+ var polysToLoop = mgrsUtils.processZonePolygons(zones, this.map, 100000, extent);
+ var currentValue = 10000;
+ while (currentValue >= this.grgPointByRefSystemGridSize.getValue()) {
+ var polys = [];
+ for (i = 0; i < polysToLoop.length; i++) {
+ polys = polys.concat(mgrsUtils.handleGridSquares(polysToLoop[i],this.map, currentValue, extent));
+ }
+ polysToLoop = [];
+ polysToLoop = polys;
+ currentValue = currentValue / 10;
+ }
+ var count = 1;
+ for (i = 0; i < polysToLoop.length; i++) {
+ if (this.map.spatialReference.wkid !== 4326) {
+ var graphic = new Graphic(polysToLoop[i].clippedPolyToUTMZone);
+ } else {
+ var graphic = new Graphic(WebMercatorUtils.webMercatorToGeographic(polysToLoop[i].clippedPolyToUTMZone));
+ }
+ var label = this.grgPointByRefLabelFormat.value
+ label = label.replace(/Y/, polysToLoop[i].y);
+ label = label.replace(/X/, polysToLoop[i].x);
+ label = label.replace(/S/, polysToLoop[i].GZD);
+ label = label.replace(/Z/, polysToLoop[i].utmZone + polysToLoop[i].latitudeZone);
+ graphic.setAttributes({'grid': label});
+ features.push(graphic);
+ geomArray.push(graphic.geometry);
+ count++;
+ }
+ break;
+ }
+ //apply the edits to the feature layer
+ this.GRGArea.applyEdits(features, null, null);
+ var union = GeometryEngine.union(geomArray)
+ this.map.setExtent(union.getExtent().expand(2),false);
+ this.createGraphicDeleteMenu();
+ //we want to keep the point but not show it on the publish page, so just hide the layer
+ this._graphicsLayerGRGExtent.hide();
+ this._showPanel("publishPage");
+ }
+ }
+ },
+
+ /**
+ * Handle create GRG button being clicked on the GRG Area by Reference System Panel
+ **/
+ _grgAreaByRefSystemCreateGRGButtonClicked: function () {
+ //check form inputs for validity
+ if (this._graphicsLayerGRGExtent.graphics[0]) {
+ var numCellsHorizontal = parseInt(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent().getWidth()) / this.grgAreaByRefSystemGridSize.getValue();
+ var numCellsVertical = parseInt(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent().getHeight()) / this.grgAreaByRefSystemGridSize.getValue();
+ if(drawGRG.checkGridSize(numCellsHorizontal,numCellsVertical)){
+ var TRString, BRString;
+ var geomArray = [];
+ this._clearLayers(false);
+ // determine which UTM grid zones and bands fall within the extent
+ var zones = mgrsUtils.zonesFromExtent(this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent(),this.map);
+ var features = [];
+
+ switch(this.grgAreaByRefSystemGridSize.getValue()){
+ case 'UTM':
+ for (i = 0; i < zones.length; i++) {
+ if(this.grgAreaByRefSystemClipToggle.checked) {
+ if (this.map.spatialReference.wkid !== 4326) {
+ var graphic = new Graphic(zones[i].gridPolygon.clippedPolygon);
+ } else {
+ var graphic = new Graphic(WebMercatorUtils.webMercatorToGeographic(zones[i].gridPolygon.clippedPolygon));
+ }
+ } else {
+ if (this.map.spatialReference.wkid !== 4326) {
+ var graphic = new Graphic(WebMercatorUtils.geographicToWebMercator(zones[i].gridPolygon.unclippedPolygon));
+ } else {
+ var graphic = new Graphic(zones[i].gridPolygon.unclippedPolygon);
+ }
+ }
+ geomArray.push(graphic.geometry);
+ var label = this.grgAreaByRefLabelFormat.value
+ label = label.replace(/Z/, zones[i].gridPolygon.text);
+ graphic.setAttributes({'grid': label});
+ features.push(graphic);
+ }
+ break;
+ default:
+ var polysToLoop = mgrsUtils.processZonePolygons(zones, this.map, 100000,this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent());
+ var currentValue = 10000;
+ while (currentValue >= this.grgAreaByRefSystemGridSize.getValue()) {
+ var polys = [];
+ for (i = 0; i < polysToLoop.length; i++) {
+ polys = polys.concat(mgrsUtils.handleGridSquares(polysToLoop[i],this.map, currentValue, this._graphicsLayerGRGExtent.graphics[0].geometry.getExtent()));
+ }
+ polysToLoop = [];
+ polysToLoop = polys;
+ currentValue = currentValue / 10;
+ }
+
+ var count = 1;
+ for (i = 0; i < polysToLoop.length; i++) {
+ if(this.grgAreaByRefSystemClipToggle.checked) {
+ if (this.map.spatialReference.wkid !== 4326) {
+ var graphic = new Graphic(polysToLoop[i].clippedPolygon);
+ } else {
+ var graphic = new Graphic(WebMercatorUtils.webMercatorToGeographic(polysToLoop[i].clippedPolygon));
+ }
+ geomArray.push(graphic.geometry);
+ } else {
+ if (this.map.spatialReference.wkid !== 4326) {
+ var graphic = new Graphic(polysToLoop[i].clippedPolyToUTMZone);
+ } else {
+ var graphic = new Graphic(WebMercatorUtils.webMercatorToGeographic(polysToLoop[i].clippedPolyToUTMZone));
+ }
+ geomArray.push(graphic.geometry);
+ }
+ var label = this.grgAreaByRefLabelFormat.value
+ label = label.replace(/Y/, polysToLoop[i].y);
+ label = label.replace(/X/, polysToLoop[i].x);
+ label = label.replace(/S/, polysToLoop[i].GZD);
+ label = label.replace(/Z/, polysToLoop[i].utmZone + polysToLoop[i].latitudeZone);
+ graphic.setAttributes({'grid': label});
+ features.push(graphic);
+ count++;
+ }
+ break;
+ }
+ //apply the edits to the feature layer
+ this.GRGArea.applyEdits(features, null, null);
+ var union = GeometryEngine.union(geomArray)
+ this.map.setExtent(union.getExtent().expand(2),false);
+ this.createGraphicDeleteMenu();
+ //we want to keep the extent but not show it on the publish page, so just hide the layer
+ this._graphicsLayerGRGExtent.hide();
+ this._showPanel("publishPage");
+ }
+ }
+ },
+
+ /**
+ * Create right click context delete option on graphics
+ **/
+ createGraphicDeleteMenu: function () {
+ // Creates right-click context menu for GRAPHICS
+ ctxMenuForGraphics = new Menu({});
+
+ ctxMenuForGraphics.addChild(new MenuItem({
+ label: "Delete",
+ onClick: lang.hitch(this, function() {
+ this.GRGArea.remove(selected);
+ //refresh each of the feature/graphic layers to enusre labels are removed
+ this.GRGArea.refresh();
+ })
+ }));
+
+ ctxMenuForGraphics.startup();
+
+ this.GRGArea.on("mouse-over", function(evt) {
+ selected = evt.graphic;
+ ctxMenuForGraphics.bindDomNode(evt.graphic.getDojoShape().getNode());
+ });
+
+ this.GRGArea.on("mouse-out", function(evt) {
+ ctxMenuForGraphics.unBindDomNode(evt.graphic.getDojoShape().getNode());
+ });
+ },
+
+
+ /**
+ * Handle different theme styles
+ **/
+ //source:
+ //https://stackoverflow.com/questions/9979415/dynamically-load-and-unload-stylesheets
+ _removeStyleFile: function (filename, filetype) {
+ //determine element type to create nodelist from
+ var targetelement = null;
+ if (filetype === "js") {
+ targetelement = "script";
+ } else if (filetype === "css") {
+ targetelement = "link";
+ } else {
+ targetelement = "none";
+ }
+ //determine corresponding attribute to test for
+ var targetattr = null;
+ if (filetype === "js") {
+ targetattr = "src";
+ } else if (filetype === "css") {
+ targetattr = "href";
+ } else {
+ targetattr = "none";
+ }
+ var allsuspects = document.getElementsByTagName(targetelement);
+ //search backwards within nodelist for matching elements to remove
+ for (var i = allsuspects.length; i >= 0; i--) {
+ if (allsuspects[i] &&
+ allsuspects[i].getAttribute(targetattr) !== null &&
+ allsuspects[i].getAttribute(targetattr).indexOf(filename) !== -1) {
+ //remove element by calling parentNode.removeChild()
+ allsuspects[i].parentNode.removeChild(allsuspects[i]);
+ }
+ }
+ },
+
+ _setTheme: function () {
+ //Check if DartTheme
+ if (this.appConfig.theme.name === "DartTheme") {
+ //Load appropriate CSS for dart theme
+ utils.loadStyleLink('darkOverrideCSS', this.folderUrl + "css/dartTheme.css", null);
+ } else {
+ this._removeStyleFile(this.folderUrl + "css/dartTheme.css", 'css');
+ }
+ //Check if DashBoardTheme
+ if (this.appConfig.theme.name === "DashboardTheme" && this.appConfig.theme.styles[0] === "default"){
+ //Load appropriate CSS for dashboard theme
+ utils.loadStyleLink('darkDashboardOverrideCSS', this.folderUrl + "css/dashboardTheme.css", null);
+ } else {
+ this._removeStyleFile(this.folderUrl + "css/dashboardTheme.css", 'css');
+ }
+ },
+
+ /**
+ * Handle widget being destroyed
+ * Primarly needed when in WAB configuration mode
+ **/
+ destroy: function() {
+ this.inherited(arguments);
+ this.map.removeLayer(this._graphicsLayerGRGExtent);
+ this.map.removeLayer(this.GRGArea);
+ console.log('grg widget distroyed')
+ },
+
+ /**
+ * Handle publish GRG to portal
+ **/
+ _initSaveToPortal: function(layerName) {
+ esriId.registerOAuthInfos();
+ var featureServiceName = layerName;
+ esriId.getCredential(this.appConfig.portalUrl + "/sharing", { oAuthPopupConfirmation: false }).then(lang.hitch(this, function() {
+ //sign in
+ new esriPortal.Portal(this.appConfig.portalUrl).signIn().then(lang.hitch(this, function(portalUser) {
+ //Get the token
+ var token = portalUser.credential.token;
+ var orgId = portalUser.orgId;
+ var userName = portalUser.username;
+
+ var checkServiceNameUrl = this.appConfig.portalUrl + "sharing/rest/portals/" + orgId + "/isServiceNameAvailable";
+ var createServiceUrl = this.appConfig.portalUrl + "sharing/content/users/" + userName + "/createService";
+
+ drawGRG.isNameAvailable(checkServiceNameUrl, token, featureServiceName).then(lang.hitch(this, function(response0) {
+ if (response0.available) {
+ //set the widget to busy
+ this.busyIndicator.show();
+ //create the service
+ drawGRG.createFeatureService(createServiceUrl, token, drawGRG.getFeatureServiceParams(featureServiceName, this.map)).then(lang.hitch(this, function(response1) {
+ if (response1.success) {
+ var addToDefinitionUrl = response1.serviceurl.replace(new RegExp('rest', 'g'), "rest/admin") + "/addToDefinition";
+ drawGRG.addDefinitionToService(addToDefinitionUrl, token, drawGRG.getLayerParams(featureServiceName, this.map, this._cellTextSymbol, this._GRGAreaFillSymbol)).then(lang.hitch(this, function(response2) {
+ if (response2.success) {
+ //Push features to new layer
+ var newFeatureLayer = new FeatureLayer(response1.serviceurl + "/0?token=" + token, {
+ id: featureServiceName,
+ outFields: ["*"],
+
+ });
+ this.map.addLayers([newFeatureLayer]);
+
+ //must ensure the layer is loaded before we can access it to turn on the labels if required
+ if(newFeatureLayer.loaded){
+ // show or hide labels
+ featureLayerInfo = jimuLayerInfos.getInstanceSync().getLayerInfoById(featureServiceName);
+ featureLayerInfo.enablePopup();
+ if(this._showLabels) {
+ featureLayerInfo.showLabels();
+ }
+ } else {
+ newFeatureLayer.on("load", lang.hitch(this, function () {
+ // show or hide labels
+ featureLayerInfo = jimuLayerInfos.getInstanceSync().getLayerInfoById(featureServiceName);
+ featureLayerInfo.enablePopup();
+ if(this._showLabels) {
+ featureLayerInfo.showLabels();
+ }
+ }));
+ }
+
+ var newGraphics = [];
+ array.forEach(this.GRGArea.graphics, function (g) {
+ newGraphics.push(new Graphic(g.geometry, null, {grid: g.attributes["grid"]}));
+ }, this);
+ newFeatureLayer.applyEdits(newGraphics, null, null).then(lang.hitch(this, function(){
+ this._reset();
+ })).otherwise(lang.hitch(this,function(){
+ this._reset();
+ }));
+ this.busyIndicator.hide();
+ var newURL = '';
+ this.publishMessage.innerHTML = this.nls.successfullyPublished.format(newURL) + ' ';
+
+ }
+ }), function(err2) {
+ this.busyIndicator.hide();
+ this.publishMessage.innerHTML = this.nls.addToDefinition.format(err2.message);
+ });
+ } else {
+ this.busyIndicator.hide();
+ this.publishMessage.innerHTML = this.nls.unableToCreate.format(featureServiceName);
+ }
+ }), function(err1) {
+ this.busyIndicator.hide();
+ this.publishMessage.innerHTML = this.nls.createService.format(err1.message);
+ });
+ } else {
+ this.busyIndicator.hide();
+ this.publishMessage.innerHTML = this.nls.publishingFailedLayerExists.format(featureServiceName);
+
+ }
+ }), function(err0) {
+ this.busyIndicator.hide();
+ this.publishMessage.innerHTML = this.nls.checkService.format(err0.message);
+ });
+ }))
+ }));
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/config.json b/GRG/config.json
new file mode 100644
index 0000000..08c7b2c
--- /dev/null
+++ b/GRG/config.json
@@ -0,0 +1,34 @@
+{
+ "grg": {
+ "cellFill": {
+ "color": "#ffffff",
+ "transparency": 1
+ },
+ "cellOutline": {
+ "color": "#000080",
+ "transparency": 0
+ },
+ "cellShape": "default",
+ "cellUnits": "meters",
+ "gridOrigin": "center",
+ "font": {
+ "font": {
+ "fontFamily": "Arial",
+ "bold": true,
+ "italic": false,
+ "underline": false
+ },
+ "fontSize": "12",
+ "textColor": "#000000",
+ "haloSize": "1",
+ "haloColor": "#ffffff",
+ "haloOn": true,
+ "labelTransparency": 0
+ },
+ "labelType": "alphaNumeric",
+ "labelDirection": "horizontal",
+ "labelOrigin": "lowerLeft",
+ "referenceSystem": "MGRS",
+ "lockSettings": false
+ }
+}
\ No newline at end of file
diff --git a/GRG/css/dartTheme.css b/GRG/css/dartTheme.css
new file mode 100644
index 0000000..d1b6b61
--- /dev/null
+++ b/GRG/css/dartTheme.css
@@ -0,0 +1,175 @@
+.dijitSelect .dijitArrowButton
+{
+ background-color: #fafafc;
+ border-color: #fafafc;
+}
+
+.jimu-widget-GRGDrafter .dijitSelect .dijitButtonContents
+{
+ background-color: transparent;
+ border-color: #fafafc;
+}
+
+.jimu-widget-GRGDrafter .dijitSelectDisabled,
+.jimu-widget-GRGDrafter .dijitTextBoxDisabled,
+.jimu-widget-GRGDrafter .dijitTextBoxDisabled .dijitInputContainer ,
+.jimu-widget-GRGDrafter .dijitTextBoxDisabled {
+ background-color: #4c4c4c;
+}
+
+.claro .dartThemeClaroDijitTooltipContainerOverride .dijitTooltipContainer {
+ background-color: #4c4c4c;
+ background-image: -webkit-linear-gradient(bottom, rgb(76, 76, 76) 0px, #4c4c4c 10px);
+ border: 1px solid #ffffff;
+ color: #ffffff;
+}
+
+
+.claro .dartThemeClaroDijitTooltipContainerOverride .dijitTooltipConnector {
+ background-image: url(images/tooltip.png);
+}
+
+/* dojo color picker */
+
+.jimu-colorpalette {
+ background-color: #4c4c4c;
+}
+
+.jimu-color-picker-dialog .dijitTooltipContainer {
+ background-color: #4c4c4c !important;
+}
+
+.claro .dojoxColorPicker, .claro .dijitColorPalette {
+ background: #4c4c4c;
+}
+
+
+/*dojo dialog box*/
+.claro .dijitDialog {
+ background-color: #4c4c4c;
+}
+
+.claro .dijitDialogTitle {
+ color: #fff;
+}
+
+.claro .dijitDialogPaneActionBar {
+ background-color: #4c4c4c;
+ border-top: none;
+}
+
+.claro .jimu-widget-subtitle {
+ color: #ffffff;
+}
+.claro .dijitDialogTitleBar {
+ border: 0px solid #222;
+ border-bottom: 1px solid #000;
+ background-color: #222;
+ background-image: none;
+}
+
+.claro .dijitDialogPaneContent {
+ background-color: #4c4c4c;
+ border: 0px solid #222;
+ color: #fff;
+}
+
+.claro .dijitDialogPaneContent {
+ float: right;
+}
+
+/*Button*/
+
+.claro .dijitButton .dijitButtonNode {
+ color: #ffffff !important;
+ border: 0px solid #000000;
+ background-image: none;
+ background-color: rgba(0, 0, 0, 0.5) !important;
+ padding: 5px 18px 8px 18px;
+ font-size: 14px;
+}
+.claro .dijitButtonHover .dijitButtonNode {
+ background-color: rgba(0, 0, 0, 0.75) !important;
+}
+
+.jimu-widget-GRGDrafter .settingBtn {
+ display: inline-block;
+ background: url(./images/settings_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 15px;
+ height: 15px;
+ margin-top: 7px;
+ margin-left: 5px;
+ margin-bottom: -3px;
+}
+
+.jimu-widget-GRGDrafter .settingBtn:hover {
+ background: url('./images/settings_white_hover.png');
+}
+
+.jimu-widget-GRGDrafter .editBtn {
+ display: right;
+ background: url(./images/draw_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .editBtn:hover {
+ background: url('./images/draw_white_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-edit-active {
+ background: url('./images/draw_white_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .polygonBtn {
+ display: inline-block;
+ background: url(./images/polygon_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .polygonBtn:hover {
+ background: url('./images/polygon_white_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-polygon-active {
+ background: url('./images/polygon_white_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .extentBtn {
+ display: inline-block;
+ background: url(./images/extent_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .extentBtn:hover {
+ background: url('./images/extent_white_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-extent-active {
+ background: url('./images/extent_white_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+
+.claro .dijitSliderImageHandle, .claro .dijitSliderImageHandle:after {
+ background: transparent;
+ margin-top: 0px;
+}
\ No newline at end of file
diff --git a/GRG/css/dashboardTheme.css b/GRG/css/dashboardTheme.css
new file mode 100644
index 0000000..0b72006
--- /dev/null
+++ b/GRG/css/dashboardTheme.css
@@ -0,0 +1,275 @@
+/* dropdown / select menus */
+.jimu-widget-GRGDrafter .dijitSelect .dijitArrowButton
+{
+ background-color: transparent;
+ border-color: #fafafc;
+}
+
+.jimu-widget-GRGDrafter .dijitSelect .dijitButtonContents
+{
+ background-color: transparent;
+}
+
+/* disabled input boxes */
+.jimu-widget-GRGDrafter .claro .dijitSelectHover,
+.jimu-widget-GRGDrafter .claro .dijitSelectFocused{
+ border: 1px solid #00f;
+}
+
+.jimu-widget-GRGDrafter .dijitTextBoxDisabled .dijitInputContainer {
+ background-color: transparent;
+}
+
+.claro .dijitTextBoxHover {
+ background-color: #222;
+}
+
+.claro .dijitTextBoxFocused .dijitInputContainer {
+ background: #222;
+}
+
+/* button icons */
+
+.jimu-widget-GRGDrafter .settingBtn {
+ display: inline-block;
+ background: url(./images/settings_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 15px;
+ height: 15px;
+ margin-top: 7px;
+ margin-left: 5px;
+ margin-bottom: -3px;
+}
+
+.jimu-widget-GRGDrafter .settingBtn:hover {
+ background: url('./images/settings_white_hover.png');
+}
+
+.jimu-widget-GRGDrafter .editBtn {
+ float: right;
+ background: url(./images/draw_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .editBtn:hover {
+ background: url('./images/draw_white_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-edit-active {
+ background: url('./images/draw_white_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .polygonBtn {
+ display: inline-block;
+ background: url(./images/polygon_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .polygonBtn:hover {
+ background: url('./images/polygon_white_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-polygon-active {
+ background: url('./images/polygon_white_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .extentBtn {
+ display: inline-block;
+ background: url(./images/extent_white.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .extentBtn:hover {
+ background: url('./images/extent_white_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-extent-active {
+ background: url('./images/extent_white_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+/* dojo color picker */
+
+.jimu-colorpalette {
+ background-color: #222;
+}
+
+.jimu-color-picker-dialog .dijitTooltipContainer {
+ background-color: #222 !important;
+}
+
+.claro .dojoxColorPicker {
+ background: #222;
+}
+
+/* dojo select */
+
+.claro .dijitSelect{
+ background-color: #222;
+}
+.claro .dijitSelectHover,
+.claro .dijitSelectFocused{
+ border: 1px solid #999;
+}
+.claro .dijitSelect .dijitArrowButton {
+ background-color: #222;
+}
+.claro .dijitMenu{
+ border:1px solid #999;
+}
+.claro .dijitMenu .dijitMenuItem{
+ color: #fff;
+}
+.claro .dijitMenu .dijitMenuItem,
+.claro .dijitMenu .dijitMenuItem td{
+ background-color: #222;
+ border: 1px solid #222;
+ font-weight: normal;
+}
+.claro .dijitMenu .dijitMenuItem:hover,
+.claro .dijitMenu .dijitMenuItem:hover td
+ {
+ background: none;
+ background-color: #1e90ff;
+}
+.claro .dijitMenu .dijitMenuItemSelected td{
+ background: none;
+ background-color: #1e90ff;
+ font-weight: normal;
+ color: #fff;
+}
+.claro .dijitMenuItem .esriTravelModesTypeName{
+ color: #fff;
+}
+.claro .dijitMenuItem .dijitMenuItemSelected td:hover .esriTravelModesTypeName{
+ color: #666;
+}
+
+/*dojo dialog box*/
+
+.claro .dijitDialog {
+ background-color: #222;
+}
+.claro .dijitDialogTitle {
+ color: #fff;
+}
+
+.claro .dijitDialogPaneActionBar {
+ background-color: #222;
+ border-top: none;
+}
+
+.claro .dijitDialogTitleBar {
+ border: 0px solid #222;
+ border-bottom: 1px solid #000;
+ background-color: #222;
+ background-image: none;
+}
+.claro .dijitTooltipContainer {
+ background-color: #222;
+ border: 1px solid #9a9a9a;
+ color: #fff;
+}
+
+.claro .dijitDialogPaneContent {
+ background-color: #222;
+ border: 0px solid #9a9a9a;
+ color: #fff;
+}
+.claro .dijitDialogPaneContent {
+ float: right;
+}
+
+/*tab*/
+
+.claro .dijitTab{
+ background: #222;
+ color: white;
+}
+.claro .dijitTabContainerTop-tabs .dijitTabChecked{
+ background: #333;
+}
+.claro .dijitTabContainerTop-dijitContentPane{
+ background: #222;
+ color: white;
+}
+
+/*ComboBox*/
+
+.claro .dijitComboBox .dijitButtonNode,
+.claro .dijitSelect .dijitArrowButton {
+ background-image: none;
+ background-color: transparent;
+}
+
+.claro .dijitComboBox .dijitArrowButtonContainer,
+.claro .dijitSelect .dijitArrowButtonContainer {
+ border-width: 0 !important;
+}
+
+.claro .dijitSelect .dijitButtonContents {
+ border-style: none;
+}
+
+/*Button*/
+
+.claro .dijitButton .dijitButtonNode {
+ border: 0px solid #000000;
+ background-image: none;
+ background-color: #666;
+ padding: 5px 18px 8px 18px;
+ font-size: 14px;
+}
+
+.claro .dijitButtonHover .dijitButtonNode {
+ background-color: #333;
+}
+
+/*tree*/
+
+.claro .dijitTreeRow{
+ background-color: #333;
+ color: white;
+}
+
+.claro .dijitTabPaneWrapper, .claro .dijitToolbar{
+ background-color: #222;
+}
+
+.claro .dijitToolbar .dijitToggleButtonChecked .dijitButtonNode{
+ background-color: #666;
+}
+.claro .dijitDropDownButton .dijitButtonNode,
+.claro .dijitButton .dijitButtonNode,
+.claro .dijitToggleButton .dijitButtonNode{
+ color: white;
+}
+.claro .dijitButtonDisabled .dijitButtonNode{
+ color: #bbb;
+}
+
+.claro .dgrid-header, .dgrid-header-row, .dgrid-footer {
+ background-color: #222;
+}
+
+.claro .dijitTooltipConnector{
+ background-image: url(images/tooltip_dark.png);
+}
\ No newline at end of file
diff --git a/GRG/css/images/draw_default.png b/GRG/css/images/draw_default.png
new file mode 100644
index 0000000..dd1001f
Binary files /dev/null and b/GRG/css/images/draw_default.png differ
diff --git a/GRG/css/images/draw_gray_hover.png b/GRG/css/images/draw_gray_hover.png
new file mode 100644
index 0000000..bb5885b
Binary files /dev/null and b/GRG/css/images/draw_gray_hover.png differ
diff --git a/GRG/css/images/draw_white.png b/GRG/css/images/draw_white.png
new file mode 100644
index 0000000..ebdc2a2
Binary files /dev/null and b/GRG/css/images/draw_white.png differ
diff --git a/GRG/css/images/draw_white_hover.png b/GRG/css/images/draw_white_hover.png
new file mode 100644
index 0000000..ee952d0
Binary files /dev/null and b/GRG/css/images/draw_white_hover.png differ
diff --git a/GRG/css/images/extent_default.png b/GRG/css/images/extent_default.png
new file mode 100644
index 0000000..a7929b2
Binary files /dev/null and b/GRG/css/images/extent_default.png differ
diff --git a/GRG/css/images/extent_gray_hover.png b/GRG/css/images/extent_gray_hover.png
new file mode 100644
index 0000000..c70f50c
Binary files /dev/null and b/GRG/css/images/extent_gray_hover.png differ
diff --git a/GRG/css/images/extent_white.png b/GRG/css/images/extent_white.png
new file mode 100644
index 0000000..659029a
Binary files /dev/null and b/GRG/css/images/extent_white.png differ
diff --git a/GRG/css/images/extent_white_hover.png b/GRG/css/images/extent_white_hover.png
new file mode 100644
index 0000000..6da2d42
Binary files /dev/null and b/GRG/css/images/extent_white_hover.png differ
diff --git a/GRG/css/images/help_default.png b/GRG/css/images/help_default.png
new file mode 100644
index 0000000..a2e4864
Binary files /dev/null and b/GRG/css/images/help_default.png differ
diff --git a/GRG/css/images/polygon_default.png b/GRG/css/images/polygon_default.png
new file mode 100644
index 0000000..5930381
Binary files /dev/null and b/GRG/css/images/polygon_default.png differ
diff --git a/GRG/css/images/polygon_gray_hover.png b/GRG/css/images/polygon_gray_hover.png
new file mode 100644
index 0000000..ab2b5c6
Binary files /dev/null and b/GRG/css/images/polygon_gray_hover.png differ
diff --git a/GRG/css/images/polygon_white.png b/GRG/css/images/polygon_white.png
new file mode 100644
index 0000000..6effb3b
Binary files /dev/null and b/GRG/css/images/polygon_white.png differ
diff --git a/GRG/css/images/polygon_white_hover.png b/GRG/css/images/polygon_white_hover.png
new file mode 100644
index 0000000..31914d4
Binary files /dev/null and b/GRG/css/images/polygon_white_hover.png differ
diff --git a/GRG/css/images/settings_black.png b/GRG/css/images/settings_black.png
new file mode 100644
index 0000000..a4c3d4e
Binary files /dev/null and b/GRG/css/images/settings_black.png differ
diff --git a/GRG/css/images/settings_black_hover_black.png b/GRG/css/images/settings_black_hover_black.png
new file mode 100644
index 0000000..60e13aa
Binary files /dev/null and b/GRG/css/images/settings_black_hover_black.png differ
diff --git a/GRG/css/images/settings_white.png b/GRG/css/images/settings_white.png
new file mode 100644
index 0000000..d75613f
Binary files /dev/null and b/GRG/css/images/settings_white.png differ
diff --git a/GRG/css/images/settings_white_hover.png b/GRG/css/images/settings_white_hover.png
new file mode 100644
index 0000000..513ee25
Binary files /dev/null and b/GRG/css/images/settings_white_hover.png differ
diff --git a/GRG/css/images/sprite.png b/GRG/css/images/sprite.png
new file mode 100644
index 0000000..17ab0b6
Binary files /dev/null and b/GRG/css/images/sprite.png differ
diff --git a/GRG/css/images/tooltip.png b/GRG/css/images/tooltip.png
new file mode 100644
index 0000000..96ce16e
Binary files /dev/null and b/GRG/css/images/tooltip.png differ
diff --git a/GRG/css/style.css b/GRG/css/style.css
new file mode 100644
index 0000000..8de3999
--- /dev/null
+++ b/GRG/css/style.css
@@ -0,0 +1,958 @@
+
+
+/*------------------------- Styles for widget panel -----------------------*/
+.GRGDrafterMainContainer
+{
+ min-width: 222px;
+ height: 100%;
+ /**-webkit-overflow-scrolling: touch;
+ overflow: hidden;**/
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterFullHeight
+{
+ height: 100%;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterFullWidth
+{
+ width: 100%;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterFullWidthAndPadding
+{
+ width: 100%;
+ padding-top: 12px;
+ padding-bottom: 8px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterHalfWidthLeft
+{
+ width: 50%;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterHalfWidthRight
+{
+ padding-left: 10px;
+ width: 50%;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterHalfWidthContainer
+{
+ display: flex;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterEllipsis
+{
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.jimu-widget-GRGDrafter .labelLeft
+{
+ display: inline-flex;
+ float: left;
+}
+
+.jimu-widget-GRGDrafter .labelRight
+{
+ display: inline-flex;
+ float: right;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterPointer
+{
+ cursor: pointer;
+}
+
+/*------------------------- Styles for Main Page starts-----------------------*/
+.jimu-widget-GRGDrafter .GRGDrafterMainPageRow
+{
+ width: calc(100% - 20px);
+ margin: 10px 10px 10px 10px;
+ display: inline-block;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterMainPageRowItem {
+ width: calc(100% - 40px);
+ margin: 5px 25px 5px 25px;
+ display: inline-block;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterButtonLabel
+{
+ float: left;
+ width: calc(100% - 30px);
+ padding: 5px 5px 0px 0;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterDoubleButtonLabel
+{
+ float: left;
+ width: calc(100% - 64px);
+ padding: 5px 5px 0px 0;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterToggleLabel
+{
+ float: left;
+ width: calc(100% - 35px);
+ padding: 5px 5px 0px 0;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterInputLabel
+{
+ float: left;
+ line-height: 28px;
+ padding: 5px 5px 0px 0;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterNewGRGPointButton
+{
+ background: url("../images/down-arrow.png") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterNewGRGAreaButton
+{
+ background: url("../images/down-arrow.png") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterNewGRGAreaBySizeButton
+{
+ background: url("../images/bySize.png") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterNewGRGPointBySizeButton
+{
+ background: url("../images/bySize.png") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterNewGRGAreaByRefSystemButton
+{
+ background: url("../images/globe.png") no-repeat;
+}
+
+
+.jimu-widget-GRGDrafter .GRGDrafterMainMenuDropDownIcon
+{
+ margin-top: 10px;
+ height: 20px;
+ width: 20px;
+ background-size: 20px;
+ float: right;
+ background-repeat: no-repeat;
+}
+
+
+.jimu-widget-GRGDrafter .GRGDrafterButtonIcon
+{
+ height: 45px;
+ width: 45px;
+ float: right;
+ background-size: 45px;
+}
+
+.esriRtl .jimu-widget-GRGDrafter .GRGDrafterButtonIcon
+{
+ float: left;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterPublishMessage {
+ float: left;
+ line-height: 16px;
+ padding: 18px 0px 0px 0;
+ font-weight: bold;
+}
+
+/*------------------------- Styles for Main Page End-----------------------*/
+
+/*------------------------- Styles for GRG Pages-----------------------*/
+.jimu-widget-GRGDrafter .claro .dijitSelect, .claro .dijitSelect .dijitButtonContents, .claro .dijitTextBox, {
+ width: calc(100% - 60px);
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterNewGRGHeader
+{
+ float: left;
+ height: 30px;
+ border-bottom: 1px solid #464646;
+ padding: 0px 10px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingsIcon
+{
+ background-image: url('../images/settings.png');
+ height: 20px;
+ width: 20px;
+ background-size: 20px;
+ float: right;
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .dijitTextBox .dijitInputInner
+{
+ height: 18px !important;
+ text-align: right;
+}
+
+.jimu-widget-GRGDrafter .dijitTextBoxFocused .dijitInputContainer
+{
+ background: transparent;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterHidden
+{
+ display: none;
+}
+
+.claro .dijitTextBox {
+ width: calc(100% - 60px);
+}
+
+/*------------------------- Styles for GRG Pages End-----------------------*/
+
+/*------------------------- Styles for GRG Settings-----------------------*/
+.jimu-widget-GRGDrafter .GRGDrafterSettingsRow {
+ width: 100%;
+ display: inline-block;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingsButtonIcon {
+ margin-top: 10px;
+ height: 20px;
+ width: 25px;
+ float: right;
+ background-size: 45px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterLabelSettingsDownButton
+{
+ background: url("../images/down-arrow.png") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterLabelSettingsUpButton
+{
+ background: url("../images/up-arrow.png") no-repeat;
+}
+
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingsNode
+{
+ width: 100%;
+ height: calc(100% - 30px);
+ display: inline-block;
+ overflow-y: auto;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingsContainer
+{
+ margin: 10px;
+ display: inline-block;
+ width: calc(100% - 20px);
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingRow
+{
+ padding-bottom: 6px;
+ padding-top: 6px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingRowPaddingTop20
+{
+ padding-top: 20px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingRowDouble
+{
+ padding-bottom: 12px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterDropdownLabel
+{
+ padding-bottom: 5px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterSettingHeader
+{
+ float: left;
+ height: 30px;
+ border-bottom: 1px solid #464646;
+ padding: 0px 10px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterBackButton
+{
+ width: 25%;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterTitleDiv
+{
+ line-height: 10px;
+ font-weight: bold;
+ text-align: center;
+ width: calc(100% - 50px);
+ padding: 5px;
+ display: inline-block;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterItemLeftArrow
+{
+ background-image: url('../images/left-arrow.png');
+ float: left;
+ margin: 0px 5px 0px 0px;
+ width: 15px;
+ height: 20px;
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+
+/* overriding CSS for the dijitSelect box starts */
+.jimu-widget-GRGDrafter .dijitSelect .dijitButtonContents
+{
+ border-style: none none none none;
+ background-color: #fafafc;
+}
+
+.jimu-widget-GRGDrafter .dijitSelect .dijitButtonContentsDartTheme {
+ background-color: inherit;
+}
+
+.jimu-widget-GRGDrafter .dijitSelect .dijitArrowButton
+{
+ background-color: #fafafc;
+ background-image: none;
+ border-color: #fafafc;
+}
+
+.jimu-widget-GRGDrafter .dijitSelect .dijitArrowButtonDartTheme {
+ background-color: rgba(0, 0, 0, 0.5) !important;
+}
+
+.jimu-widget-GRGDrafter .dijitMenuItem
+{
+ color: #7989a0;
+}
+
+.jimu-widget-GRGDrafter .dijitSelect .dijitInputField
+{
+ margin-right: 8px;
+}
+
+
+.jimu-widget-GRGDrafter .switch-toggle-group {
+ padding: 5px;
+}
+.jimu-widget-GRGDrafter .switch-toggle-group .checkbox-inline {
+ padding-left: 36px;
+ vertical-align: top;
+}
+.jimu-widget-GRGDrafter .switch-toggle-group .switch-toggle.dijitCheckBox {
+ margin-left: -36px;
+}
+
+.jimu-widget-GRGDrafter .switch-toggle.dijitCheckBox {
+ height: 16px;
+ width: 28px;
+ border: 0 none;
+ background: #e04f1d;
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+}
+.jimu-widget-GRGDrafter .switch-toggle.dijitCheckBox:before {
+ content: "";
+ background: #f8f8f8;
+ position: absolute;
+ padding: 0;
+ height: 12px;
+ width: 12px;
+ left: auto;
+ right: 2px;
+ top: 2px;
+ z-index: 1;
+ -webkit-transition: right 0.3s;
+ -moz-transition: right 0.3s;
+ -o-transition: right 0.3s;
+ transition: right 0.3s;
+ -moz-border-radius: 50%;
+ -webkit-border-radius: 50%;
+ border-radius: 50%;
+}
+.jimu-widget-GRGDrafter .switch-toggle.dijitCheckBox input {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ z-index: 2;
+}
+.jimu-widget-GRGDrafter .switch-toggle.dijitCheckBox.dijitCheckBoxChecked {
+ background: #50ad4e;
+}
+.jimu-widget-GRGDrafter .switch-toggle.dijitCheckBox.dijitCheckBoxChecked:before {
+ right: 14px;
+}
+
+
+
+
+
+/* overriding CSS for the dijitSelect box starts */
+
+/*------------------------- Styles for Settings Panel-----------------------*/
+
+.jimu-widget-GRGDrafter .dijitTextBox .dijitPlaceHolder{
+ font-size: 12px;
+}
+
+.jimu-widget-GRGDrafter .dijitTextBoxError {
+ border-color: #d9dde0 !important;
+ box-shadow: inset 0 0 0 2px #d46464;
+}
+
+/* CSS for RTL Mode Starts */
+
+.esriRtl .jimu-widget-GRGDrafter .GRGDrafterInputLabel
+{
+ float: right;
+ padding: 5px 5px 0px 0px;
+}
+
+.esriRtl .jimu-widget-GRGDrafter .GRGDrafterItemLeftArrow
+{
+ float: right;
+ margin: 0px 0px 00px 10px;
+}
+
+.esriRtl .jimu-widget-GRGDrafter .GRGDrafterSettingsIcon
+{
+ float: left;
+}
+
+.esriRtl .jimu-widget-GRGDrafter .GRGDrafterItemLeftArrow
+{
+ background-image: url('../images/right-arrow.png');
+}
+
+.esriRtl .jimu-widget-GRGDrafter .dijitSelect .dijitInputField
+{
+ margin-left: 8px;
+ margin-right: 0;
+}
+
+.SettingsLastRow {
+ border-bottom: 1px solid #464646;
+ padding-bottom: 15px !important;
+}
+
+.SubTitle {
+ font-weight: bold;
+}
+
+/* CSS for RTL Mode Ends */
+
+/*------------------------- Styles for widget panel -----------------------*/
+
+.jimu-widget-GRGDrafter .settingBtn {
+ display: inline-block;
+ background: url(./images/settings_black.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 15px;
+ height: 15px;
+ margin-top: 7px;
+ margin-left: 5px;
+ margin-bottom: -3px;
+}
+
+.jimu-widget-GRGDrafter .settingBtn:hover {
+ background: url('./images/settings_black_hover_black.png');
+}
+
+.jimu-widget-GRGDrafter .editBtn {
+ float: right;
+ background: url(./images/draw_default.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .editBtn:hover {
+ background: url('./images/draw_gray_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-edit-active {
+ background: url('./images/draw_gray_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .helpBtn {
+ float: right;
+ background: url(./images/help_default.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 16px;
+ height: 16px;
+ margin-top: 6px;
+}
+
+.jimu-widget-GRGDrafter .helpBtn:hover{
+ cursor: help;
+}
+
+.jimu-widget-GRGDrafter .polygonBtn {
+ display: inline-block;
+ background: url(./images/polygon_default.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .polygonBtn:hover {
+ background: url('./images/polygon_gray_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-polygon-active {
+ background: url('./images/polygon_gray_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .extentBtn {
+ display: inline-block;
+ background: url(./images/extent_default.png);
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 30px;
+ height: 30px;
+}
+
+.jimu-widget-GRGDrafter .extentBtn:hover {
+ background: url('./images/extent_gray_hover.png');
+ background-repeat: no-repeat;
+}
+
+.jimu-widget-GRGDrafter .jimu-extent-active {
+ background: url('./images/extent_gray_hover.png');
+ background-repeat: no-repeat;
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .add-with-icon {
+ vertical-align: text-top !important;
+}
+
+
+.btnContainer {
+ text-align: right;
+ margin-top: 15px;
+}
+
+.jimu-widget-GRGDrafter .GRGDrafterBtnContainer {
+ text-align: right;
+ margin-top: 15px;
+ display: grid;
+}
+
+.jimu-widget-GRGDrafter .controlGroupHidden {
+ display: none;
+}
+
+.jimu-widget-GRGDrafter .controlItem {
+ display: flex;
+}
+
+.jimu-widget-GRGDrafter .jimu-btn {
+ margin-bottom: 6px;
+}
+
+/*------------------------- Styles for colorPickerEditor -----------------------*/
+
+.jimu-widget-GRGDrafter .dijitSlider {
+ width: calc(100% - 212px);
+}
+
+.jimu-widget-GRGDrafter .dijitSlider {
+ margin-left: 10px;
+ margin-right: auto;
+ margin-top: 14px;
+}
+
+.jimu-rtl .jimu-widget-GRGDrafter .dijitSlider {
+ margin-left: auto;
+ margin-right: 10px;
+}
+
+.jimu-widget-GRGDrafter .dijitSlider .dijitSliderImageHandleH {
+ top: -10px;
+ width: 20px;
+ height: 20px;
+}
+
+.jimu-widget-GRGDrafter .colorPickerEditor .jimu-color-picker{
+ display: inline-block;
+ width: 25px;
+ height: 25px;
+}
+.jimu-widget-GRGDrafter .colorPickerEditor .dijitSpinner.dijitNumberTextBox.dijitValidationTextBox{
+ width:65px;
+ height:30px;
+}
+
+.jimu-widget-GRGDrafter .dijitSliderImageHandleH{
+ top: -7px;
+}
+
+.jimu-widget-GRGDrafter .dijitSliderThumbHover{
+ background-image: url("../images/sliderball_hover.png");
+ background-position: 0 0;
+}
+
+.jimu-widget-GRGDrafter .dijitSliderImageHandle.dijitSliderImageHandleH {
+ background-image: url("../images/sliderball.svg");
+ background-position: 0 0;
+}
+
+.jimu-widget-GRGDrafter .dijitSliderImageHandle.dijitSliderImageHandleH.dojoMoveItem {
+ background-image: url("../images/sliderball_hold.svg");
+ background-position: 0 0;
+}
+
+/*left*/
+.jimu-widget-GRGDrafter .dijitSlider .dijitSliderProgressBarH,
+.jimu-widget-GRGDrafter .dijitSlider .dijitSliderLeftBumper{
+ border-color: #24b5cc;
+ background-color: #24b5cc;
+ background-image: -webkit-linear-gradient(top, #24b5cc 0px, #24b5cc 1px, rgba(255, 255, 255, 0) 2px);
+ background-image: -o-linear-gradient(top, #24b5cc 0px, #24b5cc 1px, rgba(255, 255, 255, 0) 2px);
+ background-image: linear-gradient(top, #24b5cc 0px, #24b5cc 1px, rgba(255, 255, 255, 0) 2px);
+}
+.jimu-widget-GRGDrafter .dijitSlider .dijitSliderRemainingBarH,
+.jimu-widget-GRGDrafter .dijitSlider .dijitSliderRightBumper{
+ border-color: #d7d7d7;
+ background-color: #d7d7d7;
+}
+
+.jimu-widget-GRGDrafter .colorPickerEditor .trans{
+ font-family: "Avenir Light";
+ font-size: 12px;
+ padding: 0 5px 0 5px;
+ letter-spacing: 0.33px;
+}
+
+.jimu-widget-GRGDrafter .sliderbar {
+ width: 60px;
+}
+
+/*------------------------- Styles for Settings Font Styles -----------------------*/
+
+.jimu-widget-GRGDrafter .style-selector .clearFix {
+ *overflow: hidden;
+ *zoom: 1
+}
+
+.jimu-widget-GRGDrafter .style-selector .clearFix:after {
+ display: table;
+ content: "";
+ width: 0;
+ clear: both
+}
+
+.jimu-widget-GRGDrafter .style-selector .hide {
+ display: none
+}
+
+.jimu-widget-GRGDrafter .settings-container {
+}
+
+.jimu-widget-GRGDrafter .settings-container .title {
+ font-size: 14px;
+ color: #000000;
+ letter-spacing: 0.39px;
+ margin-bottom: 20px;
+}
+
+.jimu-widget-GRGDrafter .settings-container .label {
+ font-size: 12px;
+ color: #282828;
+ letter-spacing: 0.33px;
+ line-height: 30px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .label {
+ margin: 0 0;
+ max-width: 160px;
+ line-height: 30px;
+ font-size: 12px;
+ vertical-align: middle;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitTextBox,
+.jimu-widget-GRGDrafter .style-selector .dijitSelect {
+ width: 100%;
+ height: 30px;
+ border: 1px solid #D7D7D7;
+}
+
+.jimu-widget-GRGDrafter .style-selector .jimu-color-picker {
+ width: 40px !important;
+ height: 30px !important;
+ border: 1px solid #D7D7D7 !important;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitSelect .dijitArrowButtonContainer {
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitDownArrowButton .dijitButtonContents,
+.jimu-widget-GRGDrafter .style-selector .dijitComboBox .dijitDownArrowButton {
+ border: none;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitTextBox .dijitInputInner {
+ padding: 1px 0 0 0 !important;
+ font-size: 12px;
+ font-style: normal !important;
+ height: 28px;
+ line-height: 28px !important;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitSelectLabel {
+ font-size: 12px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitSelect,
+.jimu-widget-GRGDrafter .style-selector .dijitSelect .dijitButtonContents,
+.jimu-widget-GRGDrafter .style-selector .dijitTextBox,
+.jimu-widget-GRGDrafter .style-selector .dijitTextBox .dijitButtonNode {
+ background-color: transparent;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitSelect .dijitArrowButton {
+ background-color: transparent;
+}
+
+.jimu-widget-GRGDrafter .style-selector .dijitSelect .dijitInputField {
+ padding: 0px 10px;
+}
+
+.jimu-widget-GRGDrafter .jimu-image-chooser .display-text {
+ width: 100%;
+ font-size: 12px;
+ color: #4A4A4A;
+ letter-spacing: 0.33px;
+ background-color: #FFF;
+ text-align: center;
+}
+
+.jimu-image-chooser:hover .hint .display-text {
+ color: #FFF;
+}
+
+.jimu-widget-GRGDrafter .dijitTextBoxFocused {
+ border: 1px solid #D7D7D7 !important;
+ box-shadow: 0 0 0 0 !important;
+}
+
+.jimu-widget-GRGDrafter .dijitTextBox .dijitInputField {
+ padding: 2px 7px;
+}
+
+.jimu-widget-GRGDrafter .dijitSelectFocused .dijitArrowButton .dijitArrowButtonInner {
+ background-position: -35px 53%;
+}
+
+.jimu-widget-GRGDrafter .text-size .text-size-group>.dijitComboBox.dijitValidationTextBox {
+ width: 80px;
+}
+
+.jimu-widget-GRGDrafter .text-size .text-size-group>table {
+ width: 140px;
+}
+
+.jimu-widget-GRGDrafter .halo-size .halo-size-group>.dijitComboBox.dijitValidationTextBox {
+ width: 80px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .setting-items {
+ height: 30px;
+ width: 100%;
+ margin: 10px 0;
+ vertical-align: middle;
+ white-space: nowrap;
+}
+
+.jimu-widget-GRGDrafter .style-selector .setting-wapper {
+ width: 230px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .background-btn,
+.jimu-widget-GRGDrafter .style-selector .text-color-btn {
+ width: 40px;
+ height: 30px;
+ overflow: hidden;
+}
+
+.jimu-widget-GRGDrafter .style-selector .halo-color-btn {
+ width: 50px;
+ height: 30px;
+ overflow: hidden;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .align-group {
+ margin-right: 8px;
+ margin-left: -3px;
+}
+
+.jimu-rtl .jimu-widget-GRGDrafter .style-selector .align-group {
+ margin-right: -3px;
+ margin-left: 8px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .font-group-btns {
+ margin-left: 6px;
+ margin-right: 6px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .align-btn,
+.jimu-widget-GRGDrafter .style-selector .font-btn {
+ height: 30px;
+ margin: 0 3px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .font-btn {
+ width: 30px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .align-btn {
+ width: 30px;
+}
+
+.jimu-widget-GRGDrafter .style-selector .image-btn {
+ width: 120px;
+ height: 30px;
+ border: 1px solid #D7D7D7;
+}
+
+.jimu-widget-GRGDrafter .style-selector .bold {
+ background: url("../images/B.svg") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .style-selector .bold.selected {
+ background: url("../images/B_selected.svg") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .style-selector .italic {
+ background: url("../images/I.svg") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .style-selector .italic.selected {
+ background: url("../images/I_selected.svg") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .style-selector .underline {
+ background: url("../images/U.svg") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .style-selector .underline.selected {
+ background: url("../images/U_selected.svg") no-repeat;
+}
+
+.jimu-widget-GRGDrafter .halo-toggle-group {
+ padding: 5px;
+}
+.jimu-widget-GRGDrafter .halo-toggle-group .checkbox-inline {
+ padding-left: 36px;
+ vertical-align: top;
+}
+.jimu-widget-GRGDrafter .halo-toggle-group .halo-toggle.dijitCheckBox {
+ margin-left: -36px;
+}
+
+.jimu-widget-GRGDrafter .halo-toggle.dijitCheckBox {
+ height: 16px;
+ width: 28px;
+ border: 0 none;
+ background: #e04f1d;
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+ margin-top: 6px;
+ margin-left: 5px;
+}
+
+.jimu-widget-GRGDrafter .halo-toggle.dijitCheckBox:before {
+ content: "";
+ background: #f8f8f8;
+ position: absolute;
+ padding: 0;
+ height: 12px;
+ width: 12px;
+ left: auto;
+ right: 2px;
+ top: 2px;
+ z-index: 1;
+ -webkit-transition: right 0.3s;
+ -moz-transition: right 0.3s;
+ -o-transition: right 0.3s;
+ transition: right 0.3s;
+ -moz-border-radius: 50%;
+ -webkit-border-radius: 50%;
+ border-radius: 50%;
+}
+.jimu-widget-GRGDrafter .halo-toggle.dijitCheckBox input {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ z-index: 2;
+}
+.jimu-widget-GRGDrafter .halo-toggle.dijitCheckBox.dijitCheckBoxChecked {
+ background: #50ad4e;
+}
+.jimu-widget-GRGDrafter .halo-toggle.dijitCheckBox.dijitCheckBoxChecked:before {
+ right: 14px;
+}
+
+/****** Dart Theme Overrides ******/
+
+.DartTheme .jimu-widget-GRGDrafter .dijitSelectDisabled,
+.DartTheme .jimu-widget-GRGDrafter .dijitTextBoxDisabled,
+.DartTheme .jimu-widget-GRGDrafter .dijitTextBoxDisabled .dijitInputContainer ,
+.DartTheme .jimu-widget-GRGDrafter .dijitTextBoxDisabled {
+ background-color: #4c4c4c;
+}
+
+.claro .dartThemeClaroDijitTooltipContainerOverride .dijitTooltipContainer {
+ background-color: #4c4c4c;
+ background-image: -webkit-linear-gradient(bottom, rgb(76, 76, 76) 0px, #4c4c4c 10px);
+ border: 1px solid #ffffff;
+ color: #ffffff;
+}
+
+.claro .dartThemeClaroDijitTooltipContainerOverride .jimu-widget-subtitle {
+ color: #ffffff;
+}
+
+.claro .dartThemeClaroDijitTooltipContainerOverride .dijitTooltipConnector {
+ background-image: url(images/tooltip.png);
+}
+
+
+
+
diff --git a/GRG/images/B.svg b/GRG/images/B.svg
new file mode 100644
index 0000000..3d5d623
--- /dev/null
+++ b/GRG/images/B.svg
@@ -0,0 +1,19 @@
+
+
+
+ B
+ Created with Sketch.
+
+
+
+
+
+
+
+ B
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/B_selected.svg b/GRG/images/B_selected.svg
new file mode 100644
index 0000000..1080aef
--- /dev/null
+++ b/GRG/images/B_selected.svg
@@ -0,0 +1,24 @@
+
+
+
+ B-s
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+ B
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/I.svg b/GRG/images/I.svg
new file mode 100644
index 0000000..5fa03ff
--- /dev/null
+++ b/GRG/images/I.svg
@@ -0,0 +1,19 @@
+
+
+
+ I
+ Created with Sketch.
+
+
+
+
+
+
+
+ I
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/I_selected.svg b/GRG/images/I_selected.svg
new file mode 100644
index 0000000..c07a8f5
--- /dev/null
+++ b/GRG/images/I_selected.svg
@@ -0,0 +1,24 @@
+
+
+
+ I-s
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+ I
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/U.svg b/GRG/images/U.svg
new file mode 100644
index 0000000..c1b8370
--- /dev/null
+++ b/GRG/images/U.svg
@@ -0,0 +1,19 @@
+
+
+
+ U
+ Created with Sketch.
+
+
+
+
+
+
+
+ U
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/U_selected.svg b/GRG/images/U_selected.svg
new file mode 100644
index 0000000..c15ee64
--- /dev/null
+++ b/GRG/images/U_selected.svg
@@ -0,0 +1,24 @@
+
+
+
+ U-s
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+ U
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/bySize.png b/GRG/images/bySize.png
new file mode 100644
index 0000000..adbf9ca
Binary files /dev/null and b/GRG/images/bySize.png differ
diff --git a/GRG/images/down-arrow.png b/GRG/images/down-arrow.png
new file mode 100644
index 0000000..7588190
Binary files /dev/null and b/GRG/images/down-arrow.png differ
diff --git a/GRG/images/globe.png b/GRG/images/globe.png
new file mode 100644
index 0000000..66e1926
Binary files /dev/null and b/GRG/images/globe.png differ
diff --git a/GRG/images/icon.png b/GRG/images/icon.png
new file mode 100644
index 0000000..16308e0
Binary files /dev/null and b/GRG/images/icon.png differ
diff --git a/GRG/images/left-arrow.png b/GRG/images/left-arrow.png
new file mode 100644
index 0000000..5379b05
Binary files /dev/null and b/GRG/images/left-arrow.png differ
diff --git a/GRG/images/new-MGRS.png b/GRG/images/new-MGRS.png
new file mode 100644
index 0000000..2465f2b
Binary files /dev/null and b/GRG/images/new-MGRS.png differ
diff --git a/GRG/images/new-grgArea.png b/GRG/images/new-grgArea.png
new file mode 100644
index 0000000..52219a6
Binary files /dev/null and b/GRG/images/new-grgArea.png differ
diff --git a/GRG/images/new-grgPoint.png b/GRG/images/new-grgPoint.png
new file mode 100644
index 0000000..945e8d1
Binary files /dev/null and b/GRG/images/new-grgPoint.png differ
diff --git a/GRG/images/settings.png b/GRG/images/settings.png
new file mode 100644
index 0000000..5f615f3
Binary files /dev/null and b/GRG/images/settings.png differ
diff --git a/GRG/images/sliderball.png b/GRG/images/sliderball.png
new file mode 100644
index 0000000..5d65ee6
Binary files /dev/null and b/GRG/images/sliderball.png differ
diff --git a/GRG/images/sliderball.svg b/GRG/images/sliderball.svg
new file mode 100644
index 0000000..72dbf98
--- /dev/null
+++ b/GRG/images/sliderball.svg
@@ -0,0 +1,16 @@
+
+
+
+ Group
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/sliderball_hold.svg b/GRG/images/sliderball_hold.svg
new file mode 100644
index 0000000..0fd42e6
--- /dev/null
+++ b/GRG/images/sliderball_hold.svg
@@ -0,0 +1,26 @@
+
+
+
+ Oval
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/images/sliderball_hover.png b/GRG/images/sliderball_hover.png
new file mode 100644
index 0000000..2d5c1e2
Binary files /dev/null and b/GRG/images/sliderball_hover.png differ
diff --git a/GRG/images/up-arrow.png b/GRG/images/up-arrow.png
new file mode 100644
index 0000000..90ea3db
Binary files /dev/null and b/GRG/images/up-arrow.png differ
diff --git a/GRG/js/ColorPickerEditor.js b/GRG/js/ColorPickerEditor.js
new file mode 100644
index 0000000..ed8f21e
--- /dev/null
+++ b/GRG/js/ColorPickerEditor.js
@@ -0,0 +1,113 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ "dojo/_base/lang",
+ 'dojo/_base/Color',
+ 'dojo/on',
+ "dojo/query",
+ "dojo/_base/html",
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!../templates/ColorPickerEditor.html',
+ "dijit/form/HorizontalSlider",
+ 'jimu/dijit/ColorPickerPopup',
+ "dijit/form/NumberSpinner"
+ ],
+ function(declare, lang, Color, on, query, html,
+ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template,
+ HorizontalSlider, ColorPicker) {
+ return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
+ _defaultColor: '#485566',
+ templateString: template,
+ nls: null,
+
+ postCreate: function() {
+ this.colorPicker = new ColorPicker({
+ color: this._defaultColor
+ }, this.colorPicker);
+ this.colorPicker.startup();
+
+ this.slider = new HorizontalSlider({
+ name: "slider",
+ value: 100,
+ minimum: 0,
+ maximum: 100,
+ discreteValues: 101,
+ intermediateChanges: true,
+ showButtons: false,
+ style: "display: inline-block;"
+ }, this.sliderBar);
+ this.slider.startup();
+
+ this.inherited(arguments);
+ },
+ startup: function() {
+ this.own(on(this.slider, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.spinner.setValue(val);
+ }
+ })));
+
+ this.own(on(this.spinner, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.slider.setValue(val);
+ }
+ })));
+
+ this._stylePolyfill();
+ this.inherited(arguments);
+ },
+ _isSameVal: function() {
+ return this.slider.getValue() === this.spinner.getValue();
+ },
+ getValues: function() {
+ var rgb = null,
+ a = null;
+ var bgColor = this.colorPicker.getColor();
+ if (bgColor && bgColor.toHex) {
+ rgb = bgColor.toHex();
+ }
+ a = this.spinner.getValue() / 100;
+
+ return {
+ color: rgb,
+ transparency: a
+ };
+ },
+ setValues: function(obj) {
+ if (typeof obj === "object" || typeof obj === "string") {
+ this.colorPicker.setColor(new Color(obj.color));
+
+ if (typeof obj.transparency === "undefined") {
+ obj.transparency = 0;
+ } else {
+ obj.transparency = obj.transparency * 100;
+ }
+ this.slider.setValue(obj.transparency);
+ this.spinner.setValue(obj.transparency);
+ }
+ },
+ _stylePolyfill: function() {
+ var leftBumper = query('.dijitSliderLeftBumper', this.domNode)[0];
+ if (leftBumper && leftBumper.parentNode) {
+ html.setStyle(leftBumper.parentNode, 'background-color', "#24b5cc");
+ }
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/js/ConfirmNotation.js b/GRG/js/ConfirmNotation.js
new file mode 100644
index 0000000..3352617
--- /dev/null
+++ b/GRG/js/ConfirmNotation.js
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2016 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+/*global define*/
+define([
+ 'dojo/_base/declare',
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!../templates/ConfirmNotation.html'
+], function (
+ dojoDeclare,
+ dijitWidgetBase,
+ dijitTemplatedMixin,
+ dijitWidgetsInTemplate,
+ ConfirmNotation
+) {
+ 'use strict';
+ return dojoDeclare([dijitWidgetBase, dijitTemplatedMixin, dijitWidgetsInTemplate], {
+ templateString: ConfirmNotation,
+ numberOfInputs: 0,
+ selectOptions: {},
+
+ constructor: function (options1,args) {
+ dojoDeclare.safeMixin(this, args);
+ this.numberOfInputs = options1.length;
+ this.selectOptions = options1;
+ },
+
+ postCreate: function () {
+ this.label1.innerHTML = this.numberOfInputs + " " + this.nls.notationsMatch;
+ for (var i = 0; i < this.selectOptions.length; i++) {
+ this.comboOptions.addOption({ value: this.selectOptions[i].name , label: this.selectOptions[i].notationType});
+ }
+ },
+ });
+});
diff --git a/GRG/js/Coordinate.js b/GRG/js/Coordinate.js
new file mode 100644
index 0000000..199d6e9
--- /dev/null
+++ b/GRG/js/Coordinate.js
@@ -0,0 +1,392 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/array',
+ 'dojo/_base/lang',
+ 'dojo/Stateful',
+ 'dojo/topic',
+ 'dojo/Deferred',
+ 'esri/geometry/Point',
+ 'esri/SpatialReference',
+ 'esri/geometry/webMercatorUtils',
+ 'jimu/dijit/Message',
+ './util',
+ './dialogConfirm',
+ './ConfirmNotation'
+], function (
+ dojoDeclare,
+ dojoArray,
+ dojoLang,
+ dojoStateful,
+ dojoTopic,
+ DojoDeferred,
+ EsriPoint,
+ EsriSpatialReference,
+ EsriWMUtils,
+ JimuMessage,
+ CoordinateUtilities,
+ dialogConfirm,
+ ConfirmNotation
+) {
+
+ var mo = dojoDeclare([dojoStateful], {
+
+ formatPrefix: false,
+ _formatPrefixSetter: function (value) {
+ this.formatPrefix = value;
+ },
+
+ inputString: null,
+ _inputStringSetter: function (value) {
+ this.inputString = value;
+ },
+
+ formatString: 'YN XE',
+ _formatStringSetter: function (value) {
+ this.formatString = value;
+ },
+
+ inputType: 'UNKNOWN',
+
+ formatType: 'DD',
+
+ _formatTypeSetter: function (value) {
+ this.formatType = value;
+ this.getFormattedValue();
+ },
+
+ outputString: '',
+
+ coordinateEsriGeometry: null,
+
+ _coordinateEsriGeometrySetter: function (value) {
+ var pt;
+ if (value == null) return;
+ if (value.spatialReference.wkid !== 4326) {
+ pt = EsriWMUtils.webMercatorToGeographic(value);
+ } else {
+ pt = value;
+ }
+ this.coordinateEsriGeometry = pt;
+ this.getFormattedValue();
+ },
+
+ /**
+ *
+ **/
+ constructor: function (args) {
+ dojoDeclare.safeMixin(this, args);
+ this.util = new CoordinateUtilities(this.appConfig.geometryService);
+ },
+
+ /**
+ *
+ **/
+ getInputType: function () {
+ this.inputTypeDef = new DojoDeferred();
+ var sanitizedInput = this.util.getCleanInput(this.inputString);
+ this.util.getCoordinateType(sanitizedInput).then(dojoLang.hitch(this, function(itm){
+ if (itm) {
+ if (itm.length == 1) {
+ var sortedInput = this.processCoordTextInput(sanitizedInput, itm[0],false);
+ this.util.getXYNotation(sortedInput, itm[0].conversionType).then(dojoLang.hitch(this,function(r){
+ if (r.length <= 0 || (!r[0][0] && r[0][0] != 0)){
+ this.hasError = true;
+ this.valid = false;
+ this.message = 'Invalid Coordinate';
+ this.inputTypeDef.resolve(this);
+ } else {
+ this.isManual = true;
+ this.valid = true;
+ this.formatType = itm[0].conversionType;
+ this.inputType = itm[0].conversionType;
+ this.coordinateEsriGeometry = new EsriPoint(r[0][0],r[0][1],new EsriSpatialReference({wkid: 4326}));
+ this.message = 'Invalid Coordinate';
+ this.inputTypeDef.resolve(this);
+ }
+ })), dojoLang.hitch(this, function (r) {
+ this.hasError = true;
+ this.valid = false;
+ this.inputType = 'UNKNOWN';
+ this.message = 'Invalid Coordinate';
+ this.inputTypeDef.resolve(this);
+ });
+ } else {
+ var dialog = new dialogConfirm({
+ nls: this.nls,
+ title: this.nls.comfirmInputNotation,
+ content: new ConfirmNotation(itm,{nls: this.nls}),
+ style: "width: 400px",
+ hasSkipCheckBox: false
+ });
+
+ dialog.show().then(dojoLang.hitch(this, function() {
+ var singleMatch = dojoArray.filter(itm, function (singleItm) {
+ return singleItm.name == dialog.content.comboOptions.get('value');
+ });
+ var withStr = this.processCoordTextInput(sanitizedInput, singleMatch[0],false);
+ this.util.getXYNotation(withStr, singleMatch[0].conversionType).then(dojoLang.hitch(this,function(r) {
+ if (r.length <= 0 || (!r[0][0] && r[0][0] != 0)){
+ this.hasError = true;
+ this.valid = false;
+ this.message = 'Invalid Coordinate';
+ this.inputTypeDef.resolve(this);
+ } else {
+ this.isManual = true;
+ this.valid = true;
+ this.inputType = itm[0].conversionType;
+ this.formatType = itm[0].conversionType;
+ this.coordinateEsriGeometry = new EsriPoint(r[0][0],r[0][1],new EsriSpatialReference({wkid: 4326}));
+ this.message = '';
+ this.inputTypeDef.resolve(this);
+ }
+ })), dojoLang.hitch(this, function (r) {
+ this.hasError = true;
+ this.valid = false;
+ this.inputType = 'UNKNOWN';
+ this.message = 'Invalid Coordinate';
+ this.inputTypeDef.resolve(this);
+ });
+ }, function() {
+ deferred.reject();
+ }));
+ }
+ } else {
+ this.hasError = true;
+ this.valid = false;
+ this.inputType = 'UNKNOWN';
+ this.message = 'Invalid Coordinate';
+ this.inputTypeDef.resolve(this);
+ }
+ }));
+ return this.inputTypeDef;
+ },
+
+ /**
+ *
+ **/
+ processCoordTextInput: function (withStr, asType, testingMode) {
+
+ var match = asType.pattern.exec(withStr);
+
+ var northSouthPrefix, northSouthSuffix, eastWestPrefix, eastWestSuffix, latDeg, longDeg, latMin, longMin, latSec, longSec;
+
+ var prefixSuffixError = false;
+
+ var conversionType = asType.name;
+
+ switch (asType.name) {
+ case 'DD':
+ northSouthPrefix = match[2];
+ northSouthSuffix = match[7];
+ eastWestPrefix = match[10];
+ eastWestSuffix = match[16];
+ latDeg = match[3].replace(/[,:]/, '.');
+ longDeg = match[11].replace(/[,:]/, '.');
+ conversionType = 'DD';
+ break;
+ case 'DDrev':
+ northSouthPrefix = match[11];
+ northSouthSuffix = match[16];
+ eastWestPrefix = match[2];
+ eastWestSuffix = match[8];
+ latDeg = match[12].replace(/[,:]/, '.');
+ longDeg = match[3].replace(/[,:]/, '.');
+ conversionType = 'DD';
+ break;
+ case 'DDM':
+ northSouthPrefix = match[2];
+ northSouthSuffix = match[7];
+ eastWestPrefix = match[10];
+ eastWestSuffix = match[15];
+ latDeg = match[3];
+ latMin = match[4].replace(/[,:]/, '.');
+ longDeg = match[11];
+ longMin = match[12].replace(/[,:]/, '.');
+ conversionType = 'DDM';
+ break;
+ case 'DDMrev':
+ northSouthPrefix = match[10];
+ northSouthSuffix = match[15];
+ eastWestPrefix = match[2];
+ eastWestSuffix = match[7];
+ latDeg = match[11];
+ latMin = match[12].replace(/[,:]/, '.');
+ longDeg = match[3];
+ longMin = match[4].replace(/[,:]/, '.');
+ conversionType = 'DDM';
+ break;
+ case 'DMS':
+ northSouthPrefix = match[2];
+ northSouthSuffix = match[8];
+ eastWestPrefix = match[11];
+ eastWestSuffix = match[17];
+ latDeg = match[3];
+ latMin = match[4];
+ latSec = match[5].replace(/[,:]/, '.');
+ longDeg = match[12];
+ longMin = match[13];
+ longSec = match[14].replace(/[,:]/, '.');
+ conversionType = 'DMS';
+ break;
+ case 'DMSrev':
+ northSouthPrefix = match[11];
+ northSouthSuffix = match[17];
+ eastWestPrefix = match[2];
+ eastWestSuffix = match[8];
+ latDeg = match[12];
+ latMin = match[13];
+ latSec = match[14].replace(/[,:]/, '.');
+ longDeg = match[3];
+ longMin = match[4];
+ longSec = match[5].replace(/[,:]/, '.');
+ conversionType = 'DMS';
+ break;
+ }
+
+ //check for north/south prefix/suffix
+ if(northSouthPrefix && northSouthSuffix) {
+ prefixSuffixError = true;
+ new RegExp(/[Ss-]/).test(northSouthPrefix)?northSouthPrefix = '-':northSouthPrefix = '+';
+ } else {
+ if(northSouthPrefix && new RegExp(/[Ss-]/).test(northSouthPrefix)){
+ northSouthPrefix = '-';
+ } else {
+ if(northSouthSuffix && new RegExp(/[Ss-]/).test(northSouthSuffix)){
+ northSouthPrefix = '-';
+ } else {
+ northSouthPrefix = '+';
+ }
+ }
+ }
+
+ //check for east/west prefix/suffix
+ if(eastWestPrefix && eastWestSuffix) {
+ prefixSuffixError = true;
+ new RegExp(/[Ww-]/).test(eastWestPrefix)?eastWestPrefix = '-':eastWestPrefix = '+';
+ } else {
+ if(eastWestPrefix && new RegExp(/[Ww-]/).test(eastWestPrefix)){
+ eastWestPrefix = '-';
+ } else {
+ if(eastWestSuffix && new RegExp(/[Ww-]/).test(eastWestSuffix)){
+ eastWestPrefix = '-';
+ } else {
+ eastWestPrefix = '+';
+ }
+ }
+ }
+
+ //give user warning if lat or long is determined as having a prefix and suffix
+ if(prefixSuffixError) {
+ if(!testingMode) {
+ new JimuMessage({message: this.nls.prefixSuffixError});
+ }
+ }
+
+ switch (conversionType) {
+ case 'DD':
+ withStr = northSouthPrefix + latDeg + "," + eastWestPrefix + longDeg;
+ break;
+ case 'DDM':
+ withStr = northSouthPrefix + latDeg + " " + latMin + "," + eastWestPrefix + longDeg + " " + longMin;
+ break;
+ case 'DMS':
+ withStr = northSouthPrefix + latDeg + " " + latMin + " " + latSec + "," + eastWestPrefix + longDeg + " " + longMin + " " + longSec;
+ break;
+ default:
+ withStr = withStr;
+ break;
+ }
+
+ return withStr;
+ },
+
+ /**
+ *
+ **/
+ getInputTypeSync: function () {
+ var v = this.util.getCoordinateType(this.inputString);
+ return v !== null;
+ },
+
+ /**
+ *
+ **/
+ getFormattedValue: function () {
+ if (!this.coordinateEsriGeometry) {
+ return;
+ }
+ this.util.getCoordValues({
+ x: this.coordinateEsriGeometry.x,
+ y: this.coordinateEsriGeometry.y
+ }, this.formatType, 6).then(dojoLang.hitch(this, function (r) {
+ this.set('outputString', this.getCoordUI(r));
+ }));
+ },
+
+ /**
+ * Get coordinate notation in user provided format
+ **/
+ getCoordUI: function (fromValue) {
+ var as = this.get('formatPrefix');
+ var r;
+ var formattedStr;
+ switch (this.formatType) {
+ case 'DD':
+ r = this.util.getFormattedDDStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'DDM':
+ r = this.util.getFormattedDDMStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'DMS':
+ r = this.util.getFormattedDMSStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'USNG':
+ r = this.util.getFormattedUSNGStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'MGRS':
+ r = this.util.getFormattedMGRSStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'GARS':
+ r = this.util.getFormattedGARSStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'GEOREF':
+ r = this.util.getFormattedGEOREFStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'UTM':
+ r = this.util.getFormattedUTMStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ case 'UTM (H)':
+ r = this.util.getFormattedUTMHStr(fromValue, this.formatString, as);
+ formattedStr = r.formatResult;
+ break;
+ }
+ return formattedStr;
+ }
+ });
+
+ return mo;
+});
diff --git a/GRG/js/CoordinateInput.js b/GRG/js/CoordinateInput.js
new file mode 100644
index 0000000..6e77eca
--- /dev/null
+++ b/GRG/js/CoordinateInput.js
@@ -0,0 +1,78 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/topic',
+ 'dijit/form/ValidationTextBox',
+ './Coordinate'
+], function (
+ dojoDeclare,
+ dojoTopic,
+ dijitValidationTextBox,
+ Coord
+) {
+ var mo = dojoDeclare('test', dijitValidationTextBox, {
+ required: true,
+
+ inputCoordinate: null,
+
+ invalidMessage: 'Blah Blah Blah',
+
+ validateOnInput: true,
+ _validateOnInputSetter: function (value) {
+ this.validateOnInput = (value === 'true');
+ },
+
+ clear: function () {
+ this.set('validateOnInput', true);
+ this.set('value', '');
+ this.inputCoordinate.coordinateEsriGeometry = null;
+ },
+ /**
+ *
+ **/
+ constructor: function (args) {
+ dojoDeclare.safeMixin(this, args);
+ this.inherited(arguments);
+ this.inputCoordinate = new Coord({nls: this.nls, appConfig: arguments[0].appConfig});
+ },
+
+ postMixinProperties: function () {
+ console.log('Post Create');
+ },
+
+ /**
+ *
+ **/
+ validator: function (value, contstraints) {
+
+ if (!this.validateOnInput) {return true;}
+ //if (this.get('value').length < 4) return false;
+
+ this.inputCoordinate.set('inputString', value);
+
+ //this.inputCoordinate.set('formatString', 'YN XE');
+
+ this.set('invalidMessage', this.inputCoordinate.message);
+ this.set('promptMessage', this.inputCoordinate.message);
+
+ return true;
+ }
+ });
+
+ return mo;
+});
diff --git a/GRG/js/DrawFeedBack.js b/GRG/js/DrawFeedBack.js
new file mode 100644
index 0000000..1498810
--- /dev/null
+++ b/GRG/js/DrawFeedBack.js
@@ -0,0 +1,99 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2016 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/topic',
+ './Feedback'
+], function (
+ dojoDeclare,
+ dojoLang,
+ dojoTopic,
+ drawFeedback
+) {
+ var clz = dojoDeclare([drawFeedback], {
+ /**
+ *
+ **/
+ constructor: function (map,coordTool) {
+ this.syncEvents();
+ this.inherited(arguments);
+ },
+
+ syncEvents: function () {
+ dojoTopic.subscribe(
+ 'grg-center-point-input',
+ dojoLang.hitch(this, this.onCenterPointManualInputHandler)
+ );
+
+ dojoTopic.subscribe(
+ 'clear-points',
+ dojoLang.hitch(this, this.clearPoints)
+ );
+ },
+
+ /*
+ Handler for clearing out points
+ */
+ clearPoints: function (centerPoint) {
+ this._points = [];
+ this.map.graphics.clear();
+ },
+
+ /**
+ *
+ **/
+ clearGraphics: function (evt) {
+ this.map.graphics.clear();
+ },
+
+ /*
+ Handler for the manual input of a center point
+ */
+ onCenterPointManualInputHandler: function (centerPoint) {
+ this._points = [];
+ this._points.push(centerPoint.offset(0, 0));
+ this.set('startPoint', this._points[0]);
+ this.map.centerAt(centerPoint);
+ },
+
+ /**
+ *
+ **/
+ _onClickHandler: function (evt) {
+ this._points = [];
+ var snapPoint;
+ if (this.map.snappingManager) {
+ snapPoint = this.map.snappingManager._snappingPoint;
+ }
+ var start = snapPoint || evt.mapPoint;
+ var map = this.map;
+ this._points.push(start.offset(0, 0));
+ this.set('startPoint', this._points[0]);
+ this._drawEnd(start);
+ },
+
+ /*
+ *
+ */
+ cleanup: function (evt) {
+ //do nothing yet
+ }
+ });
+ return clz;
+});
diff --git a/GRG/js/EditOutputCoordinate.js b/GRG/js/EditOutputCoordinate.js
new file mode 100644
index 0000000..e15943b
--- /dev/null
+++ b/GRG/js/EditOutputCoordinate.js
@@ -0,0 +1,173 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2016 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+/*global define*/
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/dom-style',
+ 'dojo/on',
+ 'dojo/topic',
+ 'dojo/dom-attr',
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!../templates/EditOutputCoordinate.html',
+ 'dijit/form/Select',
+ 'jimu/dijit/CheckBox'
+], function (
+ dojoDeclare,
+ dojoLang,
+ dojoDomStyle,
+ dojoOn,
+ dojoTopic,
+ dojoDomAttr,
+ dijitWidgetBase,
+ dijitTemplatedMixin,
+ dijitWidgetsInTemplate,
+ edittemplate
+) {
+ 'use strict';
+ return dojoDeclare([dijitWidgetBase, dijitTemplatedMixin, dijitWidgetsInTemplate], {
+ templateString: edittemplate,
+
+ formats: {
+
+ },
+
+ ct: 'DD',
+ _setCtAttr: function (v) {
+ this.frmtSelect.set('value', v);
+ },
+
+ constructor: function (args) {
+ dojoDeclare.safeMixin(this, args);
+ },
+
+ /**
+ *
+ **/
+ postCreate: function () {
+ this.formats = {
+ DD: {
+ defaultFormat: 'YN XE',
+ customFormat: null,
+ useCustom: false
+ },
+ DDM: {
+ defaultFormat: 'A° B\'N X° Y\'E',
+ customFormat: null,
+ useCustom: false
+ },
+ DMS: {
+ defaultFormat: 'A° B\' C\"N X° Y\' Z\"E',
+ customFormat: null,
+ useCustom: false
+ },
+ GARS: {
+ defaultFormat: 'XYQK',
+ customFormat: null,
+ useCustom: false
+ },
+ GEOREF: {
+ defaultFormat: 'ABCDXY',
+ customFormat: null,
+ useCustom: false
+ },
+ MGRS: {
+ defaultFormat: 'ZSXY',
+ customFormat: null,
+ useCustom: false
+ },
+ USNG: {
+ defaultFormat: 'ZSXY',
+ customFormat: null,
+ useCustom: false
+ },
+ UTM: {
+ defaultFormat: 'ZB X Y',
+ customFormat: null,
+ useCustom: false
+ },
+ 'UTM (H)': {
+ defaultFormat: 'ZH X Y',
+ customFormat: null,
+ useCustom: false
+ }
+ };
+
+ dojoDomAttr.set(this.frmtVal, 'value', this.formats[this.ct].defaultFormat);
+
+ this.own(
+ this.frmtSelect.on('change', dojoLang.hitch(
+ this,
+ this.frmtSelectValueDidChange)
+ ));
+
+ this.own(dojoOn(
+ this.frmtVal,
+ 'change',
+ dojoLang.hitch(this, this.formatValDidChange)
+ ));
+
+ this.displayPrefixContainer();
+ },
+
+ /**
+ *
+ *
+ startup: function () {
+ this.inherited(arguments);
+ },*/
+
+ formatValDidChange: function () {
+ var newvalue = dojoDomAttr.get(this.frmtVal, 'value');
+ var crdType = this.frmtSelect.get('value');
+ this.formats[crdType].customFormat = newvalue;
+ this.formats[crdType].useCustom = true;
+ this.currentformat = newvalue;
+ },
+
+ /**
+ *
+ **/
+ frmtSelectValueDidChange: function () {
+ var curval = this.frmtSelect.get('value');
+ var selval = this.formats[curval].useCustom ? this.formats[curval].customFormat
+ : this.formats[curval].defaultFormat;
+ this.ct = curval;
+ dojoDomAttr.set(this.frmtVal, 'value', selval);
+ this.displayPrefixContainer();
+ },
+
+ /**
+ *
+ **/
+ displayPrefixContainer: function () {
+ switch(this.frmtSelect.get('value')){
+ case 'DD':
+ case 'DDM':
+ case 'DMS':
+ dojoDomStyle.set(this.prefixContainer, {display: ""});
+ break;
+ default:
+ dojoDomStyle.set(this.prefixContainer, {display: "none"});
+ break;
+ }
+ }
+
+ });
+});
diff --git a/GRG/js/Feedback.js b/GRG/js/Feedback.js
new file mode 100644
index 0000000..ad7bee4
--- /dev/null
+++ b/GRG/js/Feedback.js
@@ -0,0 +1,51 @@
+
+///////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2016 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/Stateful',
+ 'esri/toolbars/draw',
+ 'esri/graphic'
+], function (
+ dojoDeclare,
+ dojoStateful,
+ esriDraw,
+ EsriGraphic
+ ) {
+ var w = dojoDeclare([esriDraw,dojoStateful], {
+ startPoint: null,
+ _setStartPoint: function (p){
+ this._set('startPoint', p);
+ },
+
+ addStartGraphic: function (fromGeometry, withSym, targetLayer) {
+ this.removeStartGraphic(targetLayer);
+ this.startGraphic = new EsriGraphic(fromGeometry, withSym);
+ targetLayer.add(this.startGraphic);
+ },
+
+ removeStartGraphic: function (targetLayer) {
+ if (this.startGraphic) {
+ targetLayer.remove(this.startGraphic);
+ }
+ this.startGraphic = null;
+ }
+ });
+
+ return w;
+});
diff --git a/GRG/js/FontSetting.js b/GRG/js/FontSetting.js
new file mode 100644
index 0000000..4eef7d8
--- /dev/null
+++ b/GRG/js/FontSetting.js
@@ -0,0 +1,391 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ "dojo/_base/lang",
+ 'dojo/on',
+ 'dojo/_base/html',
+ 'dojo/_base/array',
+ 'dojo/Evented',
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!../templates/FontSetting.html',
+ 'jimu/dijit/ColorPickerPopup',
+ "dijit/form/HorizontalSlider",
+ './TransparencyEditor',
+ "dojo/store/Memory",
+ "dijit/form/ComboBox",
+ 'jimu/dijit/CheckBox',
+ 'jimu/dijit/ImageChooser'
+],
+ function (declare, lang, on, html, array,
+ Evented, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template,
+ ColorPickerPopup, HorizontalSlider, TransparencyEditor, Memory) {
+ return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Evented], {
+ templateString: template,
+ nls: null,
+ _FONTS: null,
+ _MIN_TEXT_SIZE: 12,
+ _MAX_TEXT_SIZE: 48,
+ _INTERVAL_TEXT_SIZE: 2,
+
+ _DEFAULT_CONFIG: null,
+
+ postCreate: function () {
+ this.inherited(arguments);
+ this._FONTS = "Arial;Comic Sans MS;Courier New;Garamond;Tahoma;Times New Roman;Verdana".split(";");
+ this._DEFAULT_CONFIG = {
+ font: {
+ fontFamily: this._FONTS[0],//first one
+ bold: false,
+ italic: false,
+ underline: false
+ },
+ fontSize: "24",
+ textColor: "#282828",
+ haloSize: 1,
+ haloColor: "#FFFFFF",
+ haloOn: true,
+ labelTransparency: 1,
+ };
+ this.config = lang.mixin(lang.clone(this._DEFAULT_CONFIG), this.config);
+
+ //font
+ array.forEach(this._FONTS, lang.hitch(this, function (font) {
+ this.fontSelect.addOption({ value: font, label: font });
+ }));
+ //text size
+ var textSizeStore = new Memory({});
+ for (var i = this._MIN_TEXT_SIZE, max = this._MAX_TEXT_SIZE; i < max; i += this._INTERVAL_TEXT_SIZE) {
+ textSizeStore.put({ id: i, name: i });
+ }
+ this.textSizeSelect.store = textSizeStore;
+ this.textSizeSelect.validator = lang.hitch(this, function () {
+ var s = this.textSizeSelect.getValue();
+ if (s !== null && s !== "") {
+ return !isNaN(s);
+ }
+ return false;
+ });
+ this.textSizeSlider = new HorizontalSlider({
+ name: "slider",
+ value: 0,
+ minimum: this._MIN_TEXT_SIZE,
+ maximum: this._MAX_TEXT_SIZE,
+ discreteValues: this.textSizeSelect.store.data.length + 1,
+ intermediateChanges: true,
+ showButtons: false,
+ style: "display: inline-block;"
+ }, this.sliderBar);
+ this.textSizeSlider.startup();
+ //.textColor
+ this.textColorPicker = new ColorPickerPopup({
+ appearance: {
+ showTransparent: false,
+ showColorPalette: true,
+ showCoustom: true,
+ showCoustomRecord: true
+ },
+ recordUID: this.recordUID
+ });
+ this.textColorPicker.placeAt(this.textColorBtn);
+ this.textColorPicker.startup();
+
+ //transparency
+ this.labelTransparency = new TransparencyEditor({}, this.transparencySlider);
+ this.labelTransparency.startup();
+
+
+
+ //halo
+ //halo size
+ var haloSizeStore = new Memory({});
+ for (var i = 1, max = 10; i <= max; i += 1) {
+ haloSizeStore.put({ id: i, name: i });
+ }
+ this.haloSizeSelect.store = haloSizeStore;
+ this.haloSizeSelect.validator = lang.hitch(this, function () {
+ var s = this.haloSizeSelect.getValue();
+ if (s !== null && s !== "") {
+ return !isNaN(s);
+ }
+ return false;
+ });
+
+
+ //halo color picker
+ this.haloColorPicker = new ColorPickerPopup({
+ appearance: {
+ showTransparent: false,
+ showColorPalette: true,
+ showCoustom: true,
+ showCoustomRecord: true
+ },
+ });
+ this.haloColorPicker.placeAt(this.haloColorBtn);
+ this.haloColorPicker.startup();
+
+ //font
+ this.own(on(this.fontSelect, 'change', lang.hitch(this, function (value) {
+ if(this.config.font.fontFamily === value){
+ return;
+ }
+ this.onSettingChange({
+ font: {
+ fontFamily: value,
+ bold: this.config.font.bold,
+ italic: this.config.font.italic,
+ underline: this.config.font.underline
+ }
+ });
+ })));
+ this._initAppearance();
+ this.own(on(this.bold, 'click', lang.hitch(this, function (/*value*/) {
+ var isClick = !html.hasClass(this.bold, "selected");
+ this.fontBtnClickd({ bold: isClick });
+ this.onSettingChange({
+ font: {
+ fontFamily: this.config.font.fontFamily,
+ bold: isClick,
+ italic: this.config.font.italic,
+ underline: this.config.font.underline
+ }
+ });
+ })));
+ this.own(on(this.italic, 'click', lang.hitch(this, function (/*value*/) {
+ var isClick = !html.hasClass(this.italic, "selected");
+ this.fontBtnClickd({ italic: isClick });
+ this.onSettingChange({
+ font: {
+ fontFamily: this.config.font.fontFamily,
+ bold: this.config.font.bold,
+ italic: isClick,
+ underline: this.config.font.underline
+ }
+ });
+ })));
+ this.own(on(this.underline, 'click', lang.hitch(this, function (/*value*/) {
+ var isClick = !html.hasClass(this.underline, "selected");
+ this.fontBtnClickd({ underline: isClick });
+ this.onSettingChange({
+ font: {
+ fontFamily: this.config.font.fontFamily,
+ bold: this.config.font.bold,
+ italic: this.config.font.italic,
+ underline: isClick
+ }
+ });
+ })));
+ //text size
+ this.own(on(this.textSizeSelect, 'change', lang.hitch(this, function (value) {
+ if(this.config.fontSize === value || false === this.textSizeSelect.isValid()){
+ return;
+ }
+ this.setTextSize(value);
+ this.onSettingChange({
+ fontSize: value
+ });
+ })));
+ this.own(on(this.textSizeSlider, 'change', lang.hitch(this, function (value) {
+ if(this.config.fontSize === value){
+ return;
+ }
+ this.setTextSize(value);
+ this.onSettingChange({
+ fontSize: value
+ });
+ })));
+ //.textColor
+ this.own(on(this.textColorPicker, 'change', lang.hitch(this, function (color) {
+ if(this.config.textColor === color){
+ return;
+ }
+ this.onSettingChange({
+ textColor: color.toHex()
+ });
+ })));
+ //transparency slider
+ this.own(this.labelTransparency.watch('transparency', lang.hitch(this, function () {
+ this.onSettingChange({
+ labelTransparency: this.labelTransparency.getValues().transparency
+ });
+ })));
+ //halo size
+ this.own(on(this.haloSizeSelect, 'change', lang.hitch(this, function (value) {
+ if(this.config.haloSize === value || false === this.haloSizeSelect.isValid()){
+ return;
+ }
+ this.onSettingChange({
+ haloSize: value
+ });
+ })));
+ //.haloColor
+ this.own(on(this.haloColorPicker, 'change', lang.hitch(this, function (color) {
+ if(this.config.haloColor === color){
+ return;
+ }
+ this.onSettingChange({
+ haloColor: color.toHex()
+ });
+ })));
+ //halo toggle switch
+ this.own(on(this.showHalo, 'change', lang.hitch(this, function () {
+ this.onSettingChange({
+ haloOn: this.showHalo.checked
+ });
+ })));
+ },
+ startup: function () {
+ this.inherited(arguments);
+ this.setConfig(this.config);
+ this.refresh();
+ //add titles
+ // var labels = html.query(".setting-items .label", this.domNode);
+ // array.forEach(labels, lang.hitch(this, function (label) {
+ // html.setAttr(label, "title", html.getAttr(label, "innerHTML"));
+ // }));
+ },
+
+ onSettingChange: function (configObj) {
+ this.config = lang.mixin(this.config, configObj);
+ this.onChange(this.config);
+ },
+ onChange: function (config) {
+ this.emit("change", config);
+ },
+ refresh: function () {
+ this.onSettingChange({});
+ },
+ isValid: function () {
+ if (false === this.textSizeSelect.isValid()) {
+ return false;
+ }
+
+ return true;
+ },
+ getConfig: function () {
+ if (this.isValid()) {
+ return this.config;
+ } else {
+ return false;
+ }
+ },
+
+ setConfig: function (configObj) {
+ if ("undefined" === configObj) {
+ return;
+ }
+
+ if ("undefined" !== typeof configObj.font) {
+ this.config.font = configObj.font;
+ if (this.config.font.fontFamily) {
+ this.fontSelect.set('value', this.config.font.fontFamily);
+ }
+ this.fontBtnClickd(this.config.font);
+ }
+ if ("undefined" !== typeof configObj.fontSize) {
+ this.config.fontSize = configObj.fontSize;
+ this.setTextSize(this.config.fontSize);
+ }
+ if ("undefined" === typeof configObj.textColor || "" === configObj.textColor) {
+ configObj.textColor = this._DEFAULT_CONFIG.textColor;//"#000001";
+ }
+ this.config.textColor = configObj.textColor;
+
+ if ("undefined" === typeof configObj.labelTransparency || "" === configObj.labelTransparency) {
+ configObj.labelTransparency = this._DEFAULT_CONFIG.labelTransparency;//"1";
+ }
+ this.config.labelTransparency = configObj.labelTransparency;
+ this.labelTransparency.setValues({"transparency": this.config.labelTransparency});
+
+ if ("undefined" === typeof configObj.haloSize || "" === configObj.haloSize) {
+ configObj.haloSize = this._DEFAULT_CONFIG.haloSize;//"1";
+
+ }
+ this.config.haloSize = configObj.haloSize;
+ this.haloSizeSelect.set('value', configObj.haloSize);
+
+ if ("undefined" === typeof configObj.haloColor || "" === configObj.haloColor) {
+ configObj.haloColor = this._DEFAULT_CONFIG.haloColor;//"#FFFFFF";
+ }
+ this.config.haloColor = configObj.haloColor;
+
+ html.setStyle(this.textColorPicker.domNode, 'backgroundColor', this.config.textColor);
+ this.textColorPicker.picker.refreshRecords();
+ this.textColorPicker.picker.setColor(this.config.textColor, false, true);
+
+ html.setStyle(this.haloColorPicker.domNode, 'backgroundColor', this.config.haloColor);
+ this.haloColorPicker.picker.refreshRecords();
+ this.haloColorPicker.picker.setColor(this.config.haloColor, false, true);
+
+ if ("undefined" === typeof configObj.haloOn || "" === configObj.haloOn) {
+ configObj.haloOn = this._DEFAULT_CONFIG.haloOn;//"#FFFFFF";
+ }
+ this.showHalo.set("checked",this.config.haloOn);
+ },
+
+ setTextSize: function (size) {
+ if (size !== this.textSizeSelect.getValue()) {
+ this.textSizeSelect.set('value', size);
+ }
+
+ if (size !== this.textSizeSlider.getValue()) {
+ if (size > this._MAX_TEXT_SIZE) {
+ size = this._MAX_TEXT_SIZE;
+ } else if (size < this._MIN_TEXT_SIZE) {
+ size = this._MIN_TEXT_SIZE;
+ }
+ this.textSizeSlider.set('value', size);
+ }
+ },
+
+ fontBtnClickd: function (fontConfig) {
+ if (true === fontConfig.bold) {
+ html.addClass(this.bold, "selected");
+ } else if (false === fontConfig.bold) {
+ html.removeClass(this.bold, "selected");
+ }
+
+ if (true === fontConfig.italic) {
+ html.addClass(this.italic, "selected");
+ } else if (false === fontConfig.italic) {
+ html.removeClass(this.italic, "selected");
+ }
+
+ if (true === fontConfig.underline) {
+ html.addClass(this.underline, "selected");
+ } else if (false === fontConfig.underline) {
+ html.removeClass(this.underline, "selected");
+ }
+ },
+
+ _initAppearance: function () {
+ if (this.appearance) {
+ if (false === this.appearance.bold) {
+ html.addClass(this.bold, "hide");
+ }
+ if (false === this.appearance.italic) {
+ html.addClass(this.italic, "hide");
+ }
+ if (false === this.appearance.underline) {
+ html.addClass(this.underline, "hide");
+ }
+ }
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/js/GridPolygon.js b/GRG/js/GridPolygon.js
new file mode 100644
index 0000000..75644de
--- /dev/null
+++ b/GRG/js/GridPolygon.js
@@ -0,0 +1,186 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+/**
+ * @fileOverview Contains the GridPolygon class used by GRG widget.
+ * @author Esri
+ *
+ * @todo Review, add and cleanup the code comments (including JSDoc comments)
+ */
+
+define([
+ "dojo/_base/declare"
+], function(
+ declare
+) {
+
+ /**
+ * @classdesc A GridPolygon object is derived by taking a parent (non-clipped) grid polygon,
+ * along with the same polygon clipped by the current map screen extent
+ * (clippedPolygon) and used for deriving labels and priority
+ *
+ * @constructor
+ * @param {Object}
+ * properties
+ * The GridPolygon constructor takes an object as described below
+ * @param {external:Polygon}
+ * properties.unclippedPolygon
+ * A geometry Polygon object that represents the non-clipped geometry of the grid polygon
+ * @param {external:Polygon}
+ * properties.clippedPolygon
+ * A geometry Polygon object that represents the visible portion of the unclipped polygon
+ * @param {external:Map}
+ * properties.map
+ * The Map object that is tied to the Grid Overlay
+ * @param {Number}
+ * properties.xmin
+ * The minimum x-coordinate value of the unclipped polygon
+ * (the coordinate units are specified in the minMaxType property)
+ * @param {Number}
+ * properties.ymin
+ * The minimum y-coordinate value of the unclipped polygon
+ * (the coordinate units are specified in the minMaxType property)
+ * @param {Number}
+ * properties.xmax
+ * The maximum x-coordinate value of the unclipped
+ * polygon (the coordinate units are specified in the minMaxType property)
+ * @param {Number}
+ * properties.ymax
+ * The maximum y-coordinate value of the unclipped polygon
+ * (the coordinate units are specified in the minMaxType property)
+ * @param {String}
+ * [properties.minMaxType="degrees"]
+ * The type of unit for the min and max coordinate values ""
+ * @param {Number}
+ * [properties.utmZone=0]
+ * If minMaxType is "utm", then this poperty holds the utm zone number
+ * @param {String}
+ * properties.text
+ *
+ * @todo Review, add and cleanup the code comments (including JSDoc comments)
+ */
+ return declare(null, {
+ /** A geometry Polygon object that represents the clipped geometry of the grid polygon
+ * @type external:Polygon
+ */
+ "clippedPolygon": null,
+
+ /** A geometry Polygon object that represents the visible portion of the unclipped polygon
+ * @type external:Polygon
+ */
+ "unclippedPolygon": null,
+
+ /** A geometry Polygon object that represents the visible portion of the clipped polygon to the full utm zone
+ * @type external:Polygon
+ */
+ "clippedPolyToUTMZone": null,
+
+ /** The Map object that is tied to the Grid Overlay
+ * @type external:Polygon
+ */
+ "utmZonePoly": null,
+
+ /** A geometry Polygon object that represents the full utm zone geometry
+ * @type external:Polygon
+ */
+ "fullZoneGeometry": null,
+
+ /** A geometry Polygon object that represents utm zone
+ * @type external:Map
+ */
+ "map": null,
+
+ /** The minimum x-coordinate value of the unclipped polygon
+ (the coordinate units are specified in the minMaxType property)
+ * @type Number
+ */
+ "xmin": 0,
+
+ /** The minimum y-coordinate value of the unclipped polygon
+ (the coordinate units are specified in the minMaxType property)
+ * @type Number
+ */
+ "ymin": 0,
+
+ /** The minimum x-coordinate value of the unclipped polygon
+ (the coordinate units are specified in the minMaxType property)
+ * @type string
+ */
+ "x": '',
+
+ /** The minimum y-coordinate value of the unclipped polygon
+ (the coordinate units are specified in the minMaxType property)
+ * @type string
+ */
+ "y": '',
+
+ /** The maximum x-coordinate value of the unclipped polygon
+ (the coordinate units are specified in the minMaxType property)
+ * @type Number
+ */
+ "xmax": 0,
+
+ /** The maximum y-coordinate value of the unclipped polygon
+ (the coordinate units are specified in the minMaxType property)
+ * @type Number
+ */
+ "ymax": 0,
+
+ /** The type of unit for the min and max coordinate values ""
+ * @type String
+ */
+ "minMaxType": "",
+
+ /** If minMaxType is "utm", then this poperty holds the utm zone number
+ * @type Number
+ */
+ "utmZone": 0,
+
+ /** If grid is 100k or less then this property holds the 100k GZD
+ * @type String
+ */
+ "latitudeZone": "",
+
+ /** If grid is 100k or less then this property holds the latitude zone
+ * @type String
+ */
+ "GZD": "",
+
+ /** The label text for the polygon
+ * @type String
+ */
+ "text": "",
+
+ constructor: function(args) {
+ this.unclippedPolygon = args.unclippedPolygon;
+ this.clippedPolygon = args.clippedPolygon;
+ this.utmZonePoly = args.utmZonePoly;
+ this.fullZoneGeometry = args.fullZoneGeometry;
+ this.clippedPolyToUTMZone = args.clippedPolyToUTMZone;
+ this.map = args.map;
+ this.xmin = args.xmin;
+ this.ymin = args.ymin;
+ this.xmax = args.xmax;
+ this.ymax = args.ymax;
+ this.x = args.x;
+ this.y = args.y;
+ this.minMaxType = args.minMaxType;
+ this.utmZone = Math.round(args.utmZone);
+ this.latitudeZone = args.latitudeZone;
+ this.GZD = args.GZD;
+ this.text = args.text;
+ }
+ });
+});
\ No newline at end of file
diff --git a/GRG/js/GridSettings.js b/GRG/js/GridSettings.js
new file mode 100644
index 0000000..452ad61
--- /dev/null
+++ b/GRG/js/GridSettings.js
@@ -0,0 +1,304 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/array',
+ 'dojo/_base/html',
+ 'dojo/on',
+ './ColorPickerEditor',
+ './FontSetting',
+ 'jimu/BaseWidget',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!../templates/GridSettings.html',
+ 'dojo/_base/lang',
+ 'dojo/Evented',
+ 'dojo/dom-class',
+ 'dojo/query',
+ 'dijit/registry',
+ 'dijit/form/Select'
+],
+ function (
+ declare,
+ array,
+ html,
+ on,
+ ColorPickerEditor,
+ FontSetting,
+ BaseWidget,
+ _WidgetsInTemplateMixin,
+ GridSettingsTemplate,
+ lang,
+ Evented,
+ domClass,
+ query,
+ dijitRegistry
+ ) {
+ return declare([BaseWidget, _WidgetsInTemplateMixin, Evented], {
+ baseClass: 'jimu-widget-GRGDrafter-Settings',
+ templateString: GridSettingsTemplate,
+ selectedGridSettings: {}, //Holds selected Settings
+ _defaultColor: '#1a299c',
+ _defaultTextSize: 12,
+ _defaultFont: {"font": {"fontFamily": "Arial","bold": false,"italic": false,"underline": false},"fontSize": 12,"textColor": "#2f4f4f"},
+ gridSettingsOptions: {
+ "cellShape": ["default", "hexagon"],
+ "cellUnits": ["meters", "kilometers", "miles", "nautical-miles", "yards", "feet"],
+ "labelStartPosition": ["lowerLeft", "lowerRight", "upperLeft", "upperRight"],
+ "labelType": ["alphaNumeric", "alphaAlpha", "numeric"],
+ "labelDirection": ["horizontal", "vertical"],
+ "gridOrigin": ["center", "lowerLeft", "lowerRight", "upperLeft", "upperRight"],
+ "referenceSystem": ["MGRS", "USNG"]
+ }, //Object that holds all the options and their keys
+
+ constructor: function (options) {
+ lang.mixin(this, options);
+ },
+
+ //Load all the options on startup
+ startup: function () {
+
+ this.gridOutlineColorPicker = new ColorPickerEditor({nls: this.nls}, this.cellOutlineColorPicker);
+ this.gridOutlineColorPicker.setValues({
+ "color": this.config.grg.cellOutline.color,
+ "transparency": this.config.grg.cellOutline.transparency
+ });
+ this.gridOutlineColorPicker.startup();
+
+
+ this.gridFillColorPicker = new ColorPickerEditor({nls: this.nls}, this.cellFillColorPicker);
+ this.gridFillColorPicker.setValues({
+ "color": this.config.grg.cellFill.color,
+ "transparency": this.config.grg.cellFill.transparency
+ });
+ this.gridFillColorPicker.startup();
+
+
+ this.fontSetting = new FontSetting({
+ config: this.config.grg.font || this._defaultFont,
+ nls: this.nls
+ }, this.fontSettingNode);
+
+ this.fontSetting.startup();
+
+ //load options for all drop downs
+ this._loadOptionsForDropDown(this.cellShape, this.gridSettingsOptions.cellShape);
+ this._loadOptionsForDropDown(this.labelStartPosition, this.gridSettingsOptions.labelStartPosition);
+ this._loadOptionsForDropDown(this.cellUnits, this.gridSettingsOptions.cellUnits);
+ this._loadOptionsForDropDown(this.labelType, this.gridSettingsOptions.labelType);
+ this._loadOptionsForDropDown(this.labelDirection, this.gridSettingsOptions.labelDirection);
+ this._loadOptionsForDropDown(this.gridOrigin, this.gridSettingsOptions.gridOrigin);
+ this._loadOptionsForDropDown(this.referenceSystem, this.gridSettingsOptions.referenceSystem);
+
+ if(this.config.grg) {
+ this.cellShape.setValue(this.config.grg.cellShape);
+ this.cellUnits.setValue(this.config.grg.cellUnits);
+ this.gridOrigin.setValue(this.config.grg.gridOrigin);
+ this.labelType.setValue(this.config.grg.labelType);
+ this.labelDirection.setValue(this.config.grg.labelDirection);
+ this.labelStartPosition.setValue(this.config.grg.labelOrigin);
+ this.referenceSystem.setValue(this.config.grg.referenceSystem);
+
+ if(this.cellShape.get('value') == 'hexagon') {
+ this.labelDirection.set('disabled',true);
+ this.labelDirection.setValue('horizontal');
+ } else {
+ this.labelDirection.set('disabled',false);
+ }
+ }
+
+ //send by default updated parameters
+ this.onGridsettingsChanged();
+
+
+ },
+
+ postCreate: function () {
+ this.inherited(arguments);
+ //set class to main container
+ domClass.add(this.domNode, "GRGDrafterSettingsContainer GRGDrafterFullWidth");
+ this._handleClickEvents();
+ },
+
+ /**
+ * Handle click events for different controls
+ * @memberOf widgets/GRG/Widget
+ **/
+ _handleClickEvents: function () {
+ //handle grid settings button clicked
+ this.own(on(this.gridSettingsButton, "click", lang.hitch(this, function () {
+ if(domClass.contains(this.gridSettingsButton,'GRGDrafterLabelSettingsDownButton')) {
+ //in closed state - so open and change arrow to up
+ html.removeClass(this.gridSettingsContainer, 'controlGroupHidden');
+ html.removeClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ html.addClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ //close label settings if open
+ html.addClass(this.labelSettingsContainer, 'controlGroupHidden');
+ html.removeClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ html.addClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ } else {
+ //in open state - so close and change arrow to down
+ html.addClass(this.gridSettingsContainer, 'controlGroupHidden');
+ html.addClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ }
+ })));
+
+ //handle label settings button clicked
+ this.own(on(this.labelSettingsButton, "click", lang.hitch(this, function () {
+ if(domClass.contains(this.labelSettingsButton,'GRGDrafterLabelSettingsDownButton')) {
+ //in closed state - so open and change arrow to up
+ html.removeClass(this.labelSettingsContainer, 'controlGroupHidden');
+ html.removeClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ html.addClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ //close label settings if open
+ html.addClass(this.gridSettingsContainer, 'controlGroupHidden');
+ html.removeClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ html.addClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ } else {
+ //in open state - so close and change arrow to down
+ html.addClass(this.labelSettingsContainer, 'controlGroupHidden');
+ html.addClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ }
+ })));
+
+ this.own(on(this.cellShape, 'change', lang.hitch(this, function () {
+ if(this.cellShape.get('value') == 'hexagon') {
+ this.labelDirection.set('disabled',true);
+ this.labelDirection.setValue('horizontal');
+ } else {
+ this.labelDirection.set('disabled',false);
+ }
+ })));
+ },
+
+
+ /**
+ * Add options to passed dropdown
+ * @memberOf widgets/GRGDrafter/Settings
+ **/
+ _loadOptionsForDropDown: function (dropDown, dropDownOptions) {
+ var options = [], option;
+ //Add options for selected dropdown
+ array.forEach(dropDownOptions, lang.hitch(this, function (type) {
+ if (this.nls.gridSettings[type].hasOwnProperty("label")) {
+ option = { value: type, label: this.nls.gridSettings[type].label };
+ } else {
+ option = { value: type, label: this.nls.gridSettings[type] };
+ }
+ options.push(option);
+ }));
+ dropDown.addOption(options);
+ },
+
+ /**
+ * Return's flag based on plan settings are changed or not
+ * @memberOf widgets/GRGDrafter/Settings
+ **/
+ _isSettingsChanged: function () {
+ var isDataChanged = false;
+ //check if cellShape is changed
+ if (this.selectedGridSettings.cellShape !==
+ this.cellShape.get('value')) {
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.labelStartPosition !==
+ this.labelStartPosition.get('value')) {
+ //check if labelStartPosition is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.cellUnits !==
+ this.cellUnits.get('value')) {
+ //check if cellUnits is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.labelType !==
+ this.labelType.get('value')) {
+ //check if labelType is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.labelDirection !==
+ this.labelDirection.get('value')) {
+ //check if labelDirection is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.gridOrigin !==
+ this.gridOrigin.get('value')) {
+ //check if gridOrigin is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.referenceSystem !==
+ this.referenceSystem.get('value')) {
+ //check if reference system is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.gridOutlineColor !==
+ this.gridOutlineColorPicker.getValues().color) {
+ //check if grid Outline Color is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.gridOutlineTransparency !==
+ this.gridOutlineColorPicker.getValues().transparency) {
+ //check if grid Outline transparency is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.gridFillColor !==
+ this.gridFillColorPicker.getValues().color) {
+ //check if grid Fill Color is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.gridFillTransparency !==
+ this.gridFillColorPicker.getValues().transparency) {
+ //check if grid Fill transparency is changed
+ isDataChanged = true;
+ } else if (this.selectedGridSettings.fontSettings !==
+ this.fontSetting.getConfig()) {
+ //check if font settings is changed
+ isDataChanged = true;
+ }
+ return isDataChanged;
+ },
+
+ /**
+ * Update's Settings on close of the widget
+ * @memberOf widgets/GRGDrafter/Settings
+ **/
+ onClose: function () {
+ if (this._isSettingsChanged()) {
+ this.onGridsettingsChanged();
+ }
+ html.addClass(this.gridSettingsContainer, 'controlGroupHidden');
+ html.addClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.labelSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ html.addClass(this.labelSettingsContainer, 'controlGroupHidden');
+ html.addClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsDownButton');
+ html.removeClass(this.gridSettingsButton, 'GRGDrafterLabelSettingsUpButton');
+ },
+
+ /**
+ * Set's the selectedGridSettings on any value change
+ * @memberOf widgets/GRGDrafter/Settings
+ **/
+ onGridsettingsChanged: function () {
+ this.selectedGridSettings = {
+ "cellShape": this.cellShape.get('value'),
+ "labelStartPosition": this.labelStartPosition.get('value'),
+ "cellUnits": this.cellUnits.get('value'),
+ "labelType": this.labelType.get('value'),
+ "labelDirection": this.labelDirection.get('value'),
+ "gridOrigin": this.gridOrigin.get('value'),
+ "referenceSystem": this.referenceSystem.get('value'),
+ "gridOutlineColor": this.gridOutlineColorPicker.getValues().color,
+ "gridOutlineTransparency": this.gridOutlineColorPicker.getValues().transparency,
+ "gridFillColor": this.gridFillColorPicker.getValues().color,
+ "gridFillTransparency": this.gridFillColorPicker.getValues().transparency,
+ "fontSettings": lang.clone(this.fontSetting.getConfig()),
+ };
+ this.emit("gridSettingsChanged", this.selectedGridSettings);
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/js/NonPolarGridZone.js b/GRG/js/NonPolarGridZone.js
new file mode 100644
index 0000000..98787a4
--- /dev/null
+++ b/GRG/js/NonPolarGridZone.js
@@ -0,0 +1,172 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+/**
+ * @fileOverview Contains the NonPolarGridZone class used by GRG widget.
+ * @author Esri
+ */
+
+define([
+ "dojo/_base/declare",
+ "dojo/json",
+ "./constants",
+ "esri/geometry/Polygon",
+ "esri/geometry/Extent"
+], function(
+ declare,
+ JSON,
+ constants,
+ Polygon,
+ Extent
+) {
+
+ /**
+ * An object that contains arguments used during NonPolarGridZone construction
+ * @typedef {Object} module:mgrs-utils~NonPolarGridZoneArguments
+ * @property {String} properties.id The MGRS grid zone ID (e.g. "12S")
+ * @property {Number} properties.xmin The minimum longitude of the grid zone (-180 => 174)
+ * @property {Number} properties.ymin The minimum latitude of the grid zone (-80 => 72)
+ * @property {Number} properties.xmax The maximum longitude of the grid zone (-174 => 180)
+ * @property {Number} properties.ymax The maximum latitude of the grid zone (-72 => 84)
+ * @property {external:SpatialReference}
+ * [properties.spatialReference={wkid: 4326}] The spatial referencence object
+ */
+
+ /**
+ * @class module:mgrs-utils~NonPolarGridZone
+ * @classdesc Contains the properties of a non-polar MGRS grid zone,
+ * as defined in the MGRS definition.
+ *
+ * @constructor
+ * @param {module:mgrs-utils~NonPolarGridZoneArguments} args
+ * The NonPolarGridZone constructor arguments object
+ *
+ * @example
+ * var nonPolarGridZoneArgs = {
+ * xmin: -114,
+ * ymin: 32,
+ * xmax: -108,
+ * ymax: 40,
+ * id: "12S"
+ * }
+ *
+ * // gridZone will be an object equivalent to:
+ * // {
+ * // "id": "12S",
+ * // "utmZone": 12,
+ * // "latitudeZone": "S",
+ * // "extent": {
+ * // "type": "extent",
+ * // "xmin": -114,
+ * // "ymin": 32,
+ * // "xmax": -108,
+ * // "ymax": 40,
+ * // "spatialReference": {"wkid": 4326}
+ * // }
+ * // }
+ * var gridZone = new NonPolarGridZone(nonPolarGridZoneArgs);
+ */
+ return declare(null, /** @lends module:mgrs-utils~NonPolarGridZone# */ {
+
+ /** The extent of the grid zone
+ * @type {external:Extent}
+ */
+ "extent": null,
+
+ /** The MGRS grid zone ID (or label; e.g. "12S")
+ * @type {String}
+ */
+ "id": null,
+
+ /** The UTM longitude zone (usually 6° wide)
+ * @type {Number}
+ */
+ "utmZone": null,
+
+ /** The latitude zone (usually 8° tall)
+ * @type {String}
+ */
+ "latitudeZone": null,
+
+ /** An array of rings, used to construct a polygon from the NonPolarGridZone
+ * @type {Number[][][]}
+ * @private
+ */
+ "_rings": [],
+
+ constructor: function(args) {
+ var lowerLeftCorner, lowerRightCorner, upperRightCorner, upperLeftCorner;
+
+ // parse and set the UTM zone and latitude zone from the id
+ // (i.e. "12S" would parse to ['12', 'S'])
+ var parseId = args.id.match(/(\d+)|([A-Za-z]+)/g);
+ this.id = args.id;
+ this.utmZone = parseId[0] * 1;
+ this.latitudeZone = parseId[1];
+
+ // create the extent object for this instance
+ this.extent = new Extent({
+ "xmin": args.xmin,
+ "ymin": args.ymin,
+ "xmax": args.xmax,
+ "ymax": args.ymax,
+ "spatialReference": args.spatialReference || {wkid: 4326}
+ });
+
+ // Construct rings to be used later to construct a polygon
+ // from a NonPolarGridZone instance.
+ // Don't create the polygon now, because the same instance
+ // is reused as the map is in wraparound mode.
+ // Thus, the 'toPolygon' method is used for retreiving a polygon when needed
+ lowerLeftCorner = [this.extent.xmin, this.extent.ymin];
+ lowerRightCorner = [this.extent.xmax, this.extent.ymin];
+ upperRightCorner = [this.extent.xmax, this.extent.ymax];
+ upperLeftCorner = [this.extent.xmin, this.extent.ymax];
+ this._rings = [[
+ lowerLeftCorner,
+ lowerRightCorner,
+ upperRightCorner,
+ upperLeftCorner,
+ lowerLeftCorner
+ ]];
+ },
+
+ /**
+ * Convert to a polygon
+ * @param {Number} [offsetX=0] Instruction to return a non-normalized polygon
+ * (i.e. falls outside the normal world extent)
+ * Used for drawing grids when a map is in wraparound mode
+ * NOTE: Specify a negative integer for west of W180° OR a positive integer for east of E180°
+ * @return {external:Polygon} The zone, represented as a Polygon
+ */
+ toPolygon: function(offsetX) {
+ var rings = JSON.parse(JSON.stringify(this._rings));
+
+ // Shift the rings left/right to match the x-offset (i.e. how many increments left or right
+ // of the dateline, to support wraparound maps)
+ if (offsetX) {
+ for (var i = 0; i < rings[0].length; i++) { // modify the zone paths for x_offset
+ rings[0][i][0] += offsetX * constants.GEOGRAPHIC_360;
+ }
+ }
+
+ // build and return the polygon
+ return new Polygon({
+ "rings": rings,
+ "spatialReference": this.spatialReference
+ });
+ }
+ });
+});
\ No newline at end of file
diff --git a/GRG/js/TransparencyEditor.js b/GRG/js/TransparencyEditor.js
new file mode 100644
index 0000000..88cc56e
--- /dev/null
+++ b/GRG/js/TransparencyEditor.js
@@ -0,0 +1,99 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/_base/Color',
+ 'dojo/on',
+ 'dojo/query',
+ 'dojo/Stateful',
+ 'dojo/_base/html',
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!../templates/TransparencyEditor.html',
+ 'dijit/form/HorizontalSlider',
+ "dijit/form/NumberSpinner"
+ ],
+ function(declare, lang, Color, on, query, dojoStateful, html,
+ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template,
+ HorizontalSlider) {
+ return declare([dojoStateful, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
+ templateString: template,
+ transparency: 1,
+
+ postCreate: function() {
+ this.slider = new HorizontalSlider({
+ name: "slider",
+ value: 0,
+ minimum: 0,
+ maximum: 100,
+ discreteValues: 101,
+ intermediateChanges: true,
+ showButtons: false,
+ style: "width:140px;display: inline-block;"
+ }, this.sliderBar);
+ this.slider.startup();
+ this.inherited(arguments);
+ },
+ startup: function() {
+ this.own(on(this.slider, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.spinner.setValue(val);
+ this._set("transparency", val/100);
+ }
+ })));
+
+ this.own(on(this.spinner, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.slider.setValue(val);
+ this._set("transparency", val/100);
+ }
+ })));
+
+ this._stylePolyfill();
+ this.inherited(arguments);
+ },
+ _isSameVal: function() {
+ return this.slider.getValue() === this.spinner.getValue();
+ },
+ getValues: function() {
+ var a = null;
+ a = this.spinner.getValue() / 100;
+ return {
+ transparency: a
+ };
+ },
+ setValues: function(obj) {
+ if (typeof obj === "object" || typeof obj === "string") {
+ if (typeof obj.transparency === "undefined") {
+ obj.transparency = 0;
+ } else {
+ obj.transparency = obj.transparency * 100;
+ }
+ this.slider.setValue(obj.transparency);
+ this.spinner.setValue(obj.transparency);
+ }
+ },
+ _stylePolyfill: function() {
+ var leftBumper = query('.dijitSliderLeftBumper', this.domNode)[0];
+ if (leftBumper && leftBumper.parentNode) {
+ html.setStyle(leftBumper.parentNode, 'background-color', "#24b5cc");
+ }
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/js/VisibleGridZone.js b/GRG/js/VisibleGridZone.js
new file mode 100644
index 0000000..1ad3353
--- /dev/null
+++ b/GRG/js/VisibleGridZone.js
@@ -0,0 +1,128 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ * @fileOverview Contains the VisibleGridZone class used by MGRS GRG widget.
+ * @author Esri
+ */
+
+define([
+ "dojo/_base/declare",
+ "./GridPolygon"
+], function(
+ declare,
+ GridPolygon
+) {
+
+ /**
+ * @class module:mgrs-utils~VisibleGridZone
+ * @classdesc A VisibleGridZone object is derived by taking a NonPolarGridZone object
+ * and displaying it on screen. It holds all the parameters needed to draw and label
+ * the visible portion of the NonPolarGridZone.
+ *
+ * @constructor
+ * @param {Object}
+ * properties
+ * The VisibleGridZone constructor takes an object as described below
+ * @param {external:Polygon}
+ * properties.polygon
+ * The visible area of the grid zone
+ * @param {Number}
+ * [properties.offset=0]
+ * The non-normalized x-offset of the grid
+ * @param {module:mgrs-utils~NonPolarGridZone}
+ * properties.nonPolarGridZone
+ *The NonPolarGridZone object that is related to this VisibleGridZone object
+ * @param {external:Map}
+ * properties.map
+ * The Map object that the grid overlay is associated with
+ *
+ * @example
+ * var offset = -1; // in this case, the current longitude is in the range -540 => -180
+ * var nonPolarGridZone = ZonesDictionary["42S"];
+ * var zonePolygon = nonPolarGridZone.toPolygon(offset);
+ *
+ * convert zonePolygon to web mercator so it can be used with the
+ * geometryEngine.intersect method
+ * zonePolygon = webMercatorUtils.geographicToWebMercator(zonePolygon);
+ * var clippedPolygon = geometryEngine.intersect(zonePolygon, map.extent);
+ *
+ * visibleGridZone = new VisibleGridZone({
+ * "map": map,
+ * "polygon": zonePolygon,
+ * "offset": 0,
+ * "nonPolarGridZone": nonPolarGridZone
+ * });
+ */
+ return declare(null, /** @lends module:mgrs-utils~VisibleGridZone# */ {
+
+ /** The clipped portion of the grid zone polygon that represents the visible area
+ * @type {external:Polygon}
+ */
+ "polygon": null,
+
+ /** The non-normalized x-offset of the grid. This allows for grid overlays
+ * to be drawn in wraparound mound
+ * (i.e. spanning accross the Dateline).
+ * For Example: An offset of 0 means the x-coordinate is in the longitude range of -180 => 180,
+ * and an offset of -1 correlates to the range of -540 => -180.
+ * @type {Number}
+ */
+ "offset": null,
+
+ /** The original NonPolarGridZone object, before it was clipped for visible area
+ * @type {module:mgrs-utils~NonPolarGridZone}
+ */
+ "nonPolarGridZone": null,
+
+ /** A polygon of the full UTM Zone
+ * @type {external:Polyline}
+ */
+ "fullZoneGeometry": null,
+
+ /** The Map object that this grid overlay is associated with
+ * @type {external:Map}
+ */
+ "map": null,
+
+ constructor: function(args) {
+ // offset must be an integer
+ this.offset = Math.round(args.offset);
+ this.polygon = args.polygon;
+ this.nonPolarGridZone = args.nonPolarGridZone;
+ this.fullZoneGeometry = args.fullZoneGeometry;
+ this.map = args.map;
+ this.utmZone = args.utmZone;
+ this.latitudeBand = args.latitudeBand;
+
+ // construct a GridPolygon, which is used as the label manager
+ var gridPolygonArgs = {
+ "clippedPolygon": this.polygon,
+ "unclippedPolygon": this.nonPolarGridZone.toPolygon(args.offset),
+ "map": this.map,
+ "xmin": this.nonPolarGridZone.extent.xmin,
+ "ymin": this.nonPolarGridZone.extent.ymin,
+ "xmax": this.nonPolarGridZone.extent.xmax,
+ "ymax": this.nonPolarGridZone.extent.ymax,
+ "minMaxType": "degrees",
+ "utmZone": this.utmZone,
+ "text": this.nonPolarGridZone.id,
+ "latitudeBand": this.latitudeBand
+ };
+ this.gridPolygon = new GridPolygon(gridPolygonArgs);
+ }
+ });
+});
\ No newline at end of file
diff --git a/GRG/js/constants.js b/GRG/js/constants.js
new file mode 100644
index 0000000..5f53e7f
--- /dev/null
+++ b/GRG/js/constants.js
@@ -0,0 +1,160 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+/**
+ * @fileOverview Contains constants used by GRG widget.
+ * @author Esri
+ */
+
+/**
+ * @module constants
+ * @description Contains constants used by GRG widgets.
+ * @author Esri
+ */
+
+define([], function() {
+
+ /** @namespace */
+ return {
+
+ /**
+ * MGRS zones are 6 degrees wide
+ * @instance
+ * @default
+ */
+ "ZONE_WIDTH_DEGREES": 6,
+
+ /**
+ * MGRS zones are 8 degrees tall
+ * @instance
+ * @default
+ */
+ "ZONE_HEIGHT_DEGREES": 8,
+
+ /**
+ * MGRS is only valid between -80 -> 84 degrees latitude
+ * @instance
+ * @default
+ */
+ "MIN_MGRS_LATITUDE": -80,
+
+ /**
+ * MGRS is only valid between -80 -> 84 degrees latitude
+ * @instance
+ * @default
+ */
+ "MAX_MGRS_LATITUDE": 84,
+
+ /**
+ * Used to convert 180 to a slightly smaller number since it
+ * causes problems when drawing graphics
+ * @instance
+ * @default
+ */
+ "POSITIVE_180": 179.99999999,
+
+ /**
+ * Used to convert -180 to a slightly larger number since
+ * it causes problems when drawing graphics
+ * @instance
+ * @default
+ */
+ "NEGATIVE_180": -179.99999999,
+
+ /**
+ * The westernmost, normalized Geographic longitude
+ * (i.e. the International Date Line; longitude 180°W)
+ * @instance
+ * @default
+ */
+ "WEST_GEOGRAPHIC_LIMIT": -180,
+
+ /**
+ * The easternmost, normalized Geographic longitude
+ * (i.e. the International Date Line; longitude 180°E)
+ * @instance
+ * @default
+ */
+ "EAST_GEOGRAPHIC_LIMIT": 180,
+
+ /**
+ * The westernmost, normalized Web Mercator x
+ * (i.e. the International Date Line; longitude 180°W)
+ * @instance
+ * @default
+ */
+
+ /**
+ * The entire span of the X axis in Geographics degrees (360° of longitude)
+ * @instance
+ * @default
+ */
+ "GEOGRAPHIC_360": 360,
+
+ "WEST_WEBMERCATOR_LIMIT": -20037508.342789244,
+
+ /**
+ * The easternmost, normalized Web Mercator x
+ * (i.e. the International Date Line; longitude 180°E)
+ * @instance
+ * @default
+ */
+ "EAST_WEBMERCATOR_LIMIT": 20037508.342789244,
+
+ /**
+ * The entire span of the X axis in web mercator units (equivalent to 360° of longitude)
+ * @instance
+ * @default
+ */
+ "WEBMERCATOR_360": 40075016.68557849,
+
+ /**
+ * Defined by the equation: 360° / (2 * Math.PI)
+ * @instance
+ * @default
+ */
+ "DEGREES_PER_RADIAN": 57.29577951308232,
+
+ /**
+ * Defined by the equation: (2 * Math.PI) / 360°
+ * @instance
+ * @default
+ */
+ "RADIANS_PER_DEGREE": 0.017453292519943295,
+
+ /**
+ * The equatorial radius of the earth, using reference earth model WGS84
+ * @instance
+ * @default
+ */
+ "WGS84_EQUATORIAL_RADIUS": 6378137.0,
+
+ /**
+ * One half of the WGS84_EQUATORIAL_RADIUS,
+ * used to slightly speed up conversion to web mercator
+ * @instance
+ * @default
+ */
+ "WGS84_HALF_EQUATORIAL_RADIUS": 3189068.5,
+
+ /**
+ * One half of Math.PI, used to slightly speed up conversion to web mercator
+ * @instance
+ * @default
+ */
+ "HALF_PI": 1.5707963267948966
+
+ };
+});
diff --git a/GRG/js/dialogConfirm.js b/GRG/js/dialogConfirm.js
new file mode 100644
index 0000000..4b550e9
--- /dev/null
+++ b/GRG/js/dialogConfirm.js
@@ -0,0 +1,121 @@
+///////////////////////////////////////////////////////////////////////////
+// Code sourced from https://github.com/speich/DialogConfirm
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/lang',
+ 'dojo/_base/declare',
+ 'dojo/_base/Deferred',
+ 'dojo/dom-construct',
+ 'dijit/Dialog',
+ 'dijit/form/Button',
+ 'dijit/form/CheckBox'
+], function(lang, declare, Deferred, domConstruct, Dialog, Button, Checkbox) {
+
+ /**
+ * @class
+ * @name rfe.DialogConfirm
+ * @extends {dijit.Dialog}
+ * @property {dijit.form.Button} okButton reference to OK button
+ * @property {dijit.form.Button} cancelButton reference to Cancel button
+ * @property {dijit.form.CheckBox} skipCheckBox reference to skipping check box
+ * @property {boolean} hasOkButton create an OK button?
+ * @property {boolean} hasCancelButton create a cancel button
+ * @property {boolean} hasSkipCheckBox create the skipping check box
+ * @property {boolean} hasUnderlay create the dialog underlay?
+ * @property {dojo.Deferred} dfd Deferred
+ * @property {HTMLDivElement} buttonNode reference to div containing buttons
+ */
+ return declare(Dialog, /* @lends rfe.DialogConfirm.prototype */ {
+ okButton: null,
+ cancelButton: null,
+ skipCheckBox: null,
+ hasOkButton: true,
+ hasCancelButton: true,
+ hasSkipCheckBox: true,
+ hasUnderlay: true,
+ dfd: null,
+ buttonNode: null,
+
+ /**
+ * Instantiates the confirm dialog.
+ * @constructor
+ * @param {object} props
+ */
+ constructor: function(props) {
+ lang.mixin(this, props);
+ },
+
+ /**
+ * Creates the OK/Cancel buttons.
+ */
+ postCreate: function() {
+ this.inherited('postCreate', arguments);
+
+ var label, div, remember = false;
+
+ div = domConstruct.create('div', {
+ className: 'dijitDialogPaneContent dialogConfirm'
+ }, this.domNode, 'last');
+
+ if (this.hasSkipCheckBox) {
+ this.skipCheckBox = new Checkbox({
+ checked: false
+ }, domConstruct.create('div'));
+ div.appendChild(this.skipCheckBox.domNode);
+ label = domConstruct.create('label', {
+ 'for': this.skipCheckBox.id,
+ innerHTML: 'Remember my decision and do not ask again. '
+ }, div);
+ }
+ if (this.hasOkButton) {
+ this.okButton = new Button({
+ label: 'OK',
+ onClick: lang.hitch(this, function() {
+ remember = this.hasSkipCheckBox ? this.skipCheckBox.get('checked') : false;
+ this.hide();
+ this.dfd.resolve(remember);
+ })
+ }, domConstruct.create('div'));
+ div.appendChild(this.okButton.domNode);
+ }
+ if (this.hasCancelButton) {
+ this.cancelButton = new Button({
+ label: 'Cancel',
+ onClick: lang.hitch(this, function() {
+ remember = this.hasSkipCheckBox ? this.skipCheckBox.get('checked') : false;
+ this.hide();
+ this.dfd.cancel(remember);
+ })
+ }, domConstruct.create('div'));
+ div.appendChild(this.cancelButton.domNode);
+ }
+ this.buttonNode = div;
+ },
+
+ /**
+ * Shows the dialog.
+ * @return {Deferred}
+ */
+ show: function() {
+ this.inherited('show', arguments);
+ if (!this.hasUnderlay) {
+ domConstruct.destroy(this.id + '_underlay'); // remove underlay
+ }
+ this.dfd = new Deferred();
+ return this.dfd;
+ }
+ });
+});
diff --git a/GRG/js/drawGRG.js b/GRG/js/drawGRG.js
new file mode 100644
index 0000000..74739f5
--- /dev/null
+++ b/GRG/js/drawGRG.js
@@ -0,0 +1,674 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'esri/geometry/Point',
+ 'esri/geometry/Polygon',
+ 'esri/geometry/geometryEngine',
+ 'esri/graphic',
+ 'esri/geometry/webMercatorUtils',
+ 'esri/SpatialReference',
+ 'esri/geometry/Circle',
+ 'esri/request',
+ 'jimu/dijit/Message',
+ 'dojo/json',
+ './geometryUtils'
+], function(
+ Point,
+ Polygon,
+ geometryEngine,
+ Graphic,
+ webMercatorUtils,
+ SpatialReference,
+ EsriCircle,
+ esriRequest,
+ Message,
+ JSON,
+ geometryUtils
+) {
+
+ var grg = {};
+
+ grg.createGRG = function(HorizontalCells,VerticalCells,centerPoint,cellWidth,cellHeight,angle,labelStartPosition,labelStyle,labelDirection,gridStyle,gridOrigin,geodesic,map,geometryService) {
+
+ //set up variables
+ var letterIndex,secondLetterIndex,letter,secondLetter,number;
+ var lastY = -9999;
+ var features = [];
+ var startX = 0;
+ var startY = 0;
+ var radius = (cellWidth/2)/Math.cos(30* Math.PI/180);
+ var startPoint;
+ var nextStartPoint;
+ var hexHorizontalCells = HorizontalCells;
+
+ switch (labelStartPosition) {
+ case 'upperLeft':
+ if(labelDirection == 'horizontal') {
+ letterIndex = VerticalCells - 1;
+ secondLetterIndex = -1;
+ if(labelStyle != 'numeric') {
+ number = 0;
+ } else {
+ number = (VerticalCells - 1) * HorizontalCells;
+ if(gridStyle == "hexagon") {
+ number = number + Math.floor(VerticalCells / 2);
+ }
+ }
+ } else {
+ letterIndex = -1;
+ secondLetterIndex = VerticalCells - 1;
+ if(labelStyle != 'numeric') {
+ number = VerticalCells;
+ }
+ }
+ break;
+ case 'upperRight':
+ if(labelDirection == 'horizontal') {
+ letterIndex = VerticalCells - 1;
+ secondLetterIndex = HorizontalCells;
+ if(labelStyle != 'numeric') {
+ number = HorizontalCells + 1
+ } else {
+ number = (VerticalCells * HorizontalCells) + 1;
+ if(gridStyle == "hexagon") {
+ number = number + Math.floor(VerticalCells / 2);
+ }
+ }
+ } else {
+ if(labelStyle != 'numeric') {
+ number = VerticalCells;
+ } else {
+ number = (VerticalCells * (HorizontalCells + 1));
+ }
+ letterIndex = HorizontalCells;
+ secondLetterIndex = VerticalCells - 1;
+ }
+ break;
+ case 'lowerRight':
+ if(labelDirection == 'horizontal') {
+ letterIndex = 0;
+ secondLetterIndex = HorizontalCells;
+ number = HorizontalCells + 1;
+ } else {
+ letterIndex = HorizontalCells;
+ secondLetterIndex = 0;
+ number = 1;
+ }
+ break;
+ case 'lowerLeft':
+ if(labelDirection == 'horizontal') {
+ letterIndex = 0;
+ number = 0;
+ secondLetterIndex = -1;
+ } else {
+ letterIndex = -1;
+ number = 1;
+ secondLetterIndex = 0;
+ }
+ break;
+ }
+
+ // work out required off set for first point
+ // always draw grid from lower left corner
+ var offsetX = (HorizontalCells*cellWidth)/2;
+ if(gridStyle == "hexagon") {
+ if(VerticalCells%2 == 1){
+ var offsetY = ((((VerticalCells-1)/2) * (radius*3)) + radius)/2;
+ } else {
+ var offsetY = (((VerticalCells/2) * (radius*3)) - (radius/2))/2;
+ }
+ }else{
+ var offsetY = (VerticalCells*cellHeight)/2;
+ }
+
+ for (var i = 1; i <= VerticalCells; i++)
+ {
+ for (var j = 1; j <= HorizontalCells; j++)
+ {
+ if(geodesic) {
+ var polygon = new Polygon();
+ //always draw grid from lower left corner
+ if(i == 1 && j == 1){
+ // the center point needs to be in geographics
+ if(centerPoint.spatialReference.wkid === 102100){
+ centerPoint = webMercatorUtils.webMercatorToGeographic(centerPoint);
+ }
+
+ switch (gridOrigin) {
+ case 'center':
+ startPoint = geometryUtils.getDestinationPoint(centerPoint, 180 + angle, offsetY);
+ startPoint = geometryUtils.getDestinationPoint(startPoint, 270 + angle, offsetX);
+ break;
+ case 'upperLeft':
+ startPoint = geometryUtils.getDestinationPoint(centerPoint, 180 + angle, offsetY*2);
+ break;
+ case 'upperRight':
+ startPoint = geometryUtils.getDestinationPoint(centerPoint, 180 + angle, offsetY*2);
+ startPoint = geometryUtils.getDestinationPoint(startPoint, 270 + angle, offsetX*2);
+ break;
+ case 'lowerRight':
+ startPoint = geometryUtils.getDestinationPoint(centerPoint, 270 + angle, offsetX*2);
+ break;
+ case 'lowerLeft':
+ startPoint = centerPoint;
+ break;
+ }
+ }
+
+ if(gridStyle == "default") {
+ var BL = startPoint;
+ var TL = geometryUtils.getDestinationPoint(BL, 0 + angle, cellHeight)
+ var TR = geometryUtils.getDestinationPoint(TL, 90 + angle, cellWidth);
+ var BR = geometryUtils.getDestinationPoint(TR, 180 + angle, cellHeight);
+ polygon.addRing([[BL.x,BL.y],[TL.x,TL.y],[TR.x,TR.y],[BR.x,BR.y]]);
+ startPoint = BR;
+ } else {
+ var P1 = startPoint;
+ var P2 = geometryUtils.getDestinationPoint(P1, 0 + angle, radius)
+ var P3 = geometryUtils.getDestinationPoint(P2, 60 + angle, radius);
+ var P4 = geometryUtils.getDestinationPoint(P3, 120 + angle, radius);
+ var P5 = geometryUtils.getDestinationPoint(P4, 180 + angle, radius);
+ var P6 = geometryUtils.getDestinationPoint(P5, 240 + angle, radius);
+ polygon.addRing([[P1.x,P1.y],[P2.x,P2.y],[P3.x,P3.y],[P4.x,P4.y],[P5.x,P5.y],[P6.x,P6.y]]);
+ startPoint = geometryUtils.getDestinationPoint(startPoint, 90 + angle, cellWidth);
+ }
+
+ /*
+ For some reason if the angle is over below -45 or over 45 then the label will not show
+ running the polygon through a simplify operation fixes this
+ */
+ polygon = geometryEngine.simplify(polygon);
+
+ //project the geometry to the same spatial reference as the map
+ if(map.spatialReference.wkid != 4326){
+ polygon = webMercatorUtils.geographicToWebMercator(polygon);
+ }
+ var graphic = new Graphic(polygon);
+
+ if(j == 1){
+ if(gridStyle == "hexagon") {
+ if(hexHorizontalCells == HorizontalCells){
+ nextStartPoint = geometryUtils.getDestinationPoint(P2, 300 + angle, radius);
+ } else {
+ nextStartPoint = P3;
+ }
+
+ } else {
+ nextStartPoint = TL;
+ }
+ }
+
+ } else {
+ var polygon = new Polygon(new SpatialReference({wkid:102100}));
+
+ if(centerPoint.spatialReference.wkid === 4326){
+ centerPoint = webMercatorUtils.geographicToWebMercator(centerPoint);
+ }
+
+ switch (gridOrigin) {
+ case 'center':
+ startX = centerPoint.x - offsetX;
+ startY = centerPoint.y - offsetY;
+ break;
+ case 'upperLeft':
+ startX = centerPoint.x;
+ startY = centerPoint.y - (offsetY * 2);
+ break;
+ case 'upperRight':
+ startX = centerPoint.x - (offsetX * 2);
+ startY = centerPoint.y - (offsetY * 2);
+ break;
+ case 'lowerRight':
+ startX = centerPoint.x - (offsetX*2);
+ startY = centerPoint.y;
+ break;
+ case 'lowerLeft':
+ startX = centerPoint.x;
+ startY = centerPoint.y;
+ break;
+ }
+
+ if(gridStyle == "default") {
+ polygon.addRing([
+ [startX + ((j-1) * cellWidth) , startY + ((i-1) * cellHeight)],
+ [startX + ((j-1) * cellWidth) , startY + (i * cellHeight)],
+ [startX + (j * cellWidth) , startY + (i * cellHeight)],
+ [startX + (j * cellWidth) , startY + ((i-1) * cellHeight)],
+ [startX + ((j-1) * cellWidth) , startY + ((i-1) * cellHeight)]
+ ]);
+ } else {
+ hexHorizontalCells == HorizontalCells?startX = startX + ((j-1) * (cellWidth)) + (cellWidth/2):startX = startX + ((j-1) * (cellWidth));
+ startY = (startY + radius) + ((i-1) * (radius*1.5));
+ var hexagonCenter = new Point([startX,startY],new SpatialReference({ wkid:102100 }));
+ var hexagon = new EsriCircle(hexagonCenter, {radius: radius,numberOfPoints: 6});
+ var hexagonRotated = geometryEngine.rotate(hexagon,90,hexagonCenter);
+ polygon.addRing(hexagonRotated.rings[0]);
+ }
+
+ //rotate the graphics as required
+ var polygonRotated = geometryEngine.rotate(polygon, (angle * -1), centerPoint);
+
+ //project the geometry to the same spatial reference as the map
+ if(map.spatialReference.wkid != 102100){
+ polygonRotated = webMercatorUtils.webMercatorToGeographic(polygonRotated);
+ }
+ var graphic = new Graphic(polygonRotated);
+ }
+
+ switch (labelStartPosition) {
+ case 'upperLeft':
+ if(labelDirection == 'horizontal') {
+ secondLetterIndex += 1;
+ number += 1;
+ } else {
+ letterIndex += 1;
+ if(labelStyle == 'numeric'){
+ number = (VerticalCells * j) - (i-1);
+ }
+ }
+ break;
+ case 'lowerLeft':
+ if(labelDirection == 'horizontal') {
+ secondLetterIndex += 1;
+ number += 1;
+ } else {
+ letterIndex += 1;
+ if(labelStyle == 'numeric'){
+ number = (VerticalCells * (j-1)) + i;
+ }
+ }
+ break;
+ case 'upperRight':
+ if(labelDirection == 'horizontal') {
+ number = number - 1;
+ secondLetterIndex = secondLetterIndex - 1;
+ } else {
+ letterIndex = letterIndex - 1;
+ if(labelStyle == 'numeric'){
+ number = number - HorizontalCells;
+ }
+ }
+ break;
+ case 'lowerRight':
+ if(labelDirection == 'horizontal') {
+ number = number - 1;
+ secondLetterIndex = secondLetterIndex - 1;
+ } else {
+ letterIndex = letterIndex - 1;
+ if(labelStyle == 'numeric'){
+ number = (VerticalCells * (HorizontalCells-j)) + i;
+ }
+ }
+ break;
+ }
+
+ letter = grg.convertNumberToLetters(letterIndex);
+ secondLetter = grg.convertNumberToLetters(secondLetterIndex);
+
+ var attr = {};
+
+ switch (labelStyle) {
+ case 'alphaNumeric':
+ attr["grid"] = letter.toString() + number.toString();
+ break;
+ case 'alphaAlpha':
+ attr["grid"] = letter.toString() + '-' + secondLetter.toString();
+ break;
+ case 'numeric':
+ attr["grid"] = number.toString();
+ break
+ }
+
+ graphic.setAttributes(attr);
+ features.push(graphic);
+ }
+
+ startPoint = nextStartPoint;
+
+ if(gridStyle == "hexagon"){hexHorizontalCells == HorizontalCells?HorizontalCells++:HorizontalCells--;}
+
+ switch (labelStartPosition) {
+ case 'upperLeft':
+ if(labelDirection == 'horizontal') {
+ letterIndex = letterIndex - 1;
+ if(labelStyle != 'numeric') {
+ number = 0;
+ } else {
+ if(gridStyle == "hexagon") {
+ number = (number - (2 * hexHorizontalCells)) - 1;
+ } else {
+ number = (number - (2 * HorizontalCells));
+ }
+ }
+ secondLetterIndex = -1;
+ } else {
+ letterIndex = -1;
+ secondLetterIndex = (VerticalCells - (i+1));
+ if(labelStyle != 'numeric') {
+ number = VerticalCells - i;
+ }
+ }
+ break;
+ case 'upperRight':
+ if(labelDirection == 'horizontal') {
+ letterIndex = letterIndex - 1;
+ if (labelStyle != 'numeric')
+ {
+ number = HorizontalCells + 1;
+ }
+ secondLetterIndex = HorizontalCells;
+ } else {
+ if (labelStyle != 'numeric') {
+ number = number - 1;
+ } else {
+ number = (VerticalCells * (HorizontalCells + 1)) - i;
+ }
+ letterIndex = HorizontalCells;
+ secondLetterIndex = secondLetterIndex - 1;
+
+ }
+ break;
+ case 'lowerRight':
+ if(labelDirection == 'horizontal') {
+ letterIndex += 1;
+ if(labelStyle != 'numeric') {
+ number = HorizontalCells + 1;
+ } else {
+ if(gridStyle == "hexagon") {
+ number = (number + (2 * hexHorizontalCells)) + 1;
+ } else {
+ number = (number + (2 * HorizontalCells));
+ }
+ }
+ secondLetterIndex = HorizontalCells;
+ } else {
+ letterIndex = HorizontalCells;
+ secondLetterIndex += 1;
+ if(labelStyle != 'numeric') {
+ number += 1;
+ } else {
+ number = HorizontalCells * i;
+ }
+ }
+ break;
+ case 'lowerLeft':
+ if(labelDirection == 'horizontal') {
+ letterIndex += 1;
+ if (labelStyle != 'numeric') {
+ number = 0;
+ }
+ secondLetterIndex = -1;
+ } else {
+ letterIndex = -1;
+ if (labelStyle != 'numeric') {
+ number += 1;
+ }
+ secondLetterIndex = i;
+ }
+ break;
+ }
+ }
+ return features
+ },
+
+ grg.convertNumberToLetters = function (n) {
+ var ordA = 'A'.charCodeAt(0);
+ var ordZ = 'Z'.charCodeAt(0);
+ var len = ordZ - ordA + 1;
+ var s = "";
+ while(n >= 0) {
+ s = String.fromCharCode(n % len + ordA) + s;
+ n = Math.floor(n / len) - 1;
+ }
+ return s;
+ },
+
+ grg.checkGridSize = function (numCellsHorizontal,numCellsVertical) {
+ var totalNumber = numCellsHorizontal*numCellsVertical;
+ if(totalNumber > 2000) {
+ // Invalid entry
+ var alertMessage = new Message({
+ message: 'You are attempting to create a grid comprising of ' + parseInt(totalNumber) + ' cells. It is advisable to reduce the number of cells being created by changing the grid size or grid area.'
+ });
+ return false;
+ } else {
+ return true;
+ }
+ },
+
+ grg.getFeatureServiceParams = function (featureServiceName, map) {
+ return {
+ "name" : featureServiceName,
+ "serviceDescription" : "",
+ "hasStaticData" : false,
+ "maxRecordCount" : 1000,
+ "supportedQueryFormats" : "JSON",
+ "capabilities" : "Create,Delete,Query,Update,Editing",
+ "tags" : "GRG",
+ "description" : "",
+ "copyrightText" : "",
+ "spatialReference" : {
+ "wkid" : 102100
+ },
+ "initialExtent" : {
+ "xmin": map.extent.xmin,
+ "ymin": map.extent.ymin,
+ "xmax": map.extent.xmax,
+ "ymax": map.extent.ymax,
+ "spatialReference":{
+ "wkid":102100
+ }
+ },
+ "allowGeometryUpdates" : true,
+ "units" : "esriMeters",
+ "xssPreventionInfo" : {
+ "xssPreventionEnabled" : true,
+ "xssPreventionRule" : "InputOnly",
+ "xssInputRule" : "rejectInvalid"
+ }
+ }
+ },
+
+ grg.getLayerParams = function (layerName, map, textSymbol, gridSymbol) {
+ return {
+ "layers": [
+ {
+ "adminLayerInfo": {
+ "geometryField": {
+ "name": "Shape"
+ },
+ "xssTrustedFields": ""
+ },
+ "id": 0,
+ "name": layerName,
+ "type": "Feature Layer",
+ "displayField": "",
+ "description": "A GRG (Gridded Reference Graphic) is a grid overlay used for a common reference point in many situations - from cordon and search operations to security for presidential inaugurations.",
+ "tags" : "GRG",
+ "copyrightText": "",
+ "defaultVisibility": true,
+ "ownershipBasedAccessControlForFeatures" : {
+ "allowOthersToQuery" : false,
+ "allowOthersToDelete" : false,
+ "allowOthersToUpdate" : false
+ },
+ "relationships": [],
+ "isDataVersioned" : false,
+ "supportsCalculate" : true,
+ "supportsAttachmentsByUploadId" : true,
+ "supportsRollbackOnFailureParameter" : true,
+ "supportsStatistics" : true,
+ "supportsAdvancedQueries" : true,
+ "supportsValidateSql" : true,
+ "supportsCoordinatesQuantization" : true,
+ "supportsApplyEditsWithGlobalIds" : true,
+ "advancedQueryCapabilities" : {
+ "supportsPagination" : true,
+ "supportsQueryWithDistance" : true,
+ "supportsReturningQueryExtent" : true,
+ "supportsStatistics" : true,
+ "supportsOrderBy" : true,
+ "supportsDistinct" : true,
+ "supportsQueryWithResultType" : true,
+ "supportsSqlExpression" : true,
+ "supportsReturningGeometryCentroid" : true
+ },
+ "useStandardizedQueries" : false,
+ "geometryType": "esriGeometryPolygon",
+ "minScale" : 0,
+ "maxScale" : 0,
+ "extent": {
+ "xmin": map.extent.xmin,
+ "ymin": map.extent.ymin,
+ "xmax": map.extent.xmax,
+ "ymax": map.extent.ymax,
+ "spatialReference":{
+ "wkid":102100
+ }
+ },
+ "drawingInfo": {
+ "renderer": {
+ "type": "simple",
+ "symbol": gridSymbol
+ },
+ "transparency": 0,
+ "labelingInfo": [
+ {
+ "labelExpression": "[grid]",
+ "labelExpressionInfo": {"value": "{grid}"},
+ "format": null,
+ "fieldInfos": null,
+ "useCodedValues": false,
+ "maxScale": 0,
+ "minScale": 0,
+ "where": null,
+ "sizeInfo": null,
+ "labelPlacement": "esriServerPolygonPlacementAlwaysHorizontal",
+ "symbol": textSymbol
+ }
+ ]
+ },
+ "allowGeometryUpdates": true,
+ "hasAttachments": false,
+ "htmlPopupType": "esriServerHTMLPopupTypeNone",
+ "hasM": false,
+ "hasZ": false,
+ "objectIdField": "OBJECTID",
+ "globalIdField": "",
+ "typeIdField": "",
+ "fields": [
+ {
+ "name": "OBJECTID",
+ "type": "esriFieldTypeOID",
+ "actualType": "int",
+ "alias": "OBJECTID",
+ "sqlType": "sqlTypeOther",
+ "nullable": false,
+ "editable": false,
+ "domain": null,
+ "defaultValue": null
+ },
+ {
+ "name": "grid",
+ "type": "esriFieldTypeString",
+ "alias": "grid",
+ "actualType": "nvarchar",
+ "nullable": true,
+ "editable": true,
+ "domain": null,
+ "defaultValue": null,
+ "sqlType": "sqlTypeNVarchar",
+ "length": 256
+ }
+ ],
+ "indexes": [],
+ "types": [],
+ "templates": [
+ {
+ "name": "New Feature",
+ "description": "",
+ "drawingTool": "esriFeatureEditToolPolygon",
+ "prototype": {
+ "attributes": {
+ "grid": ""
+ }
+ }
+ }
+ ],
+ "supportedQueryFormats": "JSON",
+ "hasStaticData": false,
+ "maxRecordCount": 10000,
+ "standardMaxRecordCount" : 4000,
+ "tileMaxRecordCount" : 4000,
+ "maxRecordCountFactor" : 1,
+ "exceedsLimitFactor" : 1,
+ "capabilities": "Query,Editing,Create,Update,Delete"
+ }
+ ]
+ }
+ },
+
+ grg.isNameAvailable = function (serviceName, token, featureServiceName) {
+ //Check for the layer name
+ var def = esriRequest({
+ url: serviceName,
+ content: {
+ name: featureServiceName,
+ type: "Feature Service",
+ token: token,
+ f: "json"
+ },
+ handleAs: "json",
+ callbackParamName: "callback"
+ },{usePost: true});
+ return def;
+ },
+
+ grg.createFeatureService = function (serviceUrl, token, createParams) {
+ //create the service
+ var def = esriRequest({
+ url: serviceUrl,
+ content: {
+ f: "json",
+ token: token,
+ typeKeywords: "ArcGIS Server,Data,Feature Access,Feature Service,Service,Hosted Service",
+ createParameters: JSON.stringify(createParams),
+ outputType: "featureService"
+ },
+ handleAs: "json",
+ callbackParamName: "callback"
+ },{usePost: true});
+ return def;
+ },
+
+ grg.addDefinitionToService = function (serviceUrl, token, defParams) {
+ var def = esriRequest({
+ url: serviceUrl,
+ content: {
+ token: token,
+ addToDefinition: JSON.stringify(defParams),
+ f: "json"
+ },
+ handleAs: "json",
+ callbackParamName: "callback"
+ },{usePost: true});
+ return def;
+ }
+
+ return grg;
+});
+
diff --git a/GRG/js/geometry-utils.js b/GRG/js/geometry-utils.js
new file mode 100644
index 0000000..ac1f5d6
--- /dev/null
+++ b/GRG/js/geometry-utils.js
@@ -0,0 +1,192 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+/**
+ * @fileOverview Module containing geometry utilities used by GRG widget.
+ * @author Esri
+ */
+
+/**
+ * @module geometry-utils
+ * @description Module containing geometry utilities used by GRG widget.
+ */
+
+define([
+ "./constants",
+ "esri/geometry/webMercatorUtils",
+ "esri/geometry/Polyline",
+ "esri/geometry/Polygon"
+], function(
+ constants,
+ webMercatorUtils,
+ Polyline,
+ Polygon
+) {
+
+ return {
+
+ /**
+ * Converts any geometry from WebMercator to Geographic, or does nothing if it already is
+ * NOTE: Does not modify the input geometry object
+ * @param {external:Geometry} geometry An esri geometry object
+ * @return {external:Geometry} A geometry oject that is Geographic
+ */
+ toGeographic: function(geometry) {
+ if (geometry.spatialReference.isWebMercator()) {
+ return webMercatorUtils.webMercatorToGeographic(geometry);
+ }
+ return geometry;
+ },
+
+ /**
+ * Converts any geometry to WebMercator from Geographic, or does nothing if it already is
+ * NOTE: Does not modify the input geometry object
+ * @param {external:Geometry} geometry An esri geometry object
+ * @return {external:Geometry} A geometry oject that is WebMercator
+ */
+ toWebMercator: function(geometry) {
+ if (!geometry.spatialReference.isWebMercator()) {
+ return webMercatorUtils.geographicToWebMercator(geometry);
+ }
+ return geometry;
+ },
+
+ /**
+ * Converts a geographic latitude to Web Mercator (assumes WGS84)
+ * NOTE: This local method is favored over external API methods for better performances
+ * @param {Number} latitude A WGS84 geographic latitude
+ * @return {Number} A WGS84 Web Mercator y
+ * @private
+ */
+ _latitudeToWebMercatorY: function(latitude) {
+ var y = latitude;
+ var deg180 = constants.GEOGRAPHIC_360 / 2;
+ var eRadius = constants.WGS84_EQUATORIAL_RADIUS;
+ return (constants.HALF_PI -
+ (2.0 * Math.atan(Math.exp((-1.0 * y) / eRadius)))) * deg180 / Math.PI;
+ },
+
+ /**
+ * Converts a geographic longitude to Web Mercator (assumes WGS84)
+ * NOTE: This local method is favored over external API methods for better performance
+ * @param {number} longitude A WGS84 geographic longitude
+ * @return {Number} A WGS84 Web Mercator x
+ * @private
+ */
+ _longitudeToWebMercatorX: function(longitude) {
+ var x = longitude;
+ var deg360 = constants.GEOGRAPHIC_360;
+ var deg180 = constants.GEOGRAPHIC_360 / 2;
+ var eRadius = constants.WGS84_EQUATORIAL_RADIUS;
+ return x / eRadius * deg180 / Math.PI -
+ (Math.floor((x / eRadius * deg180 / Math.PI + deg180) / deg360) * deg360);
+ },
+
+ /**
+ * A point-like geometry object, with x an y properties,
+ * and containing the non-normalized x-offset of the point
+ * @typedef module:geometry-utils~GeogprahicPoint
+ * @property {Number} x The longitude
+ * @property {Number} y The latitude
+ * @property {Number} offsetX The x offset
+ */
+
+ /**
+ * Converts a geometry Point from WebMercator to Geographic and
+ * denotes the x offset from the range: 180°W => 180°E
+ * NOTE: Does not modify the input point object
+ * @param {external:Point} point A geometry Point object
+ * @return {module:geometry-utils~GeogprahicPoint} A geographic point object
+ */
+ pointToGeographic: function(point) {
+ var x = point.x;
+ var y = point.y;
+ var isWebMercator = point.spatialReference.isWebMercator();
+
+ // Set the limits based on whether or not the point is WebMercator or Geographic
+ // This is used to calculate the x_offset value
+ var westernLimit = isWebMercator ?
+ constants.WEST_WEBMERCATOR_LIMIT :
+ constants.WEST_GEOGRAPHIC_LIMIT;
+ var easternLimit = isWebMercator ?
+ constants.EAST_WEBMERCATOR_LIMIT :
+ constants.EAST_GEOGRAPHIC_LIMIT;
+ var span360 = isWebMercator ?
+ constants.WEBMERCATOR_360 :
+ constants.GEOGRAPHIC_360;
+
+ // retain how far left/right of int'l dateline the original point is
+ var x_offset = 0;
+
+ // fix for x west of int'l dateline
+ while (x <= westernLimit) {
+ x += span360;
+ x_offset -= 1;
+ }
+
+ // fix for x east of int'l dateline
+ while (x > easternLimit) {
+ x -= span360;
+ x_offset += 1;
+ }
+
+ if (isWebMercator) {
+ // convert web mercator point to geographic
+ x = this._longitudeToWebMercatorX(x);
+ y = this._latitudeToWebMercatorY(y);
+ }
+
+ return {
+ "x": x,
+ "y": y,
+ "offsetX": x_offset
+ };
+ },
+
+ /**
+ * Converts an Extent geometry to a Polygon geometry (it does not modify the input point object)
+ * NOTE: Unlike the ArcGIS API for JavaScript's method (Polygon.fromExtent),
+ * this does not normalize the extent before converting to polygon
+ * @param {external:Extent} extent A geometry Extent object
+ * @return {external:Polygon} A geometry Polygon object
+ */
+ extentToPolygon: function(extent) {
+ return new Polygon({
+ rings: [[
+ [extent.xmin, extent.ymin],
+ [extent.xmax, extent.ymin],
+ [extent.xmax, extent.ymax],
+ [extent.xmin, extent.ymax],
+ [extent.xmin, extent.ymin] // close the polygon
+ ]],
+ spatialReference: extent.spatialReference
+ });
+ },
+
+ /**
+ * Converts an Polygon geometry to a Polyline geometry
+ * NOTE: Does not modify the input polygon object
+ * @param {external:Polygon} polygon A geometry Polygon object
+ * @return {external:Polyline} A geometry Polyline object
+ */
+ polygonToPolyline: function(polygon) {
+ return new Polyline({
+ "paths": polygon.rings,
+ "spatialReference":{"wkid": polygon.spatialReference.wkid}
+ });
+ }
+
+ };
+});
\ No newline at end of file
diff --git a/GRG/js/geometryUtils.js b/GRG/js/geometryUtils.js
new file mode 100644
index 0000000..eae341c
--- /dev/null
+++ b/GRG/js/geometryUtils.js
@@ -0,0 +1,593 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'esri/geometry/Point',
+ 'esri/geometry/Polyline',
+ 'esri/geometry/Polygon',
+ 'esri/geometry/webMercatorUtils',
+ 'dojo/Deferred',
+ 'dojo/_base/array',
+ 'dojo/_base/lang',
+ 'esri/geometry/geometryEngine',
+ 'esri/SpatialReference',
+ 'esri/geometry/scaleUtils'
+],
+ function (
+ Point,
+ Polyline,
+ Polygon,
+ webMercatorUtils,
+ Deferred,
+ array,
+ lang,
+ geometryEngine,
+ SpatialReference,
+ scaleUtils) {
+ var mo = {};
+
+ /**
+ * Returns the projected geometry in outSR
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getProjectedGeometry = function (geometry, outSR, geometryService) {
+ var deferred, result;
+ deferred = new Deferred();
+ if (webMercatorUtils.canProject(geometry, outSR)) {
+ result = webMercatorUtils.project(geometry, outSR);
+ deferred.resolve(result);
+ } else {
+ geometryService.project([geometry], outSR, function (projectedGeometries) {
+ result = projectedGeometries[0];
+ deferred.resolve(result);
+ });
+ }
+ return deferred.promise;
+ };
+
+ /*---------------------------------------------------------------------------------------------
+ * Vincenty Direct and Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2016
+ * MIT Licence
+ *
+ * www.movable-type.co.uk/scripts/latlong-vincenty.html
+ * www.movable-type.co.uk/scripts/geodesy/docs/module-latlon-vincenty.html
+ *---------------------------------------------------------------------------------------------
+ * Returns the destination mapPoint using Vincenty direct solution.
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getDestinationPoint = function (startPoint, initialBearing, distance) {
+ var a = 6378137;
+ var b = 6356752.314245;
+ var f = (a - b) / a;
+
+ var φ1 = startPoint.y * Math.PI / 180, λ1 = startPoint.x * Math.PI / 180;
+ var α1 = initialBearing * Math.PI / 180;
+ var s = distance;
+
+ var sinα1 = Math.sin(α1);
+ var cosα1 = Math.cos(α1);
+
+ var tanU1 = (1 - f) * Math.tan(φ1),
+ cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;
+ var σ1 = Math.atan2(tanU1, cosα1);
+ var sinα = cosU1 * sinα1;
+ var cosSqα = 1 - sinα * sinα;
+ var uSq = cosSqα * (a * a - b * b) / (b * b);
+ var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
+ var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
+
+ var cos2σM, sinσ, cosσ, Δσ;
+
+ var σ = s / (b * A), σʹ, iterations = 0;
+ do {
+ cos2σM = Math.cos(2 * σ1 + σ);
+ sinσ = Math.sin(σ);
+ cosσ = Math.cos(σ);
+ Δσ = B * sinσ * (cos2σM + B / 4 * (cosσ * (-1 + 2 * cos2σM * cos2σM) -
+ B / 6 * cos2σM * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σM * cos2σM)));
+ σʹ = σ;
+ σ = s / (b * A) + Δσ;
+ } while (Math.abs(σ - σʹ) > 1e-12 && ++iterations < 200);
+ if (iterations >= 200) {
+ console.log('Formula failed to converge'); // not possible?
+ return null;
+ }
+
+ var x = sinU1 * sinσ - cosU1 * cosσ * cosα1;
+ var φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1,
+ (1 - f) * Math.sqrt(sinα * sinα + x * x));
+ var λ = Math.atan2(sinσ * sinα1, cosU1 * cosσ - sinU1 * sinσ * cosα1);
+ var C = f / 16 * cosSqα * (4 + f * (4 - 3 * cosSqα));
+ var L = λ - (1 - C) * f * sinα *
+ (σ + C * sinσ * (cos2σM + C * cosσ * (-1 + 2 * cos2σM * cos2σM)));
+ var λ2 = (λ1 + L + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalize to -180..+180
+
+ var α2 = Math.atan2(sinα, -x);
+ α2 = (α2 + 2 * Math.PI) % (2 * Math.PI); // normalize to 0..360
+
+ φ2 = φ2 * 180 / Math.PI;
+ λ2 = λ2 * 180 / Math.PI;
+ α2 = α2 * 180 / Math.PI;
+ return new Point(λ2, φ2, new SpatialReference(4326));
+ };
+
+ /*---------------------------------------------------------------------------------------------
+ * Vincenty Direct and Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2016
+ * MIT Licence
+ *
+ * www.movable-type.co.uk/scripts/latlong-vincenty.html
+ * www.movable-type.co.uk/scripts/geodesy/docs/module-latlon-vincenty.html
+ *---------------------------------------------------------------------------------------------
+ * Returns the Info (Distance, initialBearing, finalBearing) using Vincenty inverse solution.
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getInverseCalculations = function (startPoint, endPoint) {
+ var φ1 = startPoint.y * Math.PI / 180, λ1 = startPoint.x * Math.PI / 180;
+ var φ2 = endPoint.y * Math.PI / 180, λ2 = endPoint.x * Math.PI / 180;
+
+ var a = 6378137; var b = 6356752.314245; var f = (a - b) / a;
+
+ var L = λ2 - λ1;
+ var tanU1 = (1 - f) * Math.tan(φ1),
+ cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;
+ var tanU2 = (1 - f) * Math.tan(φ2),
+ cosU2 = 1 / Math.sqrt((1 + tanU2 * tanU2)), sinU2 = tanU2 * cosU2;
+
+ var sinλ, cosλ, sinSqσ, sinσ, cosσ, σ, sinα, cosSqα, cos2σM, C;
+
+ var λ = L, λʹ, iterations = 0;
+ do {
+ sinλ = Math.sin(λ);
+ cosλ = Math.cos(λ);
+ sinSqσ = (cosU2 * sinλ) * (cosU2 * sinλ) +
+ (cosU1 * sinU2 - sinU1 * cosU2 * cosλ) * (cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
+ sinσ = Math.sqrt(sinSqσ);
+ if (sinσ == 0) { // jshint ignore:line
+ return 0; // co-incident points
+ }
+ cosσ = sinU1 * sinU2 + cosU1 * cosU2 * cosλ;
+ σ = Math.atan2(sinσ, cosσ);
+ sinα = cosU1 * cosU2 * sinλ / sinσ;
+ cosSqα = 1 - sinα * sinα;
+ cos2σM = cosσ - 2 * sinU1 * sinU2 / cosSqα;
+ if (isNaN(cos2σM)) {
+ cos2σM = 0; // equatorial line: cosSqα=0 (§6)
+ }
+ C = f / 16 * cosSqα * (4 + f * (4 - 3 * cosSqα));
+ λʹ = λ;
+ λ = L + (1 - C) * f * sinα *
+ (σ + C * sinσ * (cos2σM + C * cosσ * (-1 + 2 * cos2σM * cos2σM)));
+ } while (Math.abs(λ - λʹ) > 1e-12 && ++iterations < 200);
+ if (iterations >= 200) {
+ return null;
+ }
+
+ var uSq = cosSqα * (a * a - b * b) / (b * b);
+ var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
+ var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
+ var Δσ = B * sinσ * (cos2σM + B / 4 * (cosσ * (-1 + 2 * cos2σM * cos2σM) -
+ B / 6 * cos2σM * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σM * cos2σM)));
+
+ var s = b * A * (σ - Δσ);
+
+ var α1 = Math.atan2(cosU2 * sinλ, cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
+ var α2 = Math.atan2(cosU1 * sinλ, -sinU1 * cosU2 + cosU1 * sinU2 * cosλ);
+
+ α1 = (α1 + 2 * Math.PI) % (2 * Math.PI); // normalize to 0..360
+ α2 = (α2 + 2 * Math.PI) % (2 * Math.PI); // normalize to 0..360
+
+ s = Number(s.toFixed(3)); // round to 1mm precision
+ α1 = α1 * 180 / Math.PI;
+ α2 = α2 * 180 / Math.PI;
+ return { distance: s, initialBearing: α1, finalBearing: α2 };
+ };
+
+ /**
+ * Returns the polyline geometry between point
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getLineBetweenPoints = function (pointsArray) {
+ var polyline, pathsArray = [];
+ //iterate through all the points and create paths array
+ array.forEach(pointsArray, lang.hitch(this, function (point) {
+ pathsArray.push([point.x, point.y]);
+ }));
+ //check if paths exist and create polyline object from it
+ if (pathsArray.length > 0) {
+ polyline = new Polyline({
+ "paths": [
+ pathsArray
+ ], "spatialReference": {
+ "wkid": 4326
+ }
+ });
+ }
+ return polyline;
+ };
+
+ /**
+ * Returns angle between to points
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getAngleBetweenPoints = function (originPoint, chordPoint) {
+ var angle;
+ var inverseInfo = mo.getInverseCalculations(originPoint, chordPoint);
+ if (inverseInfo === null) {
+ angle = 0;
+ } else {
+ angle = inverseInfo.initialBearing;
+ }
+ return angle;
+ };
+
+ /**
+ * Returns distance between two point in meters using geometry engine
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getDistanceBetweenPoints = function (startPoint, endPoint) {
+ var distance;
+ var inverseInfo = mo.getInverseCalculations(startPoint, endPoint);
+ if (inverseInfo === null) {
+ distance = 0;
+ } else {
+ distance = inverseInfo.distance;
+ }
+ return distance;
+ };
+
+ /**
+ * Returns the geodesic length of simplified geometry using geometry engine
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getLengthOfGeometry = function (geometry) {
+ var lengthInMeters, simplifiedGeometry;
+ simplifiedGeometry = geometryEngine.simplify(geometry);
+ if (simplifiedGeometry) {
+ lengthInMeters = geometryEngine.geodesicLength(simplifiedGeometry, 9001);
+ } else {
+ lengthInMeters = 0;
+ }
+ return lengthInMeters;
+ };
+
+ /**
+ * Returns the object containing area of the geometry, in acre, sqMeters,sqFeet, and sqUSFeet.
+ * if geometry is not simplified it will return 0 in all units
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getAreaOfGeometry = function (geometry) {
+ var simplifiedGeometry, areaConversions;
+ simplifiedGeometry = geometryEngine.simplify(geometry);
+ areaConversions = {};
+ if (simplifiedGeometry) {
+ areaConversions.acres = geometryEngine.geodesicArea(simplifiedGeometry, 109402);
+ areaConversions.squareMeters = geometryEngine.geodesicArea(simplifiedGeometry, 109404);
+ areaConversions.squareFeet = geometryEngine.geodesicArea(simplifiedGeometry, 109405);
+ areaConversions.squareUsFeet = geometryEngine.geodesicArea(simplifiedGeometry, 109406);
+ } else {
+ areaConversions.acres = 0;
+ areaConversions.squareMeters = 0;
+ areaConversions.squareFeet = 0;
+ areaConversions.squareUsFeet = 0;
+ }
+ return areaConversions;
+ };
+
+ /**
+ * Returns the polyline object form the paths array
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getPolyLineFromPaths = function (pathsArray) {
+ var polyline, i;
+ //create polyline in 102100 spatial reference
+ polyline = new Polyline(new SpatialReference({ wkid: 4326 }));
+ for (i = 0; i < pathsArray.length; i++) {
+ polyline.addPath(pathsArray[i]);
+ }
+ return polyline;
+ };
+
+ /**
+ * Returns the polygon object form the paths array
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getPolygonFromPolyLines = function (pathsArray, addLastPoint, updateLastPoint,
+ spatialReference) {
+ var ring, polygon, i, j;
+ ring = [];
+ //create polygon in 102100 spatial reference if spatial reference is not valid
+ if (!spatialReference) {
+ polygon = new Polygon(new SpatialReference({ wkid: 4326 }));
+ } else {
+ polygon = new Polygon(new SpatialReference(spatialReference));
+ }
+ for (i = 0; i < pathsArray.length; i++) {
+ for (j = 0; j < pathsArray[i].length; j++) {
+ ring.push(pathsArray[i][j]);
+ }
+ }
+ if (addLastPoint) {
+ ring.push(lang.clone(ring[0]));
+ } else if (updateLastPoint) {
+ ring[ring.length - 1][0] = ring[0][0];
+ ring[ring.length - 1][1] = ring[0][1];
+ }
+ //if ring is not in clockwise direction reverse the ring
+ if (!polygon.isClockwise(ring)) {
+ ring.reverse();
+ }
+ polygon.addRing(ring);
+ return polygon;
+ };
+
+ /**
+ * Returns the pointArray for an arc
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getPointsForArc = function (startAngle, endAngle, centerPoint, radius) {
+ var i, pointArray = [], angleOfArc, segments, unitAngle, bearingForEachPoint, point;
+ angleOfArc = endAngle - startAngle;
+ segments = parseInt(angleOfArc, 10);
+ //in case if angle is in between 0 to 1, segments parseInt value will be 0,
+ //but we would require at least 1 segment to draw arc
+ if (segments <= 0) {
+ segments = 1;
+ }
+ unitAngle = Math.abs(angleOfArc) / Math.abs(segments);
+ //unit angle is zero then we cannot calculate points of arc
+ if (unitAngle > 0) {
+ for (i = 0; i < Math.abs(segments) + 1; i++) {
+ bearingForEachPoint = startAngle + (unitAngle * i);
+ point = mo.getDestinationPoint(centerPoint, bearingForEachPoint, Math.abs(radius));
+ if (point) {
+ pointArray.push(point);
+ }
+ }
+ }
+ return pointArray;
+ };
+
+ /**
+ * Returns the arc params required to draw arc
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getArcParam = function (param) {
+ var returnValue;
+ returnValue = {};
+ if (param.distance < 0) { //major arc
+ if (param.radius < 0) { // left side of chord
+ returnValue.bearing = param.initBearing + 90;
+ returnValue.centerPoint = mo.getDestinationPoint(param.chordMidPoint, returnValue.bearing,
+ param.centerAndChordDistance);
+ returnValue.startAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordEndPoint);
+ returnValue.endAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordStartPoint);
+ } else { // Right side of chord
+ returnValue.bearing = param.initBearing - 90;
+ returnValue.centerPoint = mo.getDestinationPoint(param.chordMidPoint, returnValue.bearing,
+ param.centerAndChordDistance);
+ returnValue.startAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordStartPoint);
+ returnValue.endAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordEndPoint);
+ }
+ } else { //minor arc
+ if (param.radius > 0) { // right side of chord
+ returnValue.bearing = param.initBearing + 90;
+ returnValue.centerPoint = mo.getDestinationPoint(param.chordMidPoint, returnValue.bearing,
+ param.centerAndChordDistance);
+ returnValue.startAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordStartPoint);
+ returnValue.endAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordEndPoint);
+ } else { // left side of chord
+ returnValue.bearing = param.initBearing - 90;
+ returnValue.centerPoint = mo.getDestinationPoint(param.chordMidPoint,
+ returnValue.bearing, param.centerAndChordDistance);
+ returnValue.startAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordEndPoint);
+ returnValue.endAngle = mo.getAngleBetweenPoints(returnValue.centerPoint,
+ param.chordStartPoint);
+ }
+ }
+ return returnValue;
+ };
+
+ /**
+ * Returns the value after removing negative exponents from it
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.removeNegativeExponents = function (num) {
+ var returnValue;
+ if (num.toString().toLowerCase().split('e-').length > 1) {
+ returnValue = 0;
+ } else {
+ returnValue = num;
+ }
+ return returnValue;
+ };
+
+ /**
+ * Converts the chord length to arc length
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getChordLengthFromArcLength = function (arcLength, radius) {
+ var chordLength, arcLengthOfSemiCircle, theta;
+ arcLength = Math.abs(arcLength);
+ // using formula 'Math.PI * radius' for calculating circumference of a semi-circle.
+ arcLengthOfSemiCircle = Math.PI * Math.abs(radius);
+ // calculating angle for half of the triangle
+ theta = Math.abs(arcLength) / Math.abs(radius);
+ // calculate chordLength(perpendicular in our case) using formula
+ //sin(theta) = perpendicular / hypotenuse,
+ //so, perpendicular = hypotenuse * sin(theta)
+ chordLength = Math.abs(radius) * Math.sin(theta / 2);
+ if (arcLength <= arcLengthOfSemiCircle) {
+ chordLength = chordLength * 2;
+ } else {
+ chordLength = chordLength * (-2);
+ }
+ return chordLength;
+ };
+
+ /**
+ * Converts the arc length to chord length
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getArcLengthFromChordLength = function (chordLength, radius) {
+ var arcLength, absChordLength;
+ absChordLength = Math.abs(chordLength);
+ radius = Math.abs(radius);
+ arcLength = (2 * Math.asin(absChordLength / (2 * radius)) * radius);
+ if (chordLength < 0) {
+ arcLength = (2 * Math.PI * radius) - arcLength;
+ }
+ return arcLength;
+ };
+
+ /**
+ * Converts the chord bearing to tangent bearing
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.chordBearingToTangentBearing = function (chordBearing, radius, chordLength) {
+ var radToChordAngle, minorArc, leftOfChord, tanBearing;
+ radToChordAngle = Math.acos((Math.abs(chordLength) / 2) / Math.abs(radius)) * (180 / Math.PI);
+ //angle between radius and chord
+ minorArc = radius / Math.abs(radius);
+ leftOfChord = chordLength / Math.abs(chordLength);
+ /*
+ Combinations:
+ 1. +r +c -> tb = cb + 90 - a
+ 2. +r -c -> tb = cb + 90 + a
+ 3. -r +c -> tb = cb - 90 + a
+ 4. -r -c -> tb = cb - 90 - a
+ */
+ tanBearing = chordBearing + minorArc * 90 - minorArc * leftOfChord * radToChordAngle;
+ //ensure that angle is between 0 to 360
+ tanBearing =
+ tanBearing < 0 ? tanBearing + 360 :
+ (tanBearing >= 360 ? tanBearing % 360 : tanBearing);
+ //return the tanBearing removing negative exponent
+ return mo.removeNegativeExponents(tanBearing);
+ };
+
+ /**
+ * Converts the tangent bearing to chord bearing
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.tangentBearingToChordBearing = function (tanBearing, radius, chordLength) {
+ var radToChordAngle, minorArc, leftOfChord, chordBearing;
+ radToChordAngle = Math.acos((Math.abs(chordLength) / 2) / Math.abs(radius)) * (180 / Math.PI);
+ //angle between radius and chord
+ minorArc = radius / Math.abs(radius);
+ leftOfChord = chordLength / Math.abs(chordLength);
+ /*
+ Combinations:
+ 1. +r +c -> cb = tb + 90 - a
+ 2. +r -c -> cb = tb + 90 + a
+ 3. -r +c -> cb = tb - 90 + a
+ 4. -r -c -> cb = tb - 90 - a
+ */
+ chordBearing = tanBearing + minorArc * 90 - minorArc * leftOfChord * radToChordAngle;
+ //ensure that angle is between 0 to 360
+ chordBearing =
+ chordBearing < 0 ? chordBearing + 360 :
+ (chordBearing >= 360 ? chordBearing % 360 : chordBearing);
+ //return the chordBearing removing negative exponent
+ return mo.removeNegativeExponents(chordBearing);
+ };
+
+ /**
+ * This function is used to get unit from spatialReference
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getUnitValueForSR = function (spatialReference) {
+ var mapUnit;
+ mapUnit = scaleUtils.getUnitValueForSR(spatialReference);
+ switch (mapUnit) {
+ case 1: // meters
+ return "meters";
+ case 111194.87428468118: // degrees
+ return "meters";
+ case 0.3048: // feet
+ return "feet";
+ case 0.3048006096: // us survey feet
+ case 0.3048006096012192:
+ return "uSSurveyFeet";
+ }
+ };
+
+ /**
+ * Returns the angle between two points
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getRotationAngleBetweenPoints = function (originPoint, chordPoint) {
+ var dx, dy, XByY, YByX;
+ originPoint = webMercatorUtils.project(originPoint, new SpatialReference(102100));
+ chordPoint = webMercatorUtils.project(chordPoint, new SpatialReference(102100));
+ dx = chordPoint.x - originPoint.x;
+ dy = chordPoint.y - originPoint.y;
+ XByY = Math.atan2(Math.abs(dx), Math.abs(dy)) * 180 / Math.PI;
+ YByX = Math.atan2(Math.abs(dy), Math.abs(dx)) * 180 / Math.PI;
+ //remove negative exponents from the calculated value
+ dx = mo.removeNegativeExponents(dx);
+ dy = mo.removeNegativeExponents(dy);
+ XByY = mo.removeNegativeExponents(XByY);
+ YByX = mo.removeNegativeExponents(YByX);
+ if (dy === 0) {
+ if (dx === 0) {
+ return 0;
+ } else if (dx > 0) {
+ return 90;
+ } else if (dx < 0) {
+ return 270;
+ }
+ } else if (dy > 0) {
+ if (dx === 0) {
+ return 0;
+ } else if (dx > 0) {
+ return XByY;
+ } else if (dx < 0) {
+ return 270 + YByX;
+ }
+ } else if (dy < 0) {
+ if (dx === 0) {
+ return 180;
+ } else if (dx > 0) {
+ return 90 + YByX;
+ } else if (dx < 0) {
+ return 180 + XByY;
+ }
+ }
+ };
+
+ /**
+ * Returns the distance between two points
+ * @memberOf widgets/GRGDrafter/geometryUtils
+ **/
+ mo.getScaleDistanceBetweenPoints = function (startPoint, endPoint) {
+ startPoint = webMercatorUtils.project(startPoint, new SpatialReference(102100));
+ endPoint = webMercatorUtils.project(endPoint, new SpatialReference(102100));
+ var distance = geometryEngine.distance(startPoint, endPoint, 9001);
+ //as their could be very small distance between points,
+ //geometryEngine will return values in negative exponent which means
+ // it is equivalent to zero so removeNegativeExponents from values
+ return mo.removeNegativeExponents(distance);
+ };
+
+ return mo;
+ });
\ No newline at end of file
diff --git a/GRG/js/mgrs-utils.js b/GRG/js/mgrs-utils.js
new file mode 100644
index 0000000..bb1d5f1
--- /dev/null
+++ b/GRG/js/mgrs-utils.js
@@ -0,0 +1,643 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the 'License');
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+/**
+ * @fileOverview Module containing MGRS grid utilities used by GRG widget.
+ * @author Esri
+ */
+
+/**
+ * @module mgrs-utils
+ * @description Module containing MGRS grid utilities used by GRG widget.
+ */
+
+define([
+ "dojo/json",
+ "./constants",
+ "./geometry-utils",
+ "./geometryUtils",
+ "./mgrs",
+ "./NonPolarGridZone",
+ "./VisibleGridZone",
+ "./GridPolygon",
+ "esri/geometry/geometryEngine",
+ "esri/geometry/Point",
+ "esri/geometry/Polygon"
+], function(
+ JSON,
+ constants,
+ gridGeomUtils,
+ geomUtils,
+ mgrs,
+ NonPolarGridZone,
+ VisibleGridZone,
+ GridPolygon,
+ geometryEngine,
+ Point,
+ Polygon
+) {
+ // If Math.log10 is not supported by default in the browser, add it here
+ if (!Math.log10) {
+ Math.log10 = function log10(val) {
+ return Math.log(val) / Math.LN10;
+ };
+ }
+ return {
+ /**
+ * The zonesDictionary object contains all 1197 unique keys
+ * (one for each non-polar MGRS grid zone)
+ * @type {Object.}
+ * @private
+ * @example
+ * // returns 12
+ * _ZonesDictionary["12S"].utmZone;
+ */
+ _ZonesDictionary: (function() {
+ // The zonesDictionary object has 1197 unique keys (one for eqch MGRS grid zone).
+ // Rather than load it through a single, large json text file,
+ // we build it here programmatically,
+ // one time, on the client
+
+ var zoneNum, zoneLtr, nonPolarGridZone;
+ // Per MGRS definition, these are the valid grid zone letters
+ var zoneLetters = [
+ 'C','D','E','F','G','H','J','K','L','M','N',
+ 'P','Q','R','S','T','U','V','W','X'
+ ];
+ // A dictionary object containing all MGRS zones (excluding any zones that don't exist)
+ // this is the object that will be returned (i.e. set as the _ZonesDictionary)
+ var zonesDictionary = {};
+
+ /**
+ * Returns the NonPolarGridZone object for the zone.
+ * NOTE: This is only used during the initial creation of '_ZonesDictionary' object
+ * @param {Number} zoneNum The MGRS grid zone number
+ * @param {Number} zoneLtrIndex
+ * The index of the MGRS grid zone letter (w.r.t. the zoneLetters object)
+ * @return {module:mgrs-utils~NonPolarGridZone} The NonPolarGridZone object
+ * @private
+ */
+ var ltrZoneToExtent = function(zoneNum, zoneLtrIndex) {
+ var nonPolarGridZoneArgs, xmin, xmax, ymin, ymax;
+ var zoneLtr = zoneLetters[zoneLtrIndex];
+ var zoneId = zoneNum + zoneLtr;
+
+ // There are several unique MGRS zones which don't follow the standard convention,
+ // they are defined here:
+ if (zoneId === "32X" || zoneId === "34X" || zoneId === "36X") {
+ // Per the MGRS definition, these zones don't exist
+ return null;
+ } else if (zoneId === "31V") {
+ // unique sized zone
+ nonPolarGridZoneArgs = {
+ "xmin": 0,
+ "ymin": 56,
+ "xmax": 3,
+ "ymax": 64,
+ "id": zoneId
+ };
+ } else if (zoneId === "32V") {
+ // unique sized zone
+ nonPolarGridZoneArgs = {
+ "xmin": 3,
+ "ymin": 56,
+ "xmax": 12,
+ "ymax": 64,
+ "id": zoneId
+ };
+ } else if (zoneId === "31X") {
+ // unique sized zone
+ nonPolarGridZoneArgs = {
+ "xmin": 0,
+ "ymin": 72,
+ "xmax": 9,
+ "ymax": 84,
+ "id": zoneId
+ };
+ } else if (zoneId === "33X") {
+ // unique sized zone
+ nonPolarGridZoneArgs = {
+ "xmin": 9,
+ "ymin": 72,
+ "xmax": 21,
+ "ymax": 84,
+ "id": zoneId
+ };
+ } else if (zoneId === "35X") {
+ // unique sized zone
+ nonPolarGridZoneArgs = {
+ "xmin": 21,
+ "ymin": 72,
+ "xmax": 33,
+ "ymax": 84,
+ "id": zoneId
+ };
+ } else if (zoneId === "37X") {
+ // unique sized zone
+ nonPolarGridZoneArgs = {
+ "xmin": 33,
+ "ymin": 72,
+ "xmax": 42,
+ "ymax": 84,
+ "id": zoneId
+ };
+ } else {
+ // These are the default zones that do follow the standard MGRS convention:
+
+ // Compute the extent attributes of the zone
+ xmin = (zoneNum - 1) * constants.ZONE_WIDTH_DEGREES - 180;
+ xmax = zoneNum * constants.ZONE_WIDTH_DEGREES - 180;
+ ymin = zoneLtrIndex * constants.ZONE_HEIGHT_DEGREES + constants.MIN_MGRS_LATITUDE;
+ ymax = (zoneLtrIndex + 1) * constants.ZONE_HEIGHT_DEGREES + constants.MIN_MGRS_LATITUDE;
+
+ // Fix special cases where the numbers need to be adjusted
+ // exactly 180 or -180 causes problems, changes it to something close
+ xmin = xmin === 180 ? constants.POSITIVE_180 : xmin;
+ xmin = xmin === -180 ? constants.NEGATIVE_180 : xmin;
+ xmax = xmax === 180 ? constants.POSITIVE_180 : xmax;
+ xmax = xmax === -180 ? constants.NEGATIVE_180 : xmax;
+ if (ymax === 80) {
+ // the top row of MGRS grid zones is taller than most, in order to extent to N84°
+ ymax = constants.MAX_MGRS_LATITUDE;
+ }
+
+ nonPolarGridZoneArgs = {
+ "xmin": xmin,
+ "ymin": ymin,
+ "xmax": xmax,
+ "ymax": ymax,
+ "id": zoneId
+ };
+ }
+ return new NonPolarGridZone(nonPolarGridZoneArgs);
+ };
+
+ // Loop through all possible zone number/letter combinations,
+ // building the NonPolarGridZone object for each
+ for (zoneNum = 1; zoneNum <= 60; zoneNum++) {
+ for (zoneLtr = 0; zoneLtr < zoneLetters.length; zoneLtr++) {
+ nonPolarGridZone = ltrZoneToExtent(zoneNum, zoneLtr);
+ if (nonPolarGridZone) {
+ zonesDictionary[nonPolarGridZone.id] = nonPolarGridZone;
+ }
+ }
+ }
+
+ // Loop through all possible zone number/letter combinations,
+ // and add the full utm zone geometry
+ for (zoneNum = 1; zoneNum <= 60; zoneNum++) {
+ var geometriesToUnion = [];
+ //this first loop creates an array of geometries for a single UTM zone
+ for (zoneLtr = 0; zoneLtr < zoneLetters.length; zoneLtr++) {
+ nonPolarGridZone = ltrZoneToExtent(zoneNum, zoneLtr);
+ if (nonPolarGridZone) {
+ var polygon = new Polygon({
+ rings: JSON.parse(JSON.stringify(nonPolarGridZone._rings))
+ });
+ geometriesToUnion.push(polygon);
+ }
+ }
+ //union the geometries to create a single polygon
+ var union = geometryEngine.union(geometriesToUnion);
+ // loop back through each letter combination add the single zone geometry
+ for (zoneLtr = 0; zoneLtr < zoneLetters.length; zoneLtr++) {
+ nonPolarGridZone = ltrZoneToExtent(zoneNum, zoneLtr);
+ if (nonPolarGridZone) {
+ zonesDictionary[nonPolarGridZone.id]['fullZoneGeometry'] = union;
+ }
+ }
+ }
+ return zonesDictionary;
+ })(),
+
+ /**
+ * Finds the intersecting MGRS grid zones from the input extent
+ * @param {Object} grid The grid overlay object
+ * @return {module:mgrs-utils~VisibleGridZone[]} An array of non-polar grid zones
+ */
+ zonesFromExtent: function(extent,map) {
+ var xmin, ymin, xmax, ymax, minLtr, maxLtr, minNum, maxNum,
+ ltr, idx, rings, polygon, polygon_i, polyline, polyline_i,
+ minXOffset, maxXOffset;
+ var mapExtent = extent;
+ var deg360 = mapExtent.spatialReference.isWebMercator() ?
+ constants.WEBMERCATOR_360 :
+ constants.GEOGRAPHIC_360;
+
+ // per MGRS definition, these are the valid grid zone letters
+ var zoneLetters = [
+ 'C','D','E','F','G','H','J','K','L','M',
+ 'N','P','Q','R','S','T','U','V','W','X'
+ ];
+ // this will be the returned array (of VisibleGridZone objects)
+ var visibleGridZones = [];
+
+ // check to see if the map extent spans the entire globe
+ // (longitudinally) and hide the grid if it does
+ if ((mapExtent.xmax - mapExtent.xmin) > deg360) {
+ return visibleGridZones;
+ }
+
+ // polygon geometry of map extent, used for intersect later on
+ var mapExtentPolygon = gridGeomUtils.extentToPolygon(mapExtent);
+ mapExtentPolygon = gridGeomUtils.toWebMercator(mapExtentPolygon);
+
+ // used to find min/max values of x and y, as well as to determine wraparound offset
+ var southwestPoint = gridGeomUtils.pointToGeographic(
+ new Point([mapExtent.xmin, mapExtent.ymin],mapExtent.spatialReference)
+ );
+ var northeastPoint = gridGeomUtils.pointToGeographic(
+ new Point([mapExtent.xmax, mapExtent.ymax], mapExtent.spatialReference)
+ );
+
+ // ymin and ymax are geographic latitudes
+ ymin = southwestPoint.y;
+ ymax = northeastPoint.y;
+
+ // when map is in wraparound mode, determine if map extent spans left of 180°W
+ minXOffset = southwestPoint.offsetX;
+
+ // when map is in wraparound mode, determine if map extent spans east of 180°E
+ maxXOffset = northeastPoint.offsetX;
+
+ // when the map is in wraparound mode, handle each span separately
+ // (divided by Int'l Date Line)
+ for (var x_offset = minXOffset; x_offset <= maxXOffset; x_offset++) {
+
+ // xmin and xmax are gegraphic longitudes
+ if (x_offset > minXOffset) {
+ xmin = constants.NEGATIVE_180;
+ } else {
+ xmin = southwestPoint.x;
+ }
+ if (x_offset < maxXOffset) {
+ xmax = constants.POSITIVE_180;
+ } else {
+ xmax = northeastPoint.x;
+ }
+
+ // find the min and max MGRS grid zone letters by dividing the
+ // vertical extent by zone height (normally 8°),
+ // only considering the valid range of -80° => +84°
+ minLtr = Math.min(Math.max(Math.floor((ymin + 80) / constants.ZONE_HEIGHT_DEGREES), 0), 19);
+ maxLtr = Math.min(Math.floor((ymax + 80) / constants.ZONE_HEIGHT_DEGREES), 19);
+ minNum = Math.floor((xmin + 180) / constants.ZONE_WIDTH_DEGREES);
+ maxNum = Math.min(Math.floor((xmax + 180) / constants.ZONE_WIDTH_DEGREES) + 2, 60);
+
+ // loop through each zone number
+ for (var num = minNum; num <= maxNum; num++) {
+
+ // loop through each zone letter
+ for (var l = minLtr; l <= maxLtr; l++) {
+
+ // convert zone letter from int to character
+ ltr = zoneLetters[l];
+ idx = num + ltr; // index of zone
+
+ if (!this._ZonesDictionary[idx]) {
+ // skip and goto next zone if zone index is valid?
+ continue;
+ }
+ // create a copy of the zone paths
+ rings = JSON.parse(JSON.stringify(this._ZonesDictionary[idx]._rings));
+
+ // modify the zone paths for x_offset
+ for (var i = 0; i < rings[0].length; i++) {
+ rings[0][i][0] += x_offset * constants.GEOGRAPHIC_360;
+ }
+
+ // create polygon from new zone paths
+ polygon = new Polygon({
+ rings: rings
+ });
+
+ // check if zone polygon intersects with the original mapextent
+ polygon_i = geometryEngine.intersect(
+ gridGeomUtils.toWebMercator(polygon),
+ mapExtentPolygon);
+ if (polygon_i) {
+ // create a VisibleGridZone instance and add it to the visibleGridZones results array
+ visibleGridZones.push( new VisibleGridZone({
+ "map": map,
+ "polygon": polygon_i,
+ "fullZoneGeometry": this._ZonesDictionary[idx].fullZoneGeometry,
+ "offset": x_offset,
+ "nonPolarGridZone": this._ZonesDictionary[idx],
+ "utmZone": this._ZonesDictionary[idx].utmZone,
+ "latitudeBand": this._ZonesDictionary[idx].latitudeZone
+ }));
+ }
+ }
+ }
+ }
+ return visibleGridZones;
+ },
+
+ /**
+ * Processes an array of visible grid zone and hands them off to the appropriate handler(s)
+ * @param {module:mgrs-utils~VisibleGridZone[]} visibleGridZone A VisibleGridZone object
+ * @param {object} grid The grid overlay object that is calling this method
+ */
+ processZonePolygons: function(visibleGridZones, map, interval, extent) {
+
+ var utmZonePolygons = {};
+ var intervalSpacing = interval;
+ var polys = [];
+ extent = gridGeomUtils.toWebMercator(extent);
+
+ for (var i = 0; i < visibleGridZones.length; i++) {
+ var visibleGridZone = visibleGridZones[i];
+ if (visibleGridZone) {
+
+ var latitudeZone = visibleGridZone.nonPolarGridZone.latitudeZone;
+
+ var clippedExtent = gridGeomUtils.toGeographic(visibleGridZone.polygon.getExtent());
+
+ // compute the UTM of each extent corner, as a basis for finding the min/max values
+ var lowerLeftUtm = mgrs.LLtoUTM(clippedExtent.ymin, clippedExtent.xmin, visibleGridZone.nonPolarGridZone.utmZone);
+ var lowerRightUtm = mgrs.LLtoUTM(clippedExtent.ymin, clippedExtent.xmax, visibleGridZone.nonPolarGridZone.utmZone);
+ var upperRightUtm = mgrs.LLtoUTM(clippedExtent.ymax, clippedExtent.xmax, visibleGridZone.nonPolarGridZone.utmZone);
+ var upperLeftUtm = mgrs.LLtoUTM(clippedExtent.ymax, clippedExtent.xmin, visibleGridZone.nonPolarGridZone.utmZone);
+
+ // using the UTM coordinates, find the min/max values
+ // (index 0 of a UTM point is easting, 1 is northing)
+ var minEasting = Math.min(lowerLeftUtm[0],
+ lowerRightUtm[0], upperRightUtm[0], upperLeftUtm[0]);
+ var maxEasting = Math.max(lowerLeftUtm[0],
+ lowerRightUtm[0], upperRightUtm[0], upperLeftUtm[0]);
+ var minNorthing = Math.min(lowerLeftUtm[1],
+ lowerRightUtm[1], upperRightUtm[1], upperLeftUtm[1]); // - 10000;
+ var maxNorthing = Math.max(lowerLeftUtm[1],
+ lowerRightUtm[1], upperRightUtm[1], upperLeftUtm[1]);
+
+ var handlerArgs = {
+ "minE": minEasting,
+ "maxE": maxEasting,
+ "minN": minNorthing,
+ "maxN": maxNorthing,
+ "utmZone": visibleGridZone.nonPolarGridZone.utmZone,
+ "latitudeZone": latitudeZone,
+ "polygon": visibleGridZone.polygon,
+ "offset": visibleGridZone.offset,
+ "fullZoneGeometry": gridGeomUtils.extentToPolygon(visibleGridZone.nonPolarGridZone.extent)
+ };
+ polys = polys.concat(this.handle100kGrids(handlerArgs, map, extent));
+ }
+ }
+ return polys;
+ },
+
+ /**
+ * Creates graphics for the 100K meter grids
+ * @param {module:mgrs-utils~MgrsGridHandlerArguments} args
+ * An object holding the arguments for the various handlers
+ *
+ */
+ handle100kGrids: function(args, map, extent) {
+ var zonePolygon = args.polygon;
+ var offset = args.offset;
+ var utmZone = args.utmZone;
+ var latitudeZone = args.latitudeZone;
+ var fullZoneGeometry = args.fullZoneGeometry;
+ var minE = args.minE;
+ var maxE = args.maxE;
+ var minN = args.minN;
+ var maxN = args.maxN;
+ var poly100k = [];
+
+ var n, e, i, ring, pt, text, polygon, polyline, gridPolygonArgs, gridPolygon;
+
+ // Loop through northings, starting at the increment just south of minN
+ // go through each increment of 100K meters, until maxN is reached
+ for (n = Math.floor(minN / 100000) * 100000; n < maxN; n += 100000) {
+
+ // Loop through eastings, starting at the increment just west of minE
+ // go through each increment of 100K meters, until maxE is reached
+ for (e = Math.floor(minE / 100000) * 100000; e < maxE; e += 100000) {
+ // For each 100k increment of n & e, build a 100k by 100k grid polygon,
+ // used for labeling and border graphics
+
+ // find the label of the 100K grid
+ text = mgrs.findGridLetters(utmZone,
+ (n + 50000 < 0 ? 10000000 + (n + 50000) : n + 50000), e + 50000);
+
+ // Build the 100k grid boundary
+ ring = [];
+ // start at the bottom left corner, and work east to
+ // the bottom right corner (in 10k m increments)
+ // this is a faster way of densifying the line, since it
+ // will appear to be curved on the map
+ for (i = e; i <= e + 100000; i += 10000) {
+ pt = mgrs.UTMtoLL(n, i, utmZone);
+ ring.push([pt.lon, pt.lat]);
+ }
+ // continue adding points to the polygon, working from the
+ // bottom right to top right corner
+ for (i = n; i < n + 100000; i += 10000) {
+ pt = mgrs.UTMtoLL(i, e + 100000, utmZone);
+ ring.push([pt.lon, pt.lat]);
+ }
+ // continue adding points to the polygon, working from the top right to top left corner
+ for (i = e + 100000; i >= e;i -= 10000) {
+ pt = mgrs.UTMtoLL(n + 100000, i, utmZone);
+ ring.push([pt.lon, pt.lat]);
+ }
+ // continue adding points to the polygon, working from
+ // the top left to the bottom left corner (to close the polygon)
+ for (i = n + 100000; i >= n; i -= 10000) {
+ pt = mgrs.UTMtoLL(i, e, utmZone);
+ ring.push([pt.lon, pt.lat]);
+ }
+ // now that the polygon ring is built, shift it left/right to match the x-offset
+ // (i.e. how many increments left or right of the dateline, to support wraparound maps)
+ for (i = 0; i < ring.length; i++) {
+ ring[i][0] += offset * constants.GEOGRAPHIC_360;
+ }
+ // create the polygon, from the ring created above
+ polygon = new Polygon([ring]);
+
+ //we need to rotate the drawn extent to match the angle of the grid
+ var angle = geomUtils.getAngleBetweenPoints(polygon.getPoint(0, polygon.rings[0].length - 1),polygon.getPoint(0, polygon.rings[0].length - 2));
+ extentRotated = geometryEngine.rotate(gridGeomUtils.extentToPolygon(extent),angle * -1);
+
+ // now that the 100k grid polygon exists, clip it by the grid zone polygon
+ var clippedPolygon = geometryEngine.intersect(
+ gridGeomUtils.toWebMercator(polygon),
+ gridGeomUtils.toWebMercator(zonePolygon));
+
+ var clippedPolygonRotated = geometryEngine.intersects(
+ extentRotated,
+ gridGeomUtils.toWebMercator(polygon));
+
+ // after being clipped above, they may no longer exist
+ // (i.e. they were not within the bounds of the zone)
+ // if this is the case, skip the rest and move on to the next increment of n or e
+ if (clippedPolygon || clippedPolygonRotated) {
+
+ if(clippedPolygonRotated) {
+ var clippedPolyToUTMZone = geometryEngine.intersect(
+ gridGeomUtils.toWebMercator(polygon),
+ gridGeomUtils.toWebMercator(fullZoneGeometry));
+ }
+
+ gridPolygonArgs = {
+ "clippedPolygon": clippedPolygon,
+ "unclippedPolygon": polygon,
+ "clippedPolyToUTMZone": clippedPolyToUTMZone,
+ "map": map,
+ "xmin": e,
+ "ymin": n,
+ "xmax": (e + 100000),
+ "ymax": (n + 100000),
+ "x": '',
+ "y": '',
+ "minMaxType": "utm",
+ "utmZone": utmZone,
+ "latitudeZone": latitudeZone,
+ "utmZonePoly": zonePolygon,
+ "fullZoneGeometry" : fullZoneGeometry,
+ "GZD": text,
+ "text": text
+ };
+
+ if(!clippedPolyToUTMZone){
+ continue;
+ }
+
+ gridPolygon = new GridPolygon(gridPolygonArgs);
+ poly100k.push(gridPolygon);
+ }
+ }
+ }
+ return poly100k;
+ },
+
+ /**
+ * Creates graphics for grid interval
+ * (i.e. lines at less than 100K meter spacing)
+ * @param {module:mgrs-utils~MgrsGridHandlerArguments} poly
+ * An object holding the arguments for the various handlers
+ */
+ handleGridSquares: function(poly, map, interval, extent) {
+ // This method is similar in nature to the 'handle100kGrids' method
+ var polyOut = [];
+ var zonePolygon = poly.utmZonePoly;
+ var latitudeZone = poly.latitudeZone;
+ var utmZone = poly.utmZone;
+ var fullZoneGeometry = poly.fullZoneGeometry;
+ var GZD = poly.GZD;
+ var offset = poly.offset;
+ var minE = poly.xmin;
+ var maxE = poly.xmax;
+ var minN = poly.ymin;
+ var maxN = poly.ymax;
+ var n, e, text, polygon, gridPolygonArgs, extentRotated;
+ var firstRow = true;
+ var firstColumn = true;
+
+ extent = gridGeomUtils.toWebMercator(extent);
+
+ for (n = Math.floor(minN / interval) * interval; n < maxN; n += interval) {
+ for (e = Math.floor(minE / interval) * interval; e < maxE; e += interval) {
+ ring = [];
+ ptBL = mgrs.UTMtoLL(n, e, utmZone);
+ ring.push([ptBL.lon, ptBL.lat]);
+ ptTL = mgrs.UTMtoLL(n + interval, e, utmZone);
+ ring.push([ptTL.lon, ptTL.lat]);
+ ptTR = mgrs.UTMtoLL(n + interval, e + interval, utmZone);
+ ring.push([ptTR.lon, ptTR.lat]);
+ ptBR = mgrs.UTMtoLL(n, e + interval, utmZone);
+ ring.push([ptBR.lon, ptBR.lat]);
+ //close off poly
+ ring.push([ptBL.lon, ptBL.lat]);
+
+ polygon = new Polygon([ring]);
+
+ var clippedExtent = geometryEngine.intersect(
+ gridGeomUtils.toWebMercator(gridGeomUtils.extentToPolygon(extent)),
+ gridGeomUtils.toWebMercator(fullZoneGeometry));
+
+ if (firstRow && firstColumn) {
+ //we only need to calculate the angle for the first polygon in the group
+ var angle = geomUtils.getAngleBetweenPoints(new Point(ptBL.lon,ptBL.lat),new Point(ptTL.lon,ptTL.lat));
+ extentRotated = geometryEngine.rotate(clippedExtent,angle * -1);
+ }
+
+ var clippedPolygon = geometryEngine.intersect(
+ gridGeomUtils.toWebMercator(polygon),
+ zonePolygon);
+
+ var clippedPolygonRotated = geometryEngine.intersects(
+ extentRotated,
+ gridGeomUtils.toWebMercator(polygon));
+
+ if (clippedPolygon || clippedPolygonRotated) {
+
+ if(clippedPolygonRotated) {
+ var clippedPolyToUTMZone = geometryEngine.intersect(
+ gridGeomUtils.toWebMercator(polygon),
+ gridGeomUtils.toWebMercator(fullZoneGeometry));
+ }
+
+ text = GZD + (this._padZero(e % 100000 / interval, 5 - Math.log10(interval))).toString()
+ + (this._padZero((minN < 0 ? (10000000 + n) : n) % 100000 / interval,
+ 5 - Math.log10(interval))).toString();
+
+ gridPolygonArgs = {
+ "clippedPolygon": clippedPolygon,
+ "unclippedPolygon": polygon,
+ "fullZoneGeometry": fullZoneGeometry,
+ "clippedPolyToUTMZone": clippedPolyToUTMZone,
+ "map": map,
+ "xmin": e,
+ "ymin": n,
+ "xmax": e + interval,
+ "ymax": n + interval,
+ "x": this._padZero(e % 100000 / interval, 5 - Math.log10(interval)).toString(),
+ "y": this._padZero((minN < 0 ? (10000000 + n) : n) % 100000 / interval,5 - Math.log10(interval)).toString(),
+ "minMaxType": "utm",
+ "utmZone": utmZone,
+ "latitudeZone": latitudeZone,
+ "GZD": GZD,
+ "utmZonePoly": zonePolygon,
+ "text": text
+ };
+
+ if(!clippedPolyToUTMZone){
+ continue;
+ }
+ gridPolygon = new GridPolygon(gridPolygonArgs);
+ polyOut.push(gridPolygon);
+ }
+ firstRow = false;
+ firstColumn = false;
+ }
+ }
+ return polyOut;
+ },
+
+ /**
+ * Pads text with zeros
+ */
+ _padZero: function(number, width) {
+ number = number.toString();
+ while (number.length < width) {
+ number = "0" + number;
+ }
+ return number;
+ },
+
+ };
+});
\ No newline at end of file
diff --git a/GRG/js/mgrs.js b/GRG/js/mgrs.js
new file mode 100644
index 0000000..e648420
--- /dev/null
+++ b/GRG/js/mgrs.js
@@ -0,0 +1,674 @@
+//// ***************************************************************************
+// * usng.js (U.S. National Grid functions)
+// * Module to calculate National Grid Coordinates
+// ****************************************************************************/
+//
+// Copyright (c) 2009 Larry Moore, jane.larry@gmail.com
+// Released under the MIT License; see
+// http://www.opensource.org/licenses/mit-license.php
+// or http://en.wikipedia.org/wiki/MIT_License
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+//
+//*****************************************************************************
+define([
+ 'esri/geometry/Point'
+], function(
+ Point
+) {
+ var k0 = 0.9996; // scale factor of central meridian
+ var er; // equatorial radius
+ var e2; // eccentricity squared = 2f - f^2 (f = flattening)
+ var e2ps; // eccentricity prime squared = e2 / (1-e2)
+ // WGS84
+ er = 6378137.0; // WGS_1984
+ e2 = 0.006694379990;
+ // NAD83
+ //er = 6378137.0; // GRS_1980
+ //e2 = 0.006694380023;
+ // NAD27
+ //er = 6378206.4 // Clarke_1866
+ //e2 = 0.006768658;
+ e2ps = e2 / (1 - e2);
+ // variable used in inverse formulas (UTMtoLL function)
+ var E1 = (1 - Math.sqrt(1 - e2)) / (1 + Math.sqrt(1 - e2));
+ return {
+ setSpheroid: function(id) {
+ id = id.toUpperCase();
+ switch (id) {
+ case "AIRY 1830": er = 6377563.396; e2 = 0.00667053999998536; break;
+ case "AIRY MODIFIED": er = 6377340.189; e2 = 0.00667053999998536; break;
+ case "AVERAGE TERRESTRIAL SYSTEM 1977": er = 6378135; e2 = 0.00669438499958795; break;
+ case "AUSTRALIAN NATIONAL": er = 6378160; e2 = 0.00669454185458764; break;
+ case "BESSEL 1841": er = 6377397.155; e2 = 0.00667437223180214; break;
+ case "BESSEL MODIFIED": er = 6377492.018; e2 = 0.00667437223180214; break;
+ case "BESSEL NAMIBIA": er = 6377483.865; e2 = 0.00667437223180214; break;
+ case "CLARKE 1858": er = 6378293.639; e2 = 0.00678514600473303; break;
+ case "NAD27":
+ case "CLARKE 1866": er = 6378206.4; e2 = 0.00676865799760964; break;
+ case "CLARKE 1866 MICHIGAN": er = 6378450.047; e2 = 0.00676865830738507; break;
+ case "CLARKE 1880": er = 6378249.138; e2 = 0.00680348101883452; break;
+ case "CLARKE 1880 (ARC)": er = 6378249.145; e2 = 0.00680348101883452; break;
+ case "CLARKE 1880 (BENOIT)": er = 6378300.79; e2 = 0.00680348271028565; break;
+ case "CLARKE 1880 (IGN)": er = 6378249.2; e2 = 0.00680348767623919; break;
+ case "CLARKE 1880 (RGS)": er = 6378249.145; e2 = 0.00680351128284906; break;
+ case "CLARKE 1880 (SGA)": er = 6378249.2; e2 = 0.00680348860198551; break;
+ case "EVEREST 1830 (DEFINITION)": er = 6377299.36; e2 = 0.00663784663019969; break;
+ case "EVEREST 1830 (MODIFIED)": er = 6377304.063; e2 = 0.00663784663019969; break;
+ case "EVEREST (ADJUSTMENT 1937)": er = 6377276.345; e2 = 0.00663784663019969; break;
+ case "EVEREST (DEFINITION 1962)": er = 6377301.243; e2 = 0.00663784606842344; break;
+ case "EVEREST (DEFINITION 1967)": er = 6377298.556; e2 = 0.00663784663019969; break;
+ case "EVEREST (DEFINITION 1975)": er = 6377299.151; e2 = 0.00663784606842344; break;
+ case "NAD83":
+ case "GEM GRAVITY POTENTIAL MODEL":
+ case "GRS 1980": er = 6378137; e2 = 0.00669438002290079; break;
+ case "GRS 1967 = INTERNATIONAL 1967": er = 6378160; e2 = 0.00669460532856765; break;
+ case "HELMERT 1906": er = 6378200; e2 = 0.00669342162296594; break;
+ case "INDONESIAN NATIONAL": er = 6378160; e2 = 0.0066946090804091; break;
+ case "INTERNATIONAL 1924": er = 6378388; e2 = 0.00672267002233332; break;
+ case "INTERNATIONAL 1967": er = 6378160; e2 = 0.00669454185458764; break;
+ case "KRASOVSKY 1940": er = 6378245; e2 = 0.00669342162296594; break;
+ case "TRANSIT PRECISE EPHEMERIS": er = 6378145; e2 = 0.00669454185458764; break;
+ case "OSU 1986 GEOIDAL MODEL": er = 6378136.2; e2 = 0.00669438006997852; break;
+ case "OSU 1991 GEOIDAL MODEL": er = 6378136.3; e2 = 0.00669438006997852; break;
+ case "PLESSIS 1817": er = 6376523; e2 = 0.00646954373789485; break;
+ case "STRUVE 1860": er = 6378298.3; e2 = 0.00677435980080942; break;
+ case "WAR OFFICE": er = 6378300.583; e2 = 0.00674534331628926; break;
+ case "NWL-10D == WGS 1972": er = 6378135; e2 = 0.00669431777826672; break;
+ case "WGS 1972": er = 6378135; e2 = 0.00669431777826672; break;
+ case "WGS84":
+ case "WGS 1984": er = 6378137; e2 = 0.00669437999014132; break;
+ case "WGS 1966": er = 6378145; e2 = 0.00669454185458764; break;
+ case "FISCHER 1960": er = 6378166; e2 = 0.00669342162296594; break;
+ case "FISCHER 1968": er = 6378150; e2 = 0.00669342162296594; break;
+ case "FISCHER MODIFIED": er = 6378155; e2 = 0.00669342162296594; break;
+ case "HOUGH 1960": er = 6378270; e2 = 0.00672267002233332; break;
+ case "EVEREST MODIFIED 1969": er = 6377295.664; e2 = 0.00663784663019969; break;
+ case "WALBECK": er = 6376896; e2 = 0.00659454809414964; break;
+ case "GRS 1967 TRUNCATED": er = 6378160; e2 = 0.00669454185458764; break;
+ }
+ e2ps = e2 / (1 - e2);
+ // variable used in inverse formulas (UTMtoLL function)
+ E1 = (1 - Math.sqrt(1 - e2)) / (1 + Math.sqrt(1 - e2));
+ },
+ getSpheroidList: function() {
+ return [
+ "AIRY 1830",
+ "AIRY MODIFIED",
+ "AUSTRALIAN NATIONAL",
+ "AVERAGE TERRESTRIAL SYSTEM 1977",
+ "BESSEL 1841",
+ "BESSEL MODIFIED",
+ "BESSEL NAMIBIA",
+ "CLARKE 1858",
+ "CLARKE 1866 MICHIGAN",
+ "CLARKE 1866",
+ "CLARKE 1880 (ARC)",
+ "CLARKE 1880 (BENOIT)",
+ "CLARKE 1880 (IGN)",
+ "CLARKE 1880 (RGS)",
+ "CLARKE 1880 (SGA)",
+ "CLARKE 1880",
+ "EVEREST (ADJUSTMENT 1937)",
+ "EVEREST (DEFINITION 1962)",
+ "EVEREST (DEFINITION 1967)",
+ "EVEREST (DEFINITION 1975)",
+ "EVEREST 1830 (DEFINITION)",
+ "EVEREST 1830 (MODIFIED)",
+ "EVEREST MODIFIED 1969",
+ "FISCHER 1960",
+ "FISCHER 1968",
+ "FISCHER MODIFIED",
+ "GEM GRAVITY POTENTIAL MODEL",
+ "GRS 1967 = INTERNATIONAL 1967",
+ "GRS 1967 TRUNCATED",
+ "GRS 1980",
+ "HELMERT 1906",
+ "HOUGH 1960",
+ "INDONESIAN NATIONAL",
+ "INTERNATIONAL 1924",
+ "INTERNATIONAL 1967",
+ "KRASOVSKY 1940",
+ "NWL-10D == WGS 1972",
+ "OSU 1986 GEOIDAL MODEL",
+ "OSU 1991 GEOIDAL MODEL",
+ "PLESSIS 1817",
+ "STRUVE 1860",
+ "TRANSIT PRECISE EPHEMERIS",
+ "WALBECK",
+ "WAR OFFICE",
+ "WGS 1966",
+ "WGS 1972",
+ "WGS 1984"
+ ];
+ },
+ getZoneNumber: function(lat, lon) {
+ lat = parseFloat(lat);
+ lon = parseFloat(lon);
+ // check input
+ if (lon > 360 || lon < -180) {
+ while (lon < -180) {lon += 360;}
+ while (lon > 180) {lon -= 360;}
+ }
+ if (lon > 360 || lon < -180 || lat > 90 || lat < -90) {
+ console.error('Bad input. lat: ' + lat + ' lon: ' + lon);
+ //debugger;
+ }
+ // convert 0-360 to [-180 to 180] range
+ // FIXED: var lonTemp = (lon + 180) - parseInt((lon + 180) / 360, 10) * 360 - 180;
+ var lonTemp = (lon + 180) - Math.floor((lon + 180) / 360) * 360 - 180;
+ // FIXED: var zoneNumber = parseInt((lonTemp + 180) / 6, 10) + 1;
+ var zoneNumber = Math.floor((lonTemp + 180) / 6) + 1;
+ // There are special UTM zones between 0 degrees and 36 degrees longitude above 72
+ // degrees latitude and a special zone 32 between 56 degrees and 64 degrees north latitude:
+ // -UTM Zone 32 has been widened to 9° (at the expense of zone 31) between
+ // latitudes 56° and 64° (band V) to accommodate southwest Norway. Thus
+ // zone 32 it extends westwards to 3°E in the North Sea.
+ // -Similarly, between 72° and 84° (band X), zones 33 and 35 have been widened
+ // to 12° to accommodate Svalbard. To compensate for these 12° wide zones,
+ // zones 31 and 37 are widened to 9° and zones 32, 34, and 36 are eliminated.
+ // Thus the W and E boundaries of zones are
+ // 31: 0 - 9 E
+ // 33: 9 - 21 E
+ // 35: 21 - 33 E
+ // 37: 33 - 42 E
+ //
+ // Handle special case of west coast of Norway
+ if (lat >= 56.0 && lat < 64.0 && lonTemp >= 3.0 && lonTemp < 12.0) {
+ zoneNumber = 32;
+ }
+ // Special zones for Svalbard
+ if (lat >= 72.0 && lat < 84.0) {
+ if (lonTemp >= 0.0 && lonTemp < 9.0) {
+ zoneNumber = 31;
+ } else if (lonTemp >= 9.0 && lonTemp < 21.0) {
+ zoneNumber = 33;
+ } else if (lonTemp >= 21.0 && lonTemp < 33.0) {
+ zoneNumber = 35;
+ } else if (lonTemp >= 33.0 && lonTemp < 42.0) {
+ zoneNumber = 37;
+ }
+ }
+ return zoneNumber;
+ },
+ LLtoUTM: function(lat, lon, zone) {
+ // Converts lat/lon to UTM coords
+ //
+ // Output is in the input array utmcoords
+ // utmcoords[0] = easting
+ // utmcoords[1] = northing (NEGATIVE value in southern hemisphere)
+ // utmcoords[2] = zone
+ //
+ lat = parseFloat(lat);
+ lon = parseFloat(lon);
+ // Constrain reporting USNG coords to the latitude range [80S .. 84N]
+ if (lat > 84.0 || lat < -80.0) {
+ return "undefined, ensure 84N > Lat > 80S";
+ }
+ // sanity check on input - turned off when testing with Generic Viewer
+ if (lon > 360 || lon < -180) {
+ while (lon < -180) {lon += 360;}
+ while (lon > 180) {lon -= 360;}
+ }
+ if (lon > 360 || lon < -180 || lat > 90 || lat < -90) {
+ console.error('Bad input. lat: ' + lat + ' lon: ' + lon);
+ //debugger;
+ }
+ // Make sure the longitude is between -180.00 .. 179.99..
+ // Convert values on 0-360 range to this range.
+ // FIXED:
+ var lonTemp, latRad, lonRad, zoneNumber, lonOrigin, lonOriginRad, UTMZone, N, T, C, A, M;
+ // FIXED: lonTemp = (lon + 180) - parseInt((lon + 180) / 360, 10) * 360 - 180;
+ lonTemp = (lon + 180) - Math.floor((lon + 180) / 360) * 360 - 180;
+ latRad = lat * Math.PI / 180;
+ lonRad = lonTemp * Math.PI / 180;
+ // user-supplied zone number will force coordinates to be computed in a particular zone
+ if (!zone) {
+ zoneNumber = this.getZoneNumber(lat, lon);
+ } else {
+ zoneNumber = zone;
+ }
+ lonOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin in middle of zone
+ lonOriginRad = lonOrigin * Math.PI / 180;
+ // compute the UTM Zone from the latitude and longitude
+ UTMZone = zoneNumber + "" + this.UTMLetterDesignator(lat) + " ";
+ N = er / Math.sqrt(1 - e2 * Math.sin(latRad) * Math.sin(latRad));
+ T = Math.tan(latRad) * Math.tan(latRad);
+ C = e2ps * Math.cos(latRad) * Math.cos(latRad);
+ A = Math.cos(latRad) * (lonRad - lonOriginRad);
+ // Note that the term Mo drops out of the "M" equation, because phi
+ // (latitude crossing the central meridian, lambda0, at the origin of the
+ // x,y coordinates), is equal to zero for UTM.
+ M = er * ((1 - e2 / 4 - 3 * (e2 * e2) / 64 - 5 * (e2 * e2 * e2) / 256) *
+ latRad - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2 / 1024) *
+ Math.sin(2 * latRad) + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024) *
+ Math.sin(4 * latRad) - (35 * e2 * e2 * e2 / 3072) * Math.sin(6 * latRad));
+ var UTMEasting = (k0 * N * (A + (1 - T + C) * (A * A * A) / 6 +
+ (5 - 18 * T + T * T + 72 * C - 58 * e2ps) * (A * A * A * A * A) / 120) + 500000.0);
+ var UTMNorthing = (k0 * (M + N * Math.tan(latRad) * ((A * A) / 2 +
+ (5 - T + 9 * C + 4 * C * C) * (A * A * A * A) / 24 + (61 - 58 * T +
+ T * T + 600 * C - 330 * e2ps) * (A * A * A * A * A * A) / 720)));
+ var UTMcoordinates = UTMZone + " " + Math.round(UTMEasting);
+ if (UTMNorthing < 0) {
+ UTMcoordinates = UTMcoordinates + "mE " + Math.round(10000000 + UTMNorthing) + "mN";
+ } else {
+ UTMcoordinates = UTMcoordinates + "mE " + Math.round(UTMNorthing) + "mN";
+ }
+ return [UTMEasting, UTMNorthing, zoneNumber];
+ },
+ LLtoUSNG: function(lat, lon, precision, zone) {
+ // Converts lat/lon to USNG coordinates
+ precision = precision || 5; // 5 = 1m precision
+ // user-supplied zone number will force coordinates to be computed in a particular zone
+ // FIXED:
+ var zoneNumber;
+ if (!zone) {
+ zoneNumber = this.getZoneNumber(lat, lon);
+ } else {
+ zoneNumber = zone;
+ }
+ lat = parseFloat(lat);
+ lon = parseFloat(lon);
+ // convert lat/lon to UTM coordinates
+ var coords = this.LLtoUTM(lat, lon, zoneNumber);
+ var UTMEasting = coords[0];
+ var UTMNorthing = coords[1];
+ // then convert UTM to USNG
+ // southern hemisphere case
+ if (lat < 0) {
+ // Use offset for southern hemisphere
+ UTMNorthing += 10000000.0;
+ }
+ var USNGLetters = this.findGridLetters(zoneNumber, UTMNorthing, UTMEasting);
+ var USNGNorthing = Math.round(UTMNorthing) % 100000;
+ var USNGEasting = Math.round(UTMEasting) % 100000;
+ // added... truncate digits to achieve specified precision
+ USNGNorthing = Math.floor(USNGNorthing / Math.pow(10, (5 - precision)));
+ USNGEasting = Math.floor(USNGEasting / Math.pow(10, (5 - precision)));
+ var USNG = this.getZoneNumber(lat, lon) + this.UTMLetterDesignator(lat) +
+ " " + USNGLetters + " ";
+ // REVISIT: Modify to incorporate dynamic precision ?
+ for (var i = String(USNGEasting).length; i < precision; i++) {
+ USNG += "0";
+ }
+ USNG += USNGEasting + " ";
+ for (i = String(USNGNorthing).length; i < precision; i++) {
+ USNG += "0";
+ }
+ USNG += USNGNorthing;
+ return USNG;
+ },
+ UTMLetterDesignator: function(lat) {
+ // determines the correct UTM letter designator for the given
+ // latitude ('C' to 'X'; 'Z' if latitude is outside the UTM limits of 84N to 80S)
+ lat = parseFloat(lat);
+ var letterDesignator;
+ if ((84 >= lat) && (lat >= 72)) {
+ letterDesignator = 'X';
+ }
+ else if ((72 > lat) && (lat >= 64)) {
+ letterDesignator = 'W';
+ }
+ else if ((64 > lat) && (lat >= 56)) {
+ letterDesignator = 'V';
+ }
+ else if ((56 > lat) && (lat >= 48)) {
+ letterDesignator = 'U';
+ }
+ else if ((48 > lat) && (lat >= 40)) {
+ letterDesignator = 'T';
+ }
+ else if ((40 > lat) && (lat >= 32)) {
+ letterDesignator = 'S';
+ }
+ else if ((32 > lat) && (lat >= 24)) {
+ letterDesignator = 'R';
+ }
+ else if ((24 > lat) && (lat >= 16)) {
+ letterDesignator = 'Q';
+ }
+ else if ((16 > lat) && (lat >= 8)) {
+ letterDesignator = 'P';
+ }
+ else if ((8 > lat) && (lat >= 0)) {
+ letterDesignator = 'N';
+ }
+ else if ((0 > lat) && (lat >= -8)) {
+ letterDesignator = 'M';
+ }
+ else if ((-8 > lat) && (lat >= -16)) {
+ letterDesignator = 'L';
+ }
+ else if ((-16 > lat) && (lat >= -24)) {
+ letterDesignator = 'K';
+ }
+ else if ((-24 > lat) && (lat >= -32)) {
+ letterDesignator = 'J';
+ }
+ else if ((-32 > lat) && (lat >= -40)) {
+ letterDesignator = 'H';
+ }
+ else if ((-40 > lat) && (lat >= -48)) {
+ letterDesignator = 'G';
+ }
+ else if ((-48 > lat) && (lat >= -56)) {
+ letterDesignator = 'F';
+ }
+ else if ((-56 > lat) && (lat >= -64)) {
+ letterDesignator = 'E';
+ }
+ else if ((-64 > lat) && (lat >= -72)) {
+ letterDesignator = 'D';
+ }
+ else if ((-72 > lat) && (lat >= -80)) {
+ letterDesignator = 'C';
+ }
+ else {
+ letterDesignator = 'Z'; // error flag
+ }
+ return letterDesignator;
+ },
+ findSet: function(zoneNum) {
+ // There are six unique sets, corresponding to individual grid numbers in
+ // sets 1-6, 7-12, 13-18, etc. Set 1 is the same as sets 7, 13, ..;
+ // Set 2 is the same as sets 8, 14, ..
+ zoneNum = parseInt(zoneNum, 10);
+ zoneNum = zoneNum % 6;
+ switch (zoneNum) {
+ case 0:
+ return 6;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 3;
+ case 4:
+ return 4;
+ case 5:
+ return 5;
+ default:
+ return -1;
+ }
+ },
+ findGridLetters: function(zoneNum, northing, easting) {
+ //Retrieve the square identification for a given coordinate pair & zone
+ //See "lettersHelper" function documentation for more details.
+ zoneNum = parseInt(zoneNum, 10);
+ northing = parseFloat(northing);
+ easting = parseFloat(easting);
+ var row = 1;
+ // northing coordinate to single-meter precision
+ var north_1m = Math.round(northing);
+ // Get the row position for the square identifier that contains the point
+ while (north_1m >= 100000) {
+ north_1m = north_1m - 100000;
+ row++;
+ }
+ // cycle repeats (wraps) after 20 rows
+ row = row % 20;
+ var col = 0;
+ // easting coordinate to single-meter precision
+ var east_1m = Math.round(easting);
+ // Get the column position for the square identifier that contains the point
+ while (east_1m >= 100000) {
+ east_1m = east_1m - 100000;
+ col++;
+ }
+ // cycle repeats (wraps) after 8 columns
+ col = col % 8;
+ return this.lettersHelper(this.findSet(zoneNum), row, col);
+ },
+ lettersHelper: function(set, row, col) {
+ // Retrieve the Square Identification (two-character letter code), for the
+ // given row, column and set identifier
+ // handle case of last row
+ if (row === 0) {
+ row = 20 - 1;
+ } else {
+ row--;
+ }
+ // handle case of last column
+ if (col === 0) {
+ col = 8 - 1;
+ } else {
+ col--;
+ }
+ var l1, l2;
+ switch (set) {
+ case 1:
+ l1 = "ABCDEFGH"; // column ids
+ l2 = "ABCDEFGHJKLMNPQRSTUV"; // row ids
+ return l1.charAt(col) + l2.charAt(row);
+ case 2:
+ l1 = "JKLMNPQR";
+ l2 = "FGHJKLMNPQRSTUVABCDE";
+ return l1.charAt(col) + l2.charAt(row);
+ case 3:
+ l1 = "STUVWXYZ";
+ l2 = "ABCDEFGHJKLMNPQRSTUV";
+ return l1.charAt(col) + l2.charAt(row);
+ case 4:
+ l1 = "ABCDEFGH";
+ l2 = "FGHJKLMNPQRSTUVABCDE";
+ return l1.charAt(col) + l2.charAt(row);
+ case 5:
+ l1 = "JKLMNPQR";
+ l2 = "ABCDEFGHJKLMNPQRSTUV";
+ return l1.charAt(col) + l2.charAt(row);
+ case 6:
+ l1 = "STUVWXYZ";
+ l2 = "FGHJKLMNPQRSTUVABCDE";
+ return l1.charAt(col) + l2.charAt(row);
+ }
+ },
+ UTMtoLL: function(UTMNorthing, UTMEasting, UTMZoneNumber) {
+ // convert UTM coords to decimal degrees
+ // Expected Input args:
+ // UTMNorthing : northing-m (numeric), eg. 432001.8
+ // southern hemisphere NEGATIVE from equator ('real' value - 10,000,000)
+ // UTMEasting : easting-m (numeric), eg. 4000000.0
+ // UTMZoneNumber : 6-deg longitudinal zone (numeric), eg. 18
+ //
+ // remove 500,000 meter offset for longitude
+ var xUTM = parseFloat(UTMEasting) - 500000.0;
+ var yUTM = parseFloat(UTMNorthing);
+ var zoneNumber = parseInt(UTMZoneNumber, 10);
+ // origin longitude for the zone (+3 puts origin in zone center)
+ var lonOrigin = (zoneNumber - 1) * 6 - 180 + 3;
+ // M is the "true distance along the central meridian from the Equator to phi
+ // (latitude)
+ var M = yUTM / k0;
+ var mu = M / (er * (1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256));
+ // phi1 is the "footprint latitude" or the latitude at the central meridian which
+ // has the same y coordinate as that of the point (phi (lat), lambda (lon) ).
+ var phi1Rad = mu + (3 * E1 / 2 - 27 * E1 * E1 * E1 / 32) *
+ Math.sin(2 * mu) + (21 * E1 * E1 / 16 - 55 * E1 * E1 * E1 * E1 / 32) *
+ Math.sin(4 * mu) + (151 * E1 * E1 * E1 / 96) * Math.sin(6 * mu);
+ //var phi1 = phi1Rad * 180.0 / Math.PI;
+ // Terms used in the conversion equations
+ var N1 = er / Math.sqrt(1 - e2 * Math.sin(phi1Rad) * Math.sin(phi1Rad));
+ var T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
+ var C1 = e2ps * Math.cos(phi1Rad) * Math.cos(phi1Rad);
+ var R1 = er * (1 - e2) / Math.pow(1 - e2 * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
+ var D = xUTM / (N1 * k0);
+ // Calculate latitude, in decimal degrees
+ var lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 -
+ (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * e2ps) *
+ D * D * D * D / 24 + (61 + 90 *
+ T1 + 298 * C1 + 45 * T1 * T1 - 252 * e2ps - 3 * C1 * C1) * D * D * D * D * D * D / 720);
+ lat = lat * 180.0 / Math.PI;
+ // Calculate longitude, in decimal degrees
+ var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 *
+ C1 * C1 + 8 * e2ps + 24 * T1 * T1) * D * D * D * D * D / 120) /
+ Math.cos(phi1Rad);
+ lon = lonOrigin + lon * 180.0 / Math.PI;
+ var ret = {};
+ ret.lat = lat;
+ ret.lon = lon;
+ return ret;
+ },
+ USNGtoUTM: function(zone, ltr, sq1, sq2, east, north) {
+ //Starts (southern edge) of N-S zones in millons of meters
+ var zoneBase = [
+ 1.1, 2.0, 2.9, 3.8, 4.7, 5.6, 6.5,
+ 7.3, 8.2, 9.1, 0, 0.8, 1.7, 2.6,
+ 3.5, 4.4, 5.3, 6.2, 7.0, 7.9
+ ];//Starts of 2 million meter segments, indexed by zone
+ var segBase = [0, 2, 2, 2, 4, 4, 6, 6, 8, 8, 0, 0, 0, 2, 2, 4, 4, 6, 6, 6];
+ // convert easting to UTM
+ var eSqrs = "ABCDEFGHJKLMNPQRSTUVWXYZ".indexOf(sq1);
+ var appxEast = 1 + eSqrs % 8;
+ // convert northing to UTM
+ var letNorth = "CDEFGHJKLMNPQRSTUVWX".indexOf(ltr);
+ var nSqrs;
+ if (zone % 2) {//odd number zone
+ nSqrs = "ABCDEFGHJKLMNPQRSTUV".indexOf(sq2);
+ } else {// even number zone
+ nSqrs = "FGHJKLMNPQRSTUVABCDE".indexOf(sq2);
+ }
+ var zoneStart = zoneBase[letNorth];
+ var appxNorth = Number(segBase[letNorth]) + nSqrs / 10;
+ if (appxNorth < zoneStart) {
+ appxNorth += 2;
+ }
+ var ret = {};
+ ret.N = appxNorth * 1000000 + Number(north) * Math.pow(10, 5 - north.length);
+ ret.E = appxEast * 100000 + Number(east) * Math.pow(10, 5 - east.length);
+ ret.zone = zone;
+ ret.letter = ltr;
+ return ret;
+ },
+ USNGtoLL: function(usngStr_input) {
+ // parse a USNG string and feed results to USNGtoUTM, then the results of that to UTMtoLL
+ var usngp = this.parseUSNG_str(usngStr_input);
+ // convert USNG coords to UTM; this routine counts digits and sets precision
+ var coords = this.USNGtoUTM(usngp.zone, usngp.ltr,
+ usngp.sq1, usngp.sq2, usngp.east, usngp.north);
+ // southern hemisphere case
+ if (usngp.ltr < 'N') {
+ coords.N -= 10000000.0;
+ }
+ coords = this.UTMtoLL(coords.N, coords.E, usngp.zone);
+ return [coords.lat, coords.lon];
+ },
+ parseUSNG_str: function(usngStr_input) {
+ // convert lower-case characters to upper case, remove space delimeters,
+ // separate string into parts
+ var usngStr = [];
+ // FIXED:
+ var usngStr_temp = usngStr_input.toUpperCase();
+ // put usng string in 'standard' form with no space delimiters
+ var regexp = /%20/g;
+ usngStr = usngStr_temp.replace(regexp, "");
+ regexp = / /g;
+ usngStr = usngStr_temp.replace(regexp, "");
+ if (usngStr.length < 7) {
+ return 0;
+ }
+ // break usng string into its component pieces
+ var parts = {};
+ var j = 0;
+ parts.zone = usngStr.charAt(j++) * 10 + usngStr.charAt(j++) * 1;
+ parts.ltr = usngStr.charAt(j++);
+ parts.sq1 = usngStr.charAt(j++);
+ parts.sq2 = usngStr.charAt(j++);
+ parts.precision = (usngStr.length - j) / 2;
+ parts.east = '';
+ parts.north = '';
+ for (var k = 0; k < parts.precision; k++) {
+ parts.east += usngStr.charAt(j++);
+ }
+ if (usngStr[j] === " ") {
+ j++;
+ }
+ for (k = 0; k < parts.precision; k++) {
+ parts.north += usngStr.charAt(j++);
+ }
+ return parts;
+ },
+ isUSNG: function(inputStr) {
+ // checks a string to see if it is valid USNG;
+ // if so, returns the string in all upper case, no delimeters
+ // if not, returns 0
+ //var j = 0;
+ //var k;
+ var strregexp;
+ // convert all letters to upper case
+ var usngStr = inputStr.toUpperCase();
+ // get rid of space delimeters
+ var regexp = /%20/g;
+ usngStr = usngStr.replace(regexp, "");
+ regexp = / /g;
+ usngStr = usngStr.replace(regexp, "");
+ if (usngStr.length > 15) {
+ return 0;
+ }
+ strregexp = new RegExp("^[0-9]{2}[CDEFGHJKLMNPQRSTUVWX]$");
+ if (usngStr.match(strregexp)) {
+ return 0;
+ }
+ strregexp = new RegExp(
+ "^[0-9]{2}[CDEFGHJKLMNPQRSTUVWX]" +
+ "[ABCDEFGHJKLMNPQRSTUVWXYZ][ABCDEFGHJKLMNPQRSTUV]([0-9][0-9]){0,5}");
+ if (!usngStr.match(strregexp)) {
+ return 0;
+ }
+ if (usngStr.length < 7) {
+ return 0;
+ }
+ return usngStr;
+ },
+ LLtoMGRS: function(lat, lon, precision) {
+ // remove spaces from USNG string to produce MGRS string
+ precision = precision || 5; // 5 = 1m precision
+ var usng_str = this.LLtoUSNG(lat, lon, precision);
+ return usng_str.replace(/ /g, "");
+ },
+ USNGtoPoint: function(str) {
+ // wrapper function specific to Esri ArcGIS JS API
+ // makes a conversion from USNG string to lat/lng, return a esri.geometry.Point
+ var latlng = this.USNGtoLL(str);
+ return new Point(latlng[1], latlng[0]);
+ },
+ pointToUSNG: function(pt, precision) {
+ var lat = pt.getLatitude();
+ var lon = pt.getLongitude();
+ return this.LLtoUSNG(lat,lon,precision);
+ },
+ LLtoUSNG_nad27: function(lat, lon, precision) {
+ precision = precision || 5; // 5 = 1m precision
+ var usngstr;
+ // set to NAD27
+ // FIXED:
+ var er, e2;
+ er = 6378206.4; // Clarke_1866
+ e2 = 0.006768658;
+ usngstr = this.LLtoUSNG(lat, lon, precision);
+ // reset back to WGS84
+ er = 6378137.0; // WGS_1984
+ e2 = 0.006694379990;
+ return usngstr + " (NAD27)";
+ }
+ };
+});
diff --git a/GRG/js/util.js b/GRG/js/util.js
new file mode 100644
index 0000000..a6c3b04
--- /dev/null
+++ b/GRG/js/util.js
@@ -0,0 +1,579 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+/*global define*/
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/array',
+ 'dojo/_base/Deferred',
+ 'esri/tasks/GeometryService'
+], function (
+ dojoDeclare,
+ dojoArray,
+ Deferred,
+ EsriGeometryService
+) {
+ 'use strict';
+ return dojoDeclare(null, {
+
+ /**
+ *
+ **/
+ constructor: function (geoServiceURL) {
+ if (!geoServiceURL) {
+ geoServiceURL = '//utility.arcgisonline.com/arcgis/rest/services/Geometry/GeometryServer';
+ }
+ this.geomService = new EsriGeometryService(geoServiceURL);
+ },
+
+ /**
+ *
+ **/
+ getCleanInput: function (fromstr) {
+ fromstr = fromstr.replace(/\n/g,'');
+ fromstr = fromstr.replace(/\s+/g, ' ').trim();
+ return fromstr.toUpperCase();
+ },
+
+ /**
+ * Send request to get dd coordinates in format string
+ **/
+ getCoordValues: function (fromInput, toType, numDigits) {
+ var deferred = new Deferred();
+ var nd = numDigits || 6;
+ var tt;
+ if (toType.name) {
+ tt = toType.name;
+ } else {
+ tt = toType;
+ }
+ /**
+ * for parameter info
+ * http://resources.arcgis.com/en/help/arcgis-rest-api/#/To_GeoCoordinateString/02r30000026w000000/
+ **/
+ var params = {
+ sr: 4326,
+ coordinates: [[fromInput.x, fromInput.y]],
+ conversionType: tt,
+ numOfDigits: nd,
+ rounding: true,
+ addSpaces: false
+ };
+
+ switch (toType) {
+ case 'DD':
+ params.numOfDigits = 6;
+ break;
+ case 'USNG':
+ params.numOfDigits = 5;
+ break;
+ case 'MGRS':
+ params.conversionMode = 'mgrsDefault';
+ params.numOfDigits = 5;
+ break;
+ case 'UTM (H)':
+ params.conversionType = 'utm';
+ params.conversionMode = 'utmNorthSouth';
+ params.addSpaces = true;
+ break;
+ case 'UTM':
+ params.conversionType = 'utm';
+ params.conversionMode = 'utmDefault';
+ params.addSpaces = true;
+ break;
+ case 'GARS':
+ params.conversionMode = 'garsDefault';
+ break;
+ }
+
+ this.geomService.toGeoCoordinateString(params).then(function(itm) {
+ deferred.resolve(itm);
+ },function() {
+ deferred.resolve(null);
+ });
+
+ return deferred.promise;
+ },
+
+ /**
+ *
+ **/
+ getXYNotation: function (fromStr, toType) {
+ var deferred = new Deferred();
+ var a;
+ var tt;
+ if (toType.name) {
+ tt = toType.name;
+ } else {
+ tt = toType;
+ }
+
+ var params = {
+ sr: 4326,
+ conversionType: tt,
+ strings: []
+ };
+
+ switch (tt) {
+ case 'DD':
+ case 'DDM':
+ case 'DMS':
+ params.numOfDigits = 2;
+ a = fromStr.replace(/[°˚º^~*"'′¨˝]/g, '');
+ params.strings.push(a);
+ break;
+ case 'USNG':
+ params.strings.push(fromStr);
+ params.addSpaces = 'false';
+ break;
+ case 'MGRS':
+ params.conversionMode = 'mgrsNewStyle';
+ params.strings.push(fromStr);
+ params.addSpaces = 'false';
+ break;
+ case 'UTM (H)':
+ params.conversionType = 'utm';
+ params.conversionMode = 'utmNorthSouth';
+ params.strings.push(fromStr);
+ break;
+ case 'UTM':
+ params.conversionType = 'utm';
+ params.conversionMode = 'utmDefault';
+ params.strings.push(fromStr);
+ break;
+ case 'GARS':
+ params.conversionMode = 'garsCenter';
+ params.strings.push(fromStr);
+ break;
+ case 'GEOREF':
+ params.strings.push(fromStr);
+ break;
+ }
+
+ this.geomService.fromGeoCoordinateString(params).then(function(itm) {
+ deferred.resolve(itm);
+ },function() {
+ deferred.resolve(null);
+ });
+
+ return deferred.promise;
+ },
+
+ getNotations: function () {
+ var strs = [
+ {
+ name: 'DD',
+ pattern: /^(([NS\+\-\s])*([0-8]?\d([,.]\d*)?|90([,.]0*)?)([°˚º^~*]*)([NS\+\-\s])*)([,:;\s|\/\\]+)(([EW\+\-\s])*([0]?\d?\d([,.]\d*)?|1[0-7]\d([,.]\d*)?|180([,.]0*)?)([°˚º^~*]*)([EW\+\-\s])*)$/,
+ notationType: "DD - Latitude/Longitude",
+ conversionType: "DD"
+ }, {
+ name: 'DDrev',
+ pattern: /^(([EW\+\-\s])*([0]?\d?\d([,.]\d*)?|1[0-7]\d([,.]\d*)?|180([,.]0*)?)([°˚º^~*]*)([EW\+\-\s])*)([,:;\s|\/\\]+)(([NS\+\-\s])*([0-8]?\d([,.]\d*)?|90([,.]0*)?)([°˚º^~*]*)([NS\+\-\s])*)$/,
+ notationType: "DD - Longitude/Latitude",
+ conversionType: "DD"
+ }, {
+ name: 'DDM',
+ pattern: /^(([NS\+\-\s])*([0-8]?\d|90)[°˚º^~*\s\-_]+(([0-5]?\d|\d)([,.]\d*)?)['′\s_]*([NS\+\-\s])*)([,:;\s|\/\\]+)(([EW\+\-\s])*([0]?\d?\d|1[0-7]\d|180)[°˚º^~*\s\-_]+(([0-5]\d|\d)([,.]\d*)?)['′\s_]*([EW\+\-\s])*)[\s]*$/,
+ notationType: "DDM - Latitude/Longitude",
+ conversionType: "DDM"
+ }, {
+ name: 'DDMrev',
+ pattern: /^(([EW\+\-\s])*([0]?\d?\d|1[0-7]\d|180)[°˚º^~*\s\-_]+(([0-5]\d|\d)([,.]\d*)?)['′\s_]*([EW\+\-\s])*)([,:;\s|\/\\]+)(([NS\+\-\s])*([0-8]?\d|90)[°˚º^~*\s\-_]+(([0-5]?\d|\d)([,.]\d*)?)['′\s_]*([NS\+\-\s])*)[\s]*$/,
+ notationType: "DDM - Longitude/Latitude",
+ conversionType: "DDM"
+ }, {
+ name: 'DMS',
+ pattern: /^(([NS\+\-\s])*([0-8]?\d|90)[°˚º^~*\s\-_]+([0-5]?\d|\d)['′\s\-_]+(([0-5]?\d|\d)([,.]\d*)?)["¨˝\s_]*([NS\+\-\s])*)([,:;\s|\/\\]+)(([EW\+\-\s])*([0]?\d?\d|1[0-7]\d|180)[°˚º^~*\s\-_]+([0-5]\d|\d)['′\s\-_]+(([0-5]?\d|\d)([,.]\d*)?)["¨˝\s_]*([EW\+\-\s])*)[\s]*$/,
+ notationType: "DMS - Latitude/Longitude",
+ conversionType: "DMS"
+ }, {
+ name: 'DMSrev',
+ pattern: /^(([EW\+\-\s])*([0]?\d?\d|1[0-7]\d|180)[°˚º^~*\s\-_]+([0-5]\d|\d)['′\s\-_]+(([0-5]?\d|\d)([,.]\d*)?)["¨˝\s_]*([EW\+\-\s])*)([,:;\s|\/\\]+)(([NS\+\-\s])*([0-8]?\d|90)[°˚º^~*\s\-_]+([0-5]?\d|\d)['′\s\-_]+(([0-5]?\d|\d)([,.]\d*)?)["¨˝\s_]*([NS\+\-\s])*)[\s]*$/,
+ notationType: "DMS - Longitude/Latitude",
+ conversionType: "DMS"
+ }, {
+ name: 'GARS',
+ pattern: /^\d{3}[a-zA-Z]{2}[1-4]?[1-9]?$/,
+ notationType: "GARS",
+ conversionType: "GARS"
+ }, {
+ name: 'GEOREF',
+ pattern: /^[a-zA-Z]{4}\d{1,8}$/,
+ notationType: "GEOREF",
+ conversionType: "GEOREF"
+ }, {
+ name: 'MGRS',
+ pattern: /^\d{1,2}[-,;:\s]*[C-HJ-NP-X][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*(\d[-,;:\s]+\d|\d{2}[-,;:\s]+\d{2}|\d{3}[-,;:\s]+\d{3}|\d{4}[-,;:\s]+\d{4}|\d{5}[-,;:\s]+\d{5})$|^(\d{1,2}[-,;:\s]*[C-HJ-NP-X][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*)(\d{2}|\d{4}|\d{6}|\d{8}|\d{10})?$|^[ABYZ][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*(\d[-,;:\s]+\d|\d{2}[-,;:\s]+\d{2}|\d{3}[-,;:\s]+\d{3}|\d{4}[-,;:\s]+\d{4}|\d{5}[-,;:\s]+\d{5})$|^[ABYZ][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*(\d{2}|\d{4}|\d{6}|\d{8}|\d{10})?$/,
+ notationType: "MGRS",
+ conversionType: "MGRS"
+ },
+ //not sure if USNG is needed as its exactly the same as MGRS
+ /*{
+ name: 'USNG',
+ pattern: /^\d{1,2}[-,;:\s]*[C-HJ-NP-X][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*(\d[-,;:\s]+\d|\d{2}[-,;:\s]+\d{2}|\d{3}[-,;:\s]+\d{3}|\d{4}[-,;:\s]+\d{4}|\d{5}[-,;:\s]+\d{5})$|^(\d{1,2}[-,;:\s]*[C-HJ-NP-X][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*)(\d{2}|\d{4}|\d{6}|\d{8}|\d{10})?$|^[ABYZ][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*(\d[-,;:\s]+\d|\d{2}[-,;:\s]+\d{2}|\d{3}[-,;:\s]+\d{3}|\d{4}[-,;:\s]+\d{4}|\d{5}[-,;:\s]+\d{5})$|^[ABYZ][-,;:\s]*[A-HJ-NP-Z]{2}[-,;:\s]*(\d{2}|\d{4}|\d{6}|\d{8}|\d{10})?$/,
+ notationType: "USNG",
+ conversionType: "USNG"
+ },*/
+ {
+ name: 'UTM',
+ pattern: /^\d{1,2}[-,;:\s]*[c-hj-np-xC-HJ-NP-X][-,;:\s]*\d{1,6}\.?\d*[mM]?[-,;:\s]?\d{1,7}\.?\d*[mM]?$/,
+ notationType: "UTM - Band Letter",
+ conversionType: "UTM"
+ }, {
+ name: 'UTM (H)',
+ pattern: /^\d{1,2}[-,;:\s]*[NnSs][-,;:\s]*\d{1,6}\.?\d*[mM]?[-,;:\s]+\d{1,7}\.?\d*[mM]?$/,
+ notationType: "UTM - Hemisphere (N/S)",
+ conversionType: "UTM (H)"
+ }
+ ];
+
+ return strs;
+ },
+
+ getCoordinateType: function (fromInput) {
+ var clnInput = this.getCleanInput(fromInput);
+ var deferred = new Deferred();
+ //regexr.com
+
+ var strs = this.getNotations();
+
+ var matchedtype = dojoArray.filter(strs, function (itm) {
+ return itm.pattern.test(this.v)
+ }, {
+ v:clnInput
+ });
+
+ if (matchedtype.length > 0) {
+ deferred.resolve(matchedtype);
+ } else {
+ deferred.resolve(null);
+ }
+ return deferred.promise;
+ },
+
+ /**
+ *
+ **/
+ getFormattedDDStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ var parts = fromValue[0].split(/[ ,]+/);
+
+ r.latdeg = parts[0].replace(/[nNsS]/, '');
+ r.londeg = parts[1].replace(/[eEwW]/, '');
+
+ if (addSignPrefix) {
+ parts[0].slice(-1) === 'N'?r.latdeg = '+' + r.latdeg:r.latdeg = '-' + r.latdeg;
+ parts[1].slice(-1) === "W"?r.londeg = '-' + r.londeg:r.londeg = '+' + r.londeg;
+ }
+
+ var s = withFormatStr.replace(/X/, r.londeg);
+ s = s.replace(/[eEwW]/, parts[1].slice(-1));
+ s = s.replace(/[nNsS]/, parts[0].slice(-1));
+ s = s.replace(/Y/, r.latdeg);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedDDMStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ r.parts = fromValue[0].split(/[ ,]+/);
+
+ r.latdeg = r.parts[0];
+ r.latmin = r.parts[1].replace(/[nNsS]/, '');
+ r.londeg = r.parts[2];
+ r.lonmin = r.parts[3].replace(/[eEwW]/, '');
+
+ if (addSignPrefix) {
+ r.parts[1].slice(-1) === 'N'?r.latdeg = '+' + r.latdeg:r.latdeg = '-' + r.latdeg;
+ r.parts[3].slice(-1) === 'W'?r.londeg = '-' + r.londeg:r.londeg = '+' + r.londeg;
+ }
+
+ //A° B'N X° Y'E
+ var s = withFormatStr.replace(/[EeWw]/, r.parts[3].slice(-1));
+ s = s.replace(/Y/, r.lonmin);
+ s = s.replace(/X/, r.londeg);
+ s = s.replace(/[NnSs]/, r.parts[1].slice(-1));
+ s = s.replace(/B/, r.latmin);
+ s = s.replace(/A/, r.latdeg);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedDMSStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ r.parts = fromValue[0].split(/[ ,]+/);
+
+ r.latdeg = r.parts[0];
+ r.latmin = r.parts[1];
+ r.latsec = r.parts[2].replace(/[NnSs]/, '');
+
+
+ r.londeg = r.parts[3];
+ r.lonmin = r.parts[4];
+ r.lonsec = r.parts[5].replace(/[EWew]/, '');
+
+ if (addSignPrefix) {
+ r.parts[2].slice(-1) === 'N'?r.latdeg = '+' + r.latdeg:r.latdeg = '-' + r.latdeg;
+ r.parts[5].slice(-1) ==='W'?r.londeg = '-' + r.londeg:r.londeg = '+' + r.londeg;
+ }
+
+ //A° B' C''N X° Y' Z''E
+ var s = withFormatStr.replace(/A/, r.latdeg);
+ s = s.replace(/B/, r.latmin);
+ s = s.replace(/C/, r.latsec);
+ s = s.replace(/X/, r.londeg);
+ s = s.replace(/Y/, r.lonmin);
+ s = s.replace(/Z/, r.lonsec);
+ s = s.replace(/[NnSs]/, r.parts[2].slice(-1));
+ s = s.replace(/[EeWw]/, r.parts[5].slice(-1));
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedUSNGStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ if(fromValue[0].match(/^[ABYZ]/)) {
+ r.gzd = fromValue[0].match(/[ABYZ]/)[0].trim();
+ } else {
+ r.gzd = fromValue[0].match(/\d{1,2}[C-HJ-NP-X]/)[0].trim();
+ }
+ r.grdsq = fromValue[0].replace(r.gzd, '').match(/[a-hJ-zA-HJ-Z]{2}/)[0].trim();
+ r.easting = fromValue[0].replace(r.gzd + r.grdsq, '').match(/^\d{1,5}/)[0].trim();
+ r.northing = fromValue[0].replace(r.gzd + r.grdsq, '').match(/\d{1,5}$/)[0].trim();
+
+ //Z S X# Y#
+ var s = withFormatStr.replace(/Y/, r.northing);
+ s = s.replace(/X/, r.easting);
+ s = s.replace(/S/, r.grdsq);
+ s = s.replace(/Z/, r.gzd);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedMGRSStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ if(fromValue[0].match(/^[ABYZ]/)) {
+ r.gzd = fromValue[0].match(/[ABYZ]/)[0].trim();
+ } else {
+ r.gzd = fromValue[0].match(/\d{1,2}[C-HJ-NP-X]/)[0].trim();
+ }
+ r.grdsq = fromValue[0].replace(r.gzd, '').match(/[a-hJ-zA-HJ-Z]{2}/)[0].trim();
+ r.easting = fromValue[0].replace(r.gzd + r.grdsq, '').match(/^\d{1,5}/)[0].trim();
+ r.northing = fromValue[0].replace(r.gzd + r.grdsq, '').match(/\d{1,5}$/)[0].trim();
+
+ //Z S X# Y#
+ var s = withFormatStr.replace(/Y/, r.northing);
+ s = s.replace(/X/, r.easting);
+ s = s.replace(/S/, r.grdsq);
+ s = s.replace(/Z/, r.gzd);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedGARSStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ r.lon = fromValue[0].match(/\d{3}/);
+ r.lat = fromValue[0].match(/[a-zA-Z]{2}/);
+
+ var q = fromValue[0].match(/\d*$/);
+ r.quadrant = q[0][0];
+ r.key = q[0][1];
+
+ //XYQK
+ var s = withFormatStr.replace(/K/, r.key);
+ s = s.replace(/Q/, r.quadrant);
+ s = s.replace(/Y/, r.lat);
+ s = s.replace(/X/, r.lon);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedGEOREFStr: function (fromValue, withFormatStr, addSignPrefix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ r.lon = fromValue[0].match(/[a-zA-Z]{1}/)[0].trim();
+ r.lat = fromValue[0].replace(r.lon, '').match(/[a-zA-Z]{1}/)[0].trim();
+ r.quadrant15lon = fromValue[0].replace(r.lon + r.lat, '').match(/[a-zA-Z]{1}/)[0].trim();
+ r.quadrant15lat = fromValue[0].replace(r.lon + r.lat + r.quadrant15lon, '').match(/[a-zA-Z]{1}/)[0].trim();
+
+ var q = fromValue[0].replace(r.lon + r.lat + r.quadrant15lon + r.quadrant15lat, '');
+
+ r.quadrant1lon = q.substr(0,q.length/2);
+ r.quadrant1lat = q.substr(q.length/2, q.length);
+
+ //ABCDXY
+ var s = withFormatStr.replace(/Y/, r.quadrant1lat);
+ s = s.replace(/X/, r.quadrant1lon);
+ s = s.replace(/D/, r.quadrant15lat);
+ s = s.replace(/C/, r.quadrant15lon);
+ s = s.replace(/B/, r.lat);
+ s = s.replace(/A/, r.lon);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedUTMStr: function (fromValue, withFormatStr, addSignPrefix, addDirSuffix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ r.parts = fromValue[0].split(/[ ,]+/);
+ r.zone = r.parts[0].replace(/[A-Z]/,'');
+ r.bandLetter = r.parts[0].slice(-1);
+ r.easting = r.parts[1];
+ r.westing = r.parts[2];
+
+ //ZB Xm Ym'
+ var s = withFormatStr.replace(/Y/, r.westing);
+ s = s.replace(/X/, r.easting);
+ s = s.replace (/B/, r.bandLetter);
+ s = s.replace(/Z/, r.zone);
+
+ r.formatResult = s;
+ return r;
+ },
+
+ /**
+ *
+ **/
+ getFormattedUTMHStr: function (fromValue, withFormatStr, addSignPrefix, addDirSuffix) {
+ var r = {};
+ r.sourceValue = fromValue;
+ r.sourceFormatString = withFormatStr;
+
+ r.parts = fromValue[0].split(/[ ,]+/);
+ r.zone = r.parts[0].replace(/[A-Z]/,'');
+ r.hemisphere = r.parts[0].slice(-1);
+
+ r.easting = r.parts[1];
+ r.westing = r.parts[2];
+
+ //ZH Xm Ym'
+ var s = withFormatStr.replace(/Y/, r.westing);
+ s = s.replace(/X/, r.easting);
+ s = s.replace (/H/, r.hemisphere);
+ s = s.replace(/Z/, r.zone);
+
+ r.formatResult = s;
+ return r;
+ },
+
+
+ /**
+ *
+ **/
+ convertMetersToUnits: function (inMeters, fromUnit) {
+ var convLength = 0;
+ switch (fromUnit.toLowerCase()) {
+ case 'meters':
+ convLength = inMeters;
+ break;
+ case 'feet':
+ convLength = inMeters * 3.28084;
+ break;
+ case 'kilometers':
+ convLength = inMeters * 0.001;
+ break;
+ case 'miles':
+ convLength = inMeters * 0.000621371;
+ break;
+ case 'nautical-miles':
+ convLength = inMeters * 0.000539957;
+ break;
+ case 'yards':
+ convLength = inMeters * 1.09361;
+ break;
+ }
+ return convLength;
+ },
+
+ /**
+ *
+ **/
+ convertToMeters: function (length, inputUnit) {
+ var convertedLength = length;
+ switch (inputUnit) {
+ case 'meters':
+ convertedLength = length;
+ break;
+ case 'feet':
+ convertedLength = length * 0.3048;
+ break;
+ case 'kilometers':
+ convertedLength = length * 1000;
+ break;
+ case 'miles':
+ convertedLength = length * 1609.34;
+ break;
+ case 'nautical-miles':
+ convertedLength = length * 1852.001376036;
+ break;
+ case 'yards':
+ convertedLength = length * 0.9144;
+ break;
+ }
+ return convertedLength;
+ }
+ });
+});
diff --git a/GRG/license.txt b/GRG/license.txt
new file mode 100644
index 0000000..dae5137
--- /dev/null
+++ b/GRG/license.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2016 Esri Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/GRG/manifest.json b/GRG/manifest.json
new file mode 100644
index 0000000..65965ae
--- /dev/null
+++ b/GRG/manifest.json
@@ -0,0 +1,19 @@
+{
+ "name": "GRG",
+ "platform": "HTML",
+ "version": "2.5",
+ "wabVersion": "2.5",
+ "author": "Esri",
+ "description": "Grided Reference Graphic Widget",
+ "copyright": "",
+ "license": "http://www.apache.org/licenses/LICENSE-2.0",
+ "properties": {
+ "keepConfigAfterMapSwithched": true,
+ "supportMultiInstance": false,
+ "hasVersionManager": false,
+ "hasSettingPage": true,
+ "hasSettingUIFile": true,
+ "hasSettingLocale": true,
+ "hasSettingStyle": true
+ }
+}
diff --git a/GRG/nls/strings.js b/GRG/nls/strings.js
new file mode 100644
index 0000000..70e1248
--- /dev/null
+++ b/GRG/nls/strings.js
@@ -0,0 +1,143 @@
+define({
+ root: ({
+ _widgetLabel: "Gridded Reference Graphic", // Label of widget
+
+ //main page
+ "newGRGFromAreaButtonLabel": 'Define a Grid from an Area', // Shown as label to start new GRG from Area button on main page
+ "newGRGFromPointButtonLabel": 'Define a Grid from a Point', // Shown as label to new GRG from point button on main page
+
+ //GRG from Area and Point Menus
+ "newGRGFromAreaTitle": 'Define a Grid from an Area', // Shown as Title on Area Menu
+ "newGRGFromPointTitle": 'Define a Grid from a Point', // Shown as Title on Area Menu
+ "newGRGBySizeButtonLabel": 'By Dimension', // Shown as label to start new GRG by size button on Area Menu or Point Menu
+ "newGRGFromRefSystemButtonLabel": 'By Reference System', // Shown as label to start new from reference system button on Area Menu or Point Menu
+ "newGRGFromNonStandardButtonLabel": 'Define Non-Standard Grid', // Shown as label to start new GRG from non standard button on Area Menu or Point Menu
+
+ //Area GRG By Size Panel
+ "newGRGAreaBySizeTitle": "GRG from an Area by Dimension", // Shown as title for new GRG from area panel
+ "newGRGAreaBySizeDefineAreaLabel": 'GRG Area', // Shown as text for new GRG from area toolbar
+ "addGRGAreaPolygonToolTip": "Draw GRG Area using polygon", // Shown as tooltip on draw rectangle icon
+ "addGRGAreaExtentToolTip": "Draw GRG Area using extent", // Shown as tooltip on draw extent icon
+ "rotation": 'Grid Rotation', // Shown as label above rotation input box
+ "numberRowsColumnsLabel": 'Define number of rows and columns', // Shown as label next to the define rows and columns toggle
+
+ //Area GRG By Reference System Panel
+ "newGRGAreaByRefSystemTitle": 'GRG from an Area by Reference System', // Shown as title for new GRG from reference system panel
+ "gridSize": 'Grid Size', // Shown as title for new GRG from reference system panel
+ "UTMZoneandBand": 'Grid Zone', // Shown as label for UTM Zone and Band in gridSize dropdown
+ "100000m": '100000 meter', // Shown as label for 100000 meter in gridSize dropdown
+ "10000m": '10000 meter', // Shown as label for 10000 meter in gridSize dropdown
+ "1000m": '1000 meter', // Shown as label for 10000 meter in gridSize dropdown
+ "100m": '100 meter', // Shown as label for 100 meter in gridSize dropdown
+ "10m": '10 meter', // Shown as label for 10 meter in gridSize dropdown
+ "clipGrid": 'Clip Grid to GRG Area', // Shown as label for clip grid toggle switch
+
+ //Area GRG from non standard grid Panel
+ "newGRGAreaFromNonStandardTitle": "New NRG", // Shown as title for new GRG from non standard grid Panel
+
+ //Point GRG By Size Panel
+ "newGRGPointBySizeTitle": "GRG from Point by Dimension", // Shown as title for new GRG from point panel
+
+ //Point GRG By Reference System Panel
+ "newGRGPointByRefSystemTitle": "GRG from Point by Reference System", // Shown as title for new GRG from reference system panel
+
+ //Settings Panel
+ "settingsTitle": "Settings", // Shown as Title for Grid Settings page and label on settings buttons
+ "labelSettingsLabel": 'Label Settings', // Shown as Title for Label Settings dropdown
+ "labelSettingsButtonLabel": 'Configure Label Settings', // Shown as tooltip for Label Settings dropdown
+ "gridSettingsLabel": 'Grid Settings', // Shown as Title for Label Settings dropdown
+ "gridSettingsButtonLabel": 'Configure Grid Settings', // Shown as tooltip for Label Settings dropdown
+ "transparency": 'Transparency', // Shown as label on transparency sliders
+ "labelStyle": 'Label Style', // Shown as label on label settings
+ "font": 'Font', // Shown as label for font type
+ "textSize": 'Text Size', // Shown as label for font size
+ "textColor": 'Text Color', // Shown as label for font colour
+ "halo": 'Halo', // Shown as label for halo settings
+ "show": 'Show', // Shown as label for halo settings
+ "lockSettings": 'Settings have been locked by the application owner', // Shown as tooltip on settings button if locked
+
+ "gridSettings": {
+ "cellShape": "Cell Shape", // Shown as label to set Cell Shape Type
+ "cellUnits": "Cell Units", // Shown as label to set Cell Units
+ "cellOutline": 'Cell Outline Settings', // Shown as label to set cell Outline Settings
+ "cellFill": 'Cell Fill Settings', // Shown as label to set cell fill Settings
+ "gridReferenceSystem": 'Reference System', // Shown as label to set Reference System
+ "gridDatum": 'Datum: WGS84', // Shown as label for datum
+ "labelStartPosition": "Label Origin", // Shown as label to set label start position
+ "labelType": "Label Type", // Shown as label to set label type
+ "labelDirection": "Label Direction", // Shown as label to set label direction
+ "gridOrigin": "Grid Origin", // Shown as label to set grid origin
+
+ "default": "Rectangle", // Shown as label for default in cell shape dropdown
+ "hexagon": "Hexagon", // Shown as label for hexagon in cell shape dropdown
+
+ "miles": 'Miles', // Shown as label for miles in cell units dropdown
+ "kilometers": 'Kilometers', // Shown as label for kilometers in cell units dropdown
+ "feet": 'Feet', // Shown as label for feet in cell units dropdown
+ "meters": 'Meters', // Shown as label for meters in cell units dropdown
+ "yards": 'Yards', // Shown as label for yards in cell units dropdown
+ "nautical-miles": 'Nautical Miles', // Shown as label for nauticalMiles in cell units dropdown
+
+ "lowerLeft": 'Lower-Left', // Shown as label for lower left in label start position and grid origin dropdowns
+ "lowerRight": 'Lower-Right', // Shown as label for lower right in label start position and grid origin dropdowns
+ "upperLeft": 'Upper-Left', // Shown as label for upper left in label start position and grid origin dropdowns
+ "upperRight": 'Upper-Right', // Shown as label for upper right in label start position and grid origin dropdowns
+ "center": 'Center', // Shown as label for center in grid origin dropdown
+
+ "alphaNumeric": 'Alpha-Numeric', // Shown as label for Alpha-Numeric in label type dropdown
+ "alphaAlpha": 'Alpha-Alpha', // Shown as label for Alpha-Alpha in label type dropdown
+ "numeric": 'Numeric', // Shown as label for Numeric in label type dropdown
+
+ "horizontal": 'Horizontal', // Shown as label for Horizontal in label direction dropdown
+ "vertical": 'Vertical', // Shown as label for Vertical in label direction dropdown
+
+ "MGRS": 'MGRS', // Shown as label for MGRS in reference system dropdown
+ "USNG": 'USNG', // Shown as label for USNG in reference system dropdown
+
+ "showLabels": 'Show Labels', // Shown as label for show labels toggle switch
+ },
+
+ //Publish Panel
+ "publishTitle": "Publish GRG to Portal", // Shown as Title for Grid Settings page and label on settings buttons
+ "publishGRGBtn": 'Publish', // Shown as label on publish GRG button
+ "GRGLayerName": 'Published GRG Layer Name', // Shown as label for layer name box
+ "invalidGRGLayerName": 'Layer name must only contain alpha-numeric characters and underscores', //Shown as validation error on published layer name
+ "missingGRGLayerName": 'You must enter a name for the GRG', //Shown as validation error on empty published layer name
+
+ //publishing error messages
+ "publishingFailedLayerExists": 'Publishing Failed: You already have a feature service named {0}. Please choose another name.', //Shown as error for layer name already used when publishing {0} will be replaced with the layer name in the code so do not remove
+ "checkService": 'Check Service: {0}', //{0} will be replaced in the code so do not remove
+ "createService": 'Create Service: {0}', //{0} will be replaced in the code so do not remove
+ "unableToCreate": 'Unable to create: {0}', //{0} will be replaced in the code so do not remove
+ "addToDefinition": 'Add to definition: {0}', //{0} will be replaced in the code so do not remove
+ "successfullyPublished": 'Successfully published web layer{0}Manage the web layer', //{0} will be replaced in the code so do not remove
+
+ //common
+ "createGRGBtn": 'Create GRG', // Shown as label on create button
+ "clearGRGBtn": 'Clear', // Shown as label on clear button
+ "labelFormat": 'Label Format', // Shown as label above label format input box
+ "helpIconTooltip": 'Z: Grid Zone Designator (GZD)\nS: 100,000-meter Grid Square Identification (GSID)\nX: Easting (X Coordinate)\nY: Northing (Y Coordinate)\n\nExamples:\nZSXY is 15SWC8081751205\nZS X,Y is 15SWC 80817,51205', // Shown as label above label format input box
+ "addPointToolTip": 'Add GRG Origin', // Show as tooltip help on the draw point icon
+ "cellWidth": 'Cell Width (x)', // Shown as label above cell width input
+ "cellHeight": 'Cell Height (y)', // Shown as label above cell height input
+ "invalidNumberMessage": 'The value entered is not valid', //Shown as validation error on invalid entries
+ "invalidRangeMessage": 'Value must be greater than 0', //Shown as validation error on invalid entries
+ "gridAngleInvalidRangeMessage": 'Value must be between -89.9 and 89.9', //Shown as validation error for the angle input
+ "formatIconTooltip": 'Format Input', // Shown as tooltip on the format input coordinate button
+ "coordInputLabel": 'GRG Origin (DD)', // Shown as label for coordinate input box (DD) denotes that decimal degrees is set as the default
+ "setCoordFormat": 'Set Coordinate Format String', // Shown as label for set format string
+ "prefixNumbers": 'Add "+/-" prefix to positive and negative numbers', // Shown as text next to the add prefix check box
+ "cancelBtn": 'Cancel', // Shown as label on cancel button
+ "applyBtn": 'Apply', // Shown as label on apply button
+ "comfirmInputNotation": 'Confirm Input Notation', //Shown as panel title when more than one notation match
+ "notationsMatch": 'notations match your input please confirm which you would like to use:', // Shown as message when more than one notation match
+ "numberOfCellsHorizontal": '# Horizontal Cells', // Shown as label for number of Horizontal cells
+ "numberOfCellsVertical": '# Vertical Cells', // Shown as label for number of Vertical cells
+ "gridAngle": 'Grid Rotation', // Shown as label for grid angle
+ "missingParametersMessage": 'The GRG creation form has missing or invalid parameters, Please ensure:
A GRG area has been drawn. The cell width and height contain valid values. ',
+ "drawPointToolTip": 'Click to add GRG origin point', // Shown as tooltip help on the cursor when using the draw point tool
+ "missingLayerNameMessage": 'You must enter a valid layer name before you can publish', //shown as error message for invalid layer name
+ "parseCoordinatesError": 'Unable to parse coordinates. Please check your input.' //Shown as error message for unknown coordinates
+
+ })
+});
diff --git a/GRG/setting/ColorPickerEditor.html b/GRG/setting/ColorPickerEditor.html
new file mode 100644
index 0000000..33aaab2
--- /dev/null
+++ b/GRG/setting/ColorPickerEditor.html
@@ -0,0 +1,9 @@
+
+
+
${nls.transparency}
+
+
+
%
+
+
diff --git a/GRG/setting/ColorPickerEditor.js b/GRG/setting/ColorPickerEditor.js
new file mode 100644
index 0000000..2cf575d
--- /dev/null
+++ b/GRG/setting/ColorPickerEditor.js
@@ -0,0 +1,113 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ "dojo/_base/lang",
+ 'dojo/_base/Color',
+ 'dojo/on',
+ "dojo/query",
+ "dojo/_base/html",
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!./ColorPickerEditor.html',
+ "dijit/form/HorizontalSlider",
+ 'jimu/dijit/ColorPickerPopup',
+ "dijit/form/NumberSpinner"
+ ],
+ function(declare, lang, Color, on, query, html,
+ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template,
+ HorizontalSlider, ColorPicker) {
+ return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
+ _defaultColor: '#485566',
+ templateString: template,
+ nls: null,
+
+ postCreate: function() {
+ this.colorPicker = new ColorPicker({
+ color: this._defaultColor
+ }, this.colorPicker);
+ this.colorPicker.startup();
+
+ this.slider = new HorizontalSlider({
+ name: "slider",
+ value: 0,
+ minimum: 0,
+ maximum: 100,
+ discreteValues: 101,
+ intermediateChanges: true,
+ showButtons: false,
+ style: "width:140px;display: inline-block;"
+ }, this.sliderBar);
+ this.slider.startup();
+
+ this.inherited(arguments);
+ },
+ startup: function() {
+ this.own(on(this.slider, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.spinner.setValue(val);
+ }
+ })));
+
+ this.own(on(this.spinner, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.slider.setValue(val);
+ }
+ })));
+
+ this._stylePolyfill();
+ this.inherited(arguments);
+ },
+ _isSameVal: function() {
+ return this.slider.getValue() === this.spinner.getValue();
+ },
+ getValues: function() {
+ var rgb = null,
+ a = null;
+ var bgColor = this.colorPicker.getColor();
+ if (bgColor && bgColor.toHex) {
+ rgb = bgColor.toHex();
+ }
+ a = this.spinner.getValue() / 100;
+
+ return {
+ color: rgb,
+ transparency: a
+ };
+ },
+ setValues: function(obj) {
+ if (typeof obj === "object" || typeof obj === "string") {
+ this.colorPicker.setColor(new Color(obj.color));
+
+ if (typeof obj.transparency === "undefined") {
+ obj.transparency = 0;
+ } else {
+ obj.transparency = obj.transparency * 100;
+ }
+ this.slider.setValue(obj.transparency);
+ this.spinner.setValue(obj.transparency);
+ }
+ },
+ _stylePolyfill: function() {
+ var leftBumper = query('.dijitSliderLeftBumper', this.domNode)[0];
+ if (leftBumper && leftBumper.parentNode) {
+ html.setStyle(leftBumper.parentNode, 'background-color', "#24b5cc");
+ }
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/setting/FontSetting.html b/GRG/setting/FontSetting.html
new file mode 100644
index 0000000..641fbe6
--- /dev/null
+++ b/GRG/setting/FontSetting.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
${nls.transparency}
+
+
+
+
\ No newline at end of file
diff --git a/GRG/setting/FontSetting.js b/GRG/setting/FontSetting.js
new file mode 100644
index 0000000..6fc6226
--- /dev/null
+++ b/GRG/setting/FontSetting.js
@@ -0,0 +1,386 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ "dojo/_base/lang",
+ 'dojo/on',
+ 'dojo/_base/html',
+ 'dojo/_base/array',
+ 'dojo/Evented',
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!./FontSetting.html',
+ 'jimu/dijit/ColorPickerPopup',
+ "dijit/form/HorizontalSlider",
+ './TransparencyEditor',
+ "dojo/store/Memory",
+ "dijit/form/ComboBox",
+ 'jimu/dijit/CheckBox',
+ 'jimu/dijit/ImageChooser'
+],
+ function (declare, lang, on, html, array,
+ Evented, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template,
+ ColorPickerPopup, HorizontalSlider, TransparencyEditor, Memory) {
+ return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Evented], {
+ templateString: template,
+ nls: null,
+ _FONTS: null,
+ _MIN_TEXT_SIZE: 12,
+ _MAX_TEXT_SIZE: 48,
+ _INTERVAL_TEXT_SIZE: 2,
+
+ _DEFAULT_CONFIG: null,
+
+ postCreate: function () {
+ this.inherited(arguments);
+ this._FONTS = "Arial;Comic Sans MS;Courier New;Garamond;Tahoma;Times New Roman;Verdana".split(";");
+ this._DEFAULT_CONFIG = {
+ font: {
+ fontFamily: this._FONTS[0],//first one
+ bold: false,
+ italic: false,
+ underline: false
+ },
+ fontSize: "24",
+ textColor: "#282828",
+ haloSize: 1,
+ haloColor: "#FFFFFF",
+ haloOn: true,
+ labelTransparency: 1,
+ };
+ this.config = lang.mixin(lang.clone(this._DEFAULT_CONFIG), this.config);
+
+ //font
+ array.forEach(this._FONTS, lang.hitch(this, function (font) {
+ this.fontSelect.addOption({ value: font, label: font });
+ }));
+ //text size
+ var textSizeStore = new Memory({});
+ for (var i = this._MIN_TEXT_SIZE, max = this._MAX_TEXT_SIZE; i < max; i += this._INTERVAL_TEXT_SIZE) {
+ textSizeStore.put({ id: i, name: i });
+ }
+ this.textSizeSelect.store = textSizeStore;
+ this.textSizeSelect.validator = lang.hitch(this, function () {
+ var s = this.textSizeSelect.getValue();
+ if (s !== null && s !== "") {
+ return !isNaN(s);
+ }
+ return false;
+ });
+ this.textSizeSlider = new HorizontalSlider({
+ name: "slider",
+ value: 0,
+ minimum: this._MIN_TEXT_SIZE,
+ maximum: this._MAX_TEXT_SIZE,
+ discreteValues: this.textSizeSelect.store.data.length + 1,
+ intermediateChanges: true,
+ showButtons: false,
+ style: "display: inline-block;"
+ }, this.sliderBar);
+ this.textSizeSlider.startup();
+ //.textColor
+ this.textColorPicker = new ColorPickerPopup({
+ appearance: {
+ showTransparent: false,
+ showColorPalette: true,
+ showCoustom: true,
+ showCoustomRecord: true
+ },
+ recordUID: this.recordUID
+ });
+ this.textColorPicker.placeAt(this.textColorBtn);
+ this.textColorPicker.startup();
+
+ //transparency
+ this.labelTransparency = new TransparencyEditor({}, this.transparencySlider);
+ this.labelTransparency.startup();
+
+
+
+ //halo
+ //halo size
+ var haloSizeStore = new Memory({});
+ for (var i = 1, max = 10; i <= max; i += 1) {
+ haloSizeStore.put({ id: i, name: i });
+ }
+ this.haloSizeSelect.store = haloSizeStore;
+ this.haloSizeSelect.validator = lang.hitch(this, function () {
+ var s = this.haloSizeSelect.getValue();
+ if (s !== null && s !== "") {
+ return !isNaN(s);
+ }
+ return false;
+ });
+
+
+ //halo color picker
+ this.haloColorPicker = new ColorPickerPopup({
+ appearance: {
+ showTransparent: false,
+ showColorPalette: true,
+ showCoustom: true,
+ showCoustomRecord: true
+ },
+ });
+ this.haloColorPicker.placeAt(this.haloColorBtn);
+ this.haloColorPicker.startup();
+
+ //font
+ this.own(on(this.fontSelect, 'change', lang.hitch(this, function (value) {
+ if(this.config.font.fontFamily === value){
+ return;
+ }
+ this.onSettingChange({
+ font: {
+ fontFamily: value,
+ bold: this.config.font.bold,
+ italic: this.config.font.italic,
+ underline: this.config.font.underline
+ }
+ });
+ })));
+ this._initAppearance();
+ this.own(on(this.bold, 'click', lang.hitch(this, function (/*value*/) {
+ var isClick = !html.hasClass(this.bold, "selected");
+ this.fontBtnClickd({ bold: isClick });
+ this.onSettingChange({
+ font: {
+ fontFamily: this.config.font.fontFamily,
+ bold: isClick,
+ italic: this.config.font.italic,
+ underline: this.config.font.underline
+ }
+ });
+ })));
+ this.own(on(this.italic, 'click', lang.hitch(this, function (/*value*/) {
+ var isClick = !html.hasClass(this.italic, "selected");
+ this.fontBtnClickd({ italic: isClick });
+ this.onSettingChange({
+ font: {
+ fontFamily: this.config.font.fontFamily,
+ bold: this.config.font.bold,
+ italic: isClick,
+ underline: this.config.font.underline
+ }
+ });
+ })));
+ this.own(on(this.underline, 'click', lang.hitch(this, function (/*value*/) {
+ var isClick = !html.hasClass(this.underline, "selected");
+ this.fontBtnClickd({ underline: isClick });
+ this.onSettingChange({
+ font: {
+ fontFamily: this.config.font.fontFamily,
+ bold: this.config.font.bold,
+ italic: this.config.font.italic,
+ underline: isClick
+ }
+ });
+ })));
+ //text size
+ this.own(on(this.textSizeSelect, 'change', lang.hitch(this, function (value) {
+ if(this.config.fontSize === value || false === this.textSizeSelect.isValid()){
+ return;
+ }
+ this.setTextSize(value);
+ this.onSettingChange({
+ fontSize: value
+ });
+ })));
+ this.own(on(this.textSizeSlider, 'change', lang.hitch(this, function (value) {
+ if(this.config.fontSize === value){
+ return;
+ }
+ this.setTextSize(value);
+ this.onSettingChange({
+ fontSize: value
+ });
+ })));
+ //.textColor
+ this.own(on(this.textColorPicker, 'change', lang.hitch(this, function (color) {
+ if(this.config.textColor === color){
+ return;
+ }
+ this.onSettingChange({
+ textColor: color.toHex()
+ });
+ })));
+ //transparency slider
+ this.own(this.labelTransparency.watch('transparency', lang.hitch(this, function () {
+ this.onSettingChange({
+ labelTransparency: this.labelTransparency.getValues().transparency
+ });
+ })));
+ //halo size
+ this.own(on(this.haloSizeSelect, 'change', lang.hitch(this, function (value) {
+ if(this.config.haloSize === value || false === this.haloSizeSelect.isValid()){
+ return;
+ }
+ this.onSettingChange({
+ haloSize: value
+ });
+ })));
+ //.haloColor
+ this.own(on(this.haloColorPicker, 'change', lang.hitch(this, function (color) {
+ if(this.config.haloColor === color){
+ return;
+ }
+ this.onSettingChange({
+ haloColor: color.toHex()
+ });
+ })));
+ //halo toggle switch
+ this.own(on(this.showHalo, 'change', lang.hitch(this, function () {
+ this.onSettingChange({
+ haloOn: this.showHalo.checked
+ });
+ })));
+ },
+ startup: function () {
+ this.inherited(arguments);
+ this.setConfig(this.config);
+ this.refresh();
+ },
+
+ onSettingChange: function (configObj) {
+ this.config = lang.mixin(this.config, configObj);
+ this.onChange(this.config);
+ },
+ onChange: function (config) {
+ this.emit("change", config);
+ },
+ refresh: function () {
+ this.onSettingChange({});
+ },
+ isValid: function () {
+ if (false === this.textSizeSelect.isValid()) {
+ return false;
+ }
+
+ return true;
+ },
+ getConfig: function () {
+ if (this.isValid()) {
+ return this.config;
+ } else {
+ return false;
+ }
+ },
+
+ setConfig: function (configObj) {
+ if ("undefined" === configObj) {
+ return;
+ }
+
+ if ("undefined" !== typeof configObj.font) {
+ this.config.font = configObj.font;
+ if (this.config.font.fontFamily) {
+ this.fontSelect.set('value', this.config.font.fontFamily);
+ }
+ this.fontBtnClickd(this.config.font);
+ }
+ if ("undefined" !== typeof configObj.fontSize) {
+ this.config.fontSize = configObj.fontSize;
+ this.setTextSize(this.config.fontSize);
+ }
+ if ("undefined" === typeof configObj.textColor || "" === configObj.textColor) {
+ configObj.textColor = this._DEFAULT_CONFIG.textColor;//"#000001";
+ }
+ this.config.textColor = configObj.textColor;
+
+ if ("undefined" === typeof configObj.labelTransparency || "" === configObj.labelTransparency) {
+ configObj.labelTransparency = this._DEFAULT_CONFIG.labelTransparency;//"1";
+ }
+ this.config.labelTransparency = configObj.labelTransparency;
+ this.labelTransparency.setValues({"transparency": this.config.labelTransparency});
+
+ if ("undefined" === typeof configObj.haloSize || "" === configObj.haloSize) {
+ configObj.haloSize = this._DEFAULT_CONFIG.haloSize;//"1";
+
+ }
+ this.config.haloSize = configObj.haloSize;
+ this.haloSizeSelect.set('value', configObj.haloSize);
+
+ if ("undefined" === typeof configObj.haloColor || "" === configObj.haloColor) {
+ configObj.haloColor = this._DEFAULT_CONFIG.haloColor;//"#FFFFFF";
+ }
+ this.config.haloColor = configObj.haloColor;
+
+ html.setStyle(this.textColorPicker.domNode, 'backgroundColor', this.config.textColor);
+ this.textColorPicker.picker.refreshRecords();
+ this.textColorPicker.picker.setColor(this.config.textColor, false, true);
+
+ html.setStyle(this.haloColorPicker.domNode, 'backgroundColor', this.config.haloColor);
+ this.haloColorPicker.picker.refreshRecords();
+ this.haloColorPicker.picker.setColor(this.config.haloColor, false, true);
+
+ if ("undefined" === typeof configObj.haloOn || "" === configObj.haloOn) {
+ configObj.haloOn = this._DEFAULT_CONFIG.haloOn;//"#FFFFFF";
+ }
+ this.showHalo.set("checked",this.config.haloOn);
+ },
+
+ setTextSize: function (size) {
+ if (size !== this.textSizeSelect.getValue()) {
+ this.textSizeSelect.set('value', size);
+ }
+
+ if (size !== this.textSizeSlider.getValue()) {
+ if (size > this._MAX_TEXT_SIZE) {
+ size = this._MAX_TEXT_SIZE;
+ } else if (size < this._MIN_TEXT_SIZE) {
+ size = this._MIN_TEXT_SIZE;
+ }
+ this.textSizeSlider.set('value', size);
+ }
+ },
+
+ fontBtnClickd: function (fontConfig) {
+ if (true === fontConfig.bold) {
+ html.addClass(this.bold, "selected");
+ } else if (false === fontConfig.bold) {
+ html.removeClass(this.bold, "selected");
+ }
+
+ if (true === fontConfig.italic) {
+ html.addClass(this.italic, "selected");
+ } else if (false === fontConfig.italic) {
+ html.removeClass(this.italic, "selected");
+ }
+
+ if (true === fontConfig.underline) {
+ html.addClass(this.underline, "selected");
+ } else if (false === fontConfig.underline) {
+ html.removeClass(this.underline, "selected");
+ }
+ },
+
+ _initAppearance: function () {
+ if (this.appearance) {
+ if (false === this.appearance.bold) {
+ html.addClass(this.bold, "hide");
+ }
+ if (false === this.appearance.italic) {
+ html.addClass(this.italic, "hide");
+ }
+ if (false === this.appearance.underline) {
+ html.addClass(this.underline, "hide");
+ }
+ }
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/setting/Setting.html b/GRG/setting/Setting.html
new file mode 100644
index 0000000..7ed01b6
--- /dev/null
+++ b/GRG/setting/Setting.html
@@ -0,0 +1,100 @@
+
+
+
+ ${nls.lockSettings}
+
+
+
+
+
${nls.gridTabDescription}
+
+
+
${nls.cellOutlineColor}
+
+
+
+
+
${nls.cellFillColor}
+
+
+
+
+
${nls.cellShapeDropDown}
+
+ ${nls.default}
+ ${nls.hexagon}
+
+
+
+
+
${nls.cellUnitsDropDown}
+
+ ${nls.meters}
+ ${nls.kilometers}
+ ${nls.miles}
+ ${nls.nautical-miles}
+ ${nls.yards}
+ ${nls.feet}
+
+
+
+
+
${nls.gridOriginDropDown}
+
+ ${nls.center}
+ ${nls.lowerLeft}
+ ${nls.lowerRight}
+ ${nls.upperLeft}
+ ${nls.upperRight}
+
+
+
+
+
+
${nls.labelTabDescription}
+
+
+
${nls.labelSettings}
+
+
+
+
+
${nls.labelTypeDropDown}
+
+ ${nls.alphaNumeric}
+ ${nls.alphaAlpha}
+ ${nls.numeric}
+
+
+
+
+
${nls.labelDirectionDropDown}
+
+ ${nls.horizontal}
+ ${nls.vertical}
+
+
+
+
+
${nls.labelOriginDropDown}
+
+ ${nls.lowerLeft}
+ ${nls.lowerRight}
+ ${nls.upperLeft}
+ ${nls.upperRight}
+
+
+
+
+
+
${nls.referenceSystemlTabDescription}
+
+
+
+ ${nls.MGRS}
+ ${nls.USNG}
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/setting/Setting.js b/GRG/setting/Setting.js
new file mode 100644
index 0000000..768ed71
--- /dev/null
+++ b/GRG/setting/Setting.js
@@ -0,0 +1,181 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ "dojo/_base/lang",
+ 'dojo/_base/html',
+ 'dojo/on',
+ './ColorPickerEditor',
+ './FontSetting',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'jimu/utils',
+ 'jimu/BaseWidgetSetting',
+ "jimu/dijit/CheckBox",
+ 'jimu/dijit/TabContainer',
+ 'jimu/dijit/LoadingShelter'
+ ],
+ function(declare, lang, html, on, ColorPickerEditor, FontSetting, _WidgetsInTemplateMixin,
+ utils, BaseWidgetSetting, CheckBox, TabContainer, LoadingShelter) {
+ return declare([BaseWidgetSetting, _WidgetsInTemplateMixin], {
+ baseClass: 'jimu-widget-grg-setting',
+ _defaultCellOutlineColor: "#1a299c",
+ _defaultCellFillColor: "#ffffff",
+
+ postMixInProperties: function() {
+ this.nls = lang.mixin(this.nls, window.jimuNls.common);
+ },
+ postCreate: function() {
+ //LoadingShelter
+ this.shelter = new LoadingShelter({
+ hidden: true
+ });
+ this.shelter.placeAt(this.domNode);
+ this.shelter.startup();
+
+ this.tab = new TabContainer({
+ tabs: [{
+ title: this.nls.gridTabLabel,
+ content: this.gridTab
+ }, {
+ title: this.nls.labelTabLabel,
+ content: this.labelTab
+ }, {
+ title: this.nls.referenceSystemTabLabel,
+ content: this.referenceSystemTab
+ }],
+ selected: this.nls.gridTabLabel
+ });
+ this.tab.placeAt(this.tabsContainer);
+ this.tab.startup();
+ this.inherited(arguments);
+
+ //Handle change event of draw extent icon
+ this.own(on(this.cellShapeDropDown, 'change', lang.hitch(this, function () {
+ if(this.cellShapeDropDown.get('value') == 'hexagon') {
+ this.labelDirectionDropDown.set('disabled',true);
+ this.labelDirectionDropDown.setValue('horizontal');
+ } else {
+ this.labelDirectionDropDown.set('disabled',false);
+ }
+ })));
+ },
+
+ initGridTab: function() {
+ this.cellOutlineColorPicker = new ColorPickerEditor({nls: this.nls}, this.cellOutlineColorPickerEditor);
+ this.cellOutlineColorPicker.startup();
+
+ this.cellFillColorPicker = new ColorPickerEditor({nls: this.nls}, this.cellFillColorPickerEditor);
+ this.cellFillColorPicker.startup();
+ },
+
+ initLabelTab: function() {
+ this.fontSetting = new FontSetting({config: this.config.grg.font, nls: this.nls}, this.fontSettingNode);
+ this.fontSetting.startup();
+ },
+
+ initReferenceSystemTab: function() {
+
+ },
+
+ startup: function() {
+ this.inherited(arguments);
+ this.shelter.show();
+ if (!this.config.grg) {
+ this.config.grg = {};
+ }
+ this.initGridTab();
+ this.initLabelTab();
+ this.initReferenceSystemTab();
+ this.setConfig(this.config);
+ },
+
+ setConfig: function(config) {
+
+ this.config = config;
+
+ this.cellOutlineColorPicker.setValues({
+ "color": config.grg.cellOutline.color,
+ "transparency": config.grg.cellOutline.transparency
+ });
+
+ this.cellFillColorPicker.setValues({
+ "color": config.grg.cellFill.color,
+ "transparency": config.grg.cellFill.transparency
+ });
+
+ this.cellShapeDropDown.setValue(this.config.grg.cellShape);
+
+ this.cellUnitsDropDown.setValue(this.config.grg.cellUnits);
+
+ this.gridOriginDropDown.setValue(this.config.grg.gridOrigin);
+
+ this.fontSetting.config = this.config.grg.font;
+
+ this.labelTypeDropDown.setValue(this.config.grg.labelType);
+
+ this.labelDirectionDropDown.setValue(this.config.grg.labelDirection);
+
+ this.labelOriginDropDown.setValue(this.config.grg.labelOrigin);
+
+ this.referenceSystemDropDown.setValue(this.config.grg.referenceSystem);
+
+ this.lockSettings.set("checked",this.config.grg.lockSettings);
+
+ this.shelter.hide();
+ },
+
+ getConfig: function() {
+
+ var cellOutlineColor = this.cellOutlineColorPicker.getValues();
+ if (cellOutlineColor) {
+ this.config.grg.cellOutline.color = cellOutlineColor.color;
+ this.config.grg.cellOutline.transparency = cellOutlineColor.transparency;
+ }
+
+ var cellFillColor = this.cellFillColorPicker.getValues();
+ if (cellFillColor) {
+ this.config.grg.cellFill.color = cellFillColor.color;
+ this.config.grg.cellFill.transparency = cellFillColor.transparency;
+ }
+
+ this.config.grg.cellShape = this.cellShapeDropDown.getValue();
+
+ this.config.grg.cellUnits = this.cellUnitsDropDown.getValue();
+
+ this.config.grg.gridOrigin = this.gridOriginDropDown.getValue();
+
+ this.config.grg.font = this.fontSetting.config;
+
+ this.config.grg.labelType = this.labelTypeDropDown.getValue();
+
+ this.config.grg.labelDirection = this.labelDirectionDropDown.getValue();
+
+ this.config.grg.labelOrigin = this.labelOriginDropDown.getValue();
+
+ this.config.grg.referenceSystem = this.referenceSystemDropDown.getValue();
+
+ this.config.grg.lockSettings = this.lockSettings.checked;
+
+ return this.config;
+ },
+
+ destroy: function(){
+ this.inherited(arguments);
+ }
+
+ });
+ });
\ No newline at end of file
diff --git a/GRG/setting/TransparencyEditor.html b/GRG/setting/TransparencyEditor.html
new file mode 100644
index 0000000..9ef4677
--- /dev/null
+++ b/GRG/setting/TransparencyEditor.html
@@ -0,0 +1,7 @@
+
+
diff --git a/GRG/setting/TransparencyEditor.js b/GRG/setting/TransparencyEditor.js
new file mode 100644
index 0000000..1883738
--- /dev/null
+++ b/GRG/setting/TransparencyEditor.js
@@ -0,0 +1,99 @@
+///////////////////////////////////////////////////////////////////////////
+// Copyright © 2014 - 2017 Esri. All Rights Reserved.
+//
+// Licensed under the Apache License Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+///////////////////////////////////////////////////////////////////////////
+
+define([
+ 'dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/_base/Color',
+ 'dojo/on',
+ 'dojo/query',
+ 'dojo/Stateful',
+ 'dojo/_base/html',
+ 'dijit/_WidgetBase',
+ 'dijit/_TemplatedMixin',
+ 'dijit/_WidgetsInTemplateMixin',
+ 'dojo/text!./TransparencyEditor.html',
+ 'dijit/form/HorizontalSlider',
+ "dijit/form/NumberSpinner"
+ ],
+ function(declare, lang, Color, on, query, dojoStateful, html,
+ _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, template,
+ HorizontalSlider) {
+ return declare([dojoStateful, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
+ templateString: template,
+ transparency: 1,
+
+ postCreate: function() {
+ this.slider = new HorizontalSlider({
+ name: "slider",
+ value: 0,
+ minimum: 0,
+ maximum: 100,
+ discreteValues: 101,
+ intermediateChanges: true,
+ showButtons: false,
+ style: "width:140px;display: inline-block;"
+ }, this.sliderBar);
+ this.slider.startup();
+ this.inherited(arguments);
+ },
+ startup: function() {
+ this.own(on(this.slider, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.spinner.setValue(val);
+ this._set("transparency", val/100);
+ }
+ })));
+
+ this.own(on(this.spinner, 'change', lang.hitch(this, function(val) {
+ if (false === this._isSameVal()) {
+ this.slider.setValue(val);
+ this._set("transparency", val/100);
+ }
+ })));
+
+ this._stylePolyfill();
+ this.inherited(arguments);
+ },
+ _isSameVal: function() {
+ return this.slider.getValue() === this.spinner.getValue();
+ },
+ getValues: function() {
+ var a = null;
+ a = this.spinner.getValue() / 100;
+ return {
+ transparency: a
+ };
+ },
+ setValues: function(obj) {
+ if (typeof obj === "object" || typeof obj === "string") {
+ if (typeof obj.transparency === "undefined") {
+ obj.transparency = 0;
+ } else {
+ obj.transparency = obj.transparency * 100;
+ }
+ this.slider.setValue(obj.transparency);
+ this.spinner.setValue(obj.transparency);
+ }
+ },
+ _stylePolyfill: function() {
+ var leftBumper = query('.dijitSliderLeftBumper', this.domNode)[0];
+ if (leftBumper && leftBumper.parentNode) {
+ html.setStyle(leftBumper.parentNode, 'background-color', "#24b5cc");
+ }
+ }
+ });
+ });
\ No newline at end of file
diff --git a/GRG/setting/css/style.css b/GRG/setting/css/style.css
new file mode 100644
index 0000000..d780a6f
--- /dev/null
+++ b/GRG/setting/css/style.css
@@ -0,0 +1,739 @@
+.jimu-widget-grg-setting{
+ margin:0;
+ padding:0;
+ font-size:14px;
+ position: absolute;
+ overflow-y: hidden;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ letter-spacing: 0.38px;
+}
+
+.jimu-widget-grg-setting .instruction {
+ margin-bottom: 10px;
+}
+
+.jimu-widget-grg-setting .tabs {
+ font-family: "Avenir Light";
+ color: #000000;
+ height: 100%;
+}
+
+.jimu-widget-grg-setting .tabs .tab-description {
+ margin: 10px 0;
+}
+
+.jimu-widget-grg-setting .tabs .jimu-radio-checked .jimu-radio-inner {
+ width: 6px;
+ height: 6px;
+ margin: 4px;
+ border-radius: 50%;
+ background-color: #24B5CC;
+}
+
+.jimu-widget-grg-setting .tabs .jimu-radio{
+ border: 1px solid #ccc;
+ vertical-align: top;
+}
+
+.jimu-widget-grg-setting .jimu-tab>.control>.tab{
+ background-color: #fff;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #dedede;
+ color:#898989;
+ font-family: "Avenir Medium";
+ font-size: 14px;
+ /*letter-spacing: 0.38px;*/
+}
+.jimu-widget-grg-setting .jimu-tab>.control>.tab.jimu-state-selected {
+ border-bottom: 3px solid #24b5cc;
+ font-family: "Avenir Heavy";
+ color: #000000;
+}
+
+
+.jimu-widget-grg-setting .tabs .titles {
+ font-weight: bold;
+ font-family: "Avenir Medium";
+ font-size: 12px;
+ /*color: #000000;
+ letter-spacing: 0.38px;*/
+ margin: 20px 0 10px 0;
+}
+.jimu-widget-grg-setting .tabs .hide{
+ display: none;
+}
+/*.jimu-widget-grg-setting .dijitTextBox .dijitInputField {
+ padding: 1px 14px 1px 10px;
+}*/
+.jimu-widget-grg-setting .tabs .indent{
+ margin-left: 20px;
+ margin-top: 10px;
+}
+
+.jimu-widget-grg-setting .tabs .unit-item{
+ margin: 15px 5px 5px 5px;
+ line-height: 18px;
+ height: 18px;
+ vertical-align: middle;
+}
+
+.jimu-widget-grg-setting .tabs .jimu-widget-grg-settingearFix {
+ *overflow: hidden;
+ *zoom: 1;
+}
+
+.jimu-widget-grg-setting .tabs .jimu-widget-grg-settingearFix:after {
+ display: table;
+ content: "";
+ width: 0;
+ clear: both;
+}
+.jimu-widget-grg-setting .tabs .view{
+ height: 100%;
+ overflow-y: auto;
+}
+.jimu-widget-grg-setting .tabs .jimu-tab>.jimu-viewstack{
+/* min-height: 100000px;
+ overflow-y: auto;*/
+ padding-bottom: 30px;
+}
+
+/*.colorPickerEditor*/
+.jimu-widget-grg-setting .tabs .colorPickerEditor {
+ /*display: inline-block;
+ width: 25px;
+ height: 25px;*/
+}
+.jimu-widget-grg-setting .tabs .colorPickerEditor .jimu-color-picker{
+ display: inline-block;
+ width: 30px;
+ height: 30px;
+}
+.jimu-widget-grg-setting .tabs .colorPickerEditor .dijitSpinner.dijitNumberTextBox.dijitValidationTextBox{
+ width:66px;
+ height:30px;
+}
+
+.jimu-widget-grg-setting .dijitSliderImageHandleH{
+ top: -7px;
+}
+.jimu-widget-grg-setting .dijitSliderImageHandle.dijitSliderImageHandleH{
+ background-image: url("../../images/sliderball.png");
+ background-position: 0 0;
+}
+.jimu-widget-grg-setting .tabs .dijitSliderThumbHover{
+ background-image: url("../../images/sliderball_hover.png");
+ background-position: 0 0;
+}
+/*left*/
+.jimu-widget-grg-setting .dijitSlider .dijitSliderProgressBarH,
+.jimu-widget-grg-setting .dijitSlider .dijitSliderLeftBumper{
+ border-color: #24b5cc;
+ background-color: #24b5cc;
+ background-image: -webkit-linear-gradient(top, #24b5cc 0px, #24b5cc 1px, rgba(255, 255, 255, 0) 2px);
+ background-image: -o-linear-gradient(top, #24b5cc 0px, #24b5cc 1px, rgba(255, 255, 255, 0) 2px);
+ background-image: linear-gradient(top, #24b5cc 0px, #24b5cc 1px, rgba(255, 255, 255, 0) 2px);
+}
+.jimu-widget-grg-setting .dijitSlider .dijitSliderRemainingBarH,
+.jimu-widget-grg-setting .dijitSlider .dijitSliderRightBumper{
+ border-color: #d7d7d7;
+ background-color: #d7d7d7;
+}
+
+
+.jimu-widget-grg-setting .tabs .colorPickerEditor .trans{
+ font-family: "Avenir Light";
+ font-size: 12px;
+ padding: 0 10px 0 20px;
+ letter-spacing: 0.33px;
+}
+
+.jimu-widget-grg-setting .tabs .sliderbar {
+ width: 80px;
+}
+
+
+/* 1 content */
+.jimu-widget-grg-setting .content-tab{
+
+}
+.jimu-widget-grg-setting .content-tab .editor-container{
+}
+.jimu-widget-grg-setting .content-tab .editor-container .dijitEditorIFrameContainer textarea {
+ resize: none;
+}
+
+/* 2 appearance */
+.jimu-widget-grg-setting .appearance-tab{
+ overflow-y: auto;
+ height: 490px;
+}
+
+.jimu-widget-grg-setting .appearance-tab .size-selector .size-box-container{
+ display: inline-block;
+ text-align: center;
+ margin: 0 10px 0 0;
+ width: 80px;
+ -o-text-overflow: ellipsis;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.jimu-widget-grg-setting .appearance-tab .size-selector .size-box{
+ width:80px;
+ height:60px;
+ background: no-repeat;
+ margin-bottom: 5px;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent25{
+ background: url("../../images/percent25.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent25.selected{
+ background: url("../../images/percent25_selected.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent50{
+ background: url("../../images/percent50.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent50.selected{
+ background: url("../../images/percent50_selected.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent75{
+ background: url("../../images/percent75.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent75.selected{
+ background: url("../../images/percent75_selected.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent100{
+ background: url("../../images/percent100.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .percent100.selected{
+ background: url("../../images/percent100_selected.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .custom{
+ background: url("../../images/custom.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .custom.selected{
+ background: url("../../images/custom_selected.svg") center center no-repeat;;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .custom-label{
+ vertical-align: top;
+ line-height: 20px;
+}
+.jimu-rtl .jimu-widget-grg-setting .appearance-tab .sizes>:first-child{
+ margin-right: 0;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .wh{
+ margin: 0 14px;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .wh .wh-item{
+ display: inline-block;
+ margin-right: 10px;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .wh .wh-item .lable{
+ font-family: "Avenir Medium";
+ font-size: 12px;
+ color: #353535;
+ /*letter-spacing: 0.33px;*/
+ margin:0 0 5px 0;
+ width: 96px;
+ -o-text-overflow: ellipsis;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .wh .inputs{
+ width:96px;
+ border: 1px solid #d9dde0;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .wh .inputs .text-box{
+ width: 70px;
+ border: none;
+}
+.jimu-widget-grg-setting .appearance-tab .size-selector .wh .inputs .unit{
+ color: #898989;
+ letter-spacing: 0;
+}
+
+/* alignment */
+.jimu-widget-grg-setting .appearance-tab .align-selector .align-box-container{
+ display: inline-block;
+ text-align: center;
+ margin: 0 10px;
+ width:50px;
+ -o-text-overflow: ellipsis;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.jimu-widget-grg-setting .appearance-tab .align-selector .align-box{
+ width:40px;
+ height:36px;
+ background: no-repeat;
+ margin: 0 5px 5px 5px;
+}
+.jimu-widget-grg-setting .appearance-tab .align-selector .top{
+ background: url("../../images/top.svg") center center no-repeat;
+ border: none;
+}
+.jimu-widget-grg-setting .appearance-tab .align-selector .top.selected{
+ background: url("../../images/top_selected.svg") center center no-repeat;
+ border: 1px #24B5CC solid;
+}
+.jimu-widget-grg-setting .appearance-tab .align-selector .middle{
+ background: url("../../images/middle.svg") center center no-repeat;
+ border: none;
+}
+.jimu-widget-grg-setting .appearance-tab .align-selector .middle.selected{
+ background: url("../../images/middle_selected.svg") center center no-repeat;
+ border: 1px #24B5CC solid;
+}
+
+
+.jimu-widget-grg-setting .appearance-tab .jimu-image-chooser{
+ height:30px;
+ width:124px;
+ background: #24B5CC;
+ border: 1px solid #24B5CC;
+}
+.jimu-widget-grg-setting .appearance-tab .file-name{
+ font-size: 12px;
+ line-height: 33px;
+ height: 33px;
+ color: #000000;
+ margin: 0 20px 0 20px;
+}
+.jimu-widget-grg-setting .appearance-tab .types>:first-child{
+ margin-left: 0;
+}
+.jimu-rtl .jimu-widget-grg-setting .appearance-tab .types>:first-child{
+ margin-right: 0;
+}
+.jimu-widget-grg-setting .appearance-tab .fillstype{
+ margin: 10px 20px 0 20px;
+}
+
+.jimu-widget-grg-setting .appearance-tab .buttonText{
+ width: 290px;
+ margin-bottom: 10px;
+}
+
+
+.jimu-widget-grg-setting .instruction span{
+ color: #596679;
+}
+.jimu-widget-grg-setting .editor-container{
+ position: absolute;
+ top: 34px;
+ bottom: 165px;
+ left: 0;
+ right: 0;
+ border: 1px solid #d2dae2;
+ background-color: #fafafc;
+}
+.jimu-widget-grg-setting .editor-container .dijitEditorIFrameContainer{
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+.jimu-widget-grg-setting .editor-container .dijitEditorIFrameContainer {
+ padding-top: 0;
+}
+
+.jimu-widget-grg-setting .editor-container .uploaderInsideNode embed {
+ display: none;
+}
+.jimu-widget-grg-setting .splash-footer{
+ /*position: absolute;
+ bottom: 5px;*/
+ color: #596679;
+/* left: 0;
+ right: 0;*/
+ height: 155px;
+ margin-top: 20px;
+}
+.jimu-widget-grg-setting .splash-footer .require-continue{
+ position: absolute;
+ top: 0;
+}
+.jimu-widget-grg-setting .splash-footer .require-item{
+ margin-bottom: 10px;
+}
+.jimu-widget-grg-setting .splash-footer .option-text{
+ display: none;
+ margin: 10px 0 15px 23px;
+}
+.jimu-widget-grg-setting .splash-footer .confirm-container{
+ display: none;
+ margin-left: 20px;
+ margin-bottom: 10px;
+}
+.jimu-widget-grg-setting .splash-footer .confirm-text,
+.jimu-widget-grg-setting .splash-footer .confirm-option{
+ width: 100%;
+ margin-top: 10px;
+}
+.jimu-widget-grg-setting .splash-footer .spinner-label{
+ line-height: 30px;
+ margin-right: 10px;
+ display: inline-block;
+}
+.jimu-widget-grg-setting .splash-footer .set-background,
+.jimu-widget-grg-setting .splash-footer .set-background *{
+ vertical-align: middle;
+}
+.jimu-widget-grg-setting .splash-footer input{
+ width: 755px;
+ color: #7989a0;
+}
+.jimu-widget-grg-setting .dojoxEditorUploadNorm.dijitButtonDisabled {
+ background: #ccc url(../../css/images/uploadImageIcon_disabled.gif) no-repeat 2px 2px;
+}
+
+/*------------------------- Styles for Settings Font Styles -----------------------*/
+
+.jimu-widget-grg-setting .style-selector .jimu-widget-grg-settingearFix {
+ *overflow: hidden;
+ *zoom: 1
+}
+
+.jimu-widget-grg-setting .style-selector .jimu-widget-grg-settingearFix:after {
+ display: table;
+ content: "";
+ width: 0;
+ clear: both
+}
+
+.jimu-widget-grg-setting .style-selector .hide {
+ display: none
+}
+
+.jimu-widget-grg-setting .settings-container {
+}
+
+.jimu-widget-grg-setting .settings-container .title {
+ font-size: 14px;
+ color: #000000;
+ letter-spacing: 0.39px;
+ margin-bottom: 20px;
+}
+
+.jimu-widget-grg-setting .settings-container .label {
+ font-size: 12px;
+ color: #282828;
+ letter-spacing: 0.33px;
+ line-height: 30px;
+}
+
+.jimu-widget-grg-setting .style-selector .label {
+ margin: 0 0;
+ max-width: 160px;
+ line-height: 30px;
+ font-size: 12px;
+ vertical-align: middle;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitTextBox,
+.jimu-widget-grg-setting .style-selector .dijitSelect {
+ width: 100%;
+ height: 30px;
+ border: 1px solid #D7D7D7;
+}
+
+.jimu-widget-grg-setting .style-selector .jimu-color-picker {
+ width: 40px !important;
+ height: 30px !important;
+ border: 1px solid #D7D7D7 !important;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitSelect .dijitArrowButtonContainer {
+ border: none;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitDownArrowButton .dijitButtonContents,
+.jimu-widget-grg-setting .style-selector .dijitComboBox .dijitDownArrowButton {
+ border: none;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitTextBox .dijitInputInner {
+ padding: 1px 0 0 0 !important;
+ font-size: 12px;
+ font-style: normal !important;
+ height: 28px;
+ line-height: 28px !important;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitSelectLabel {
+ font-size: 12px;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitSelect,
+.jimu-widget-grg-setting .style-selector .dijitSelect .dijitButtonContents,
+.jimu-widget-grg-setting .style-selector .dijitTextBox,
+.jimu-widget-grg-setting .style-selector .dijitTextBox .dijitButtonNode {
+ background-color: transparent;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitSelect .dijitArrowButton {
+ background-color: transparent;
+}
+
+.jimu-widget-grg-setting .style-selector .dijitSelect .dijitInputField {
+ padding: 0px 10px;
+}
+
+.jimu-widget-grg-setting .jimu-image-chooser .display-text {
+ width: 100%;
+ font-size: 12px;
+ color: #4A4A4A;
+ letter-spacing: 0.33px;
+ background-color: #FFF;
+ text-align: center;
+}
+
+.jimu-image-chooser:hover .hint .display-text {
+ color: #FFF;
+}
+
+.jimu-widget-grg-setting .dijitTextBoxFocused {
+ border: 1px solid #D7D7D7 !important;
+ box-shadow: 0 0 0 0 !important;
+}
+
+.jimu-widget-grg-setting .dijitTextBox .dijitInputField {
+ padding: 0px 10px;
+}
+
+.jimu-widget-grg-setting .dijitSelectFocused .dijitArrowButton .dijitArrowButtonInner {
+ background-position: -35px 53%;
+}
+
+.jimu-widget-grg-setting .text-size .text-size-group>.dijitComboBox.dijitValidationTextBox {
+ width: 80px;
+}
+
+.jimu-widget-grg-setting .text-size .text-size-group>table {
+ width: 140px;
+}
+
+.jimu-widget-grg-setting .halo-size .halo-size-group>.dijitComboBox.dijitValidationTextBox {
+ width: 80px;
+}
+
+.jimu-widget-grg-setting .text-size .text-size-group>table {
+ width: 140px;
+}
+
+.jimu-widget-grg-setting .style-selector .setting-items {
+ height: 30px;
+ width: 100%;
+ margin: 10px 0;
+ vertical-align: middle;
+ white-space: nowrap;
+}
+
+.jimu-widget-grg-setting .style-selector .setting-wapper {
+ width: 230px;
+}
+
+.jimu-widget-grg-setting .style-selector .background-btn,
+.jimu-widget-grg-setting .style-selector .text-color-btn {
+ width: 40px;
+ height: 30px;
+ overflow: hidden;
+}
+
+.jimu-widget-grg-setting .style-selector .halo-color-btn {
+ width: 50px;
+ height: 30px;
+ overflow: hidden;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+.jimu-widget-grg-setting .style-selector .align-group {
+ margin-right: 8px;
+ margin-left: -3px;
+}
+
+.jimu-rtl .jimu-widget-grg-setting .style-selector .align-group {
+ margin-right: -3px;
+ margin-left: 8px;
+}
+
+.jimu-widget-grg-setting .style-selector .font-group-btns {
+ margin-left: 6px;
+ margin-right: 6px;
+}
+
+.jimu-widget-grg-setting .style-selector .align-btn,
+.jimu-widget-grg-setting .style-selector .font-btn {
+ height: 30px;
+ margin: 0 3px;
+}
+
+.jimu-widget-grg-setting .style-selector .font-btn {
+ width: 30px;
+}
+
+.jimu-widget-grg-setting .style-selector .align-btn {
+ width: 30px;
+}
+
+.jimu-widget-grg-setting .style-selector .image-btn {
+ width: 120px;
+ height: 30px;
+ border: 1px solid #D7D7D7;
+}
+
+.jimu-widget-grg-setting .style-selector .bold {
+ background: url("../../images/B.svg") no-repeat;
+}
+
+.jimu-widget-grg-setting .style-selector .bold.selected {
+ background: url("../../images/B_selected.svg") no-repeat;
+}
+
+.jimu-widget-grg-setting .style-selector .italic {
+ background: url("../../images/I.svg") no-repeat;
+}
+
+.jimu-widget-grg-setting .style-selector .italic.selected {
+ background: url("../../images/I_selected.svg") no-repeat;
+}
+
+.jimu-widget-grg-setting .style-selector .underline {
+ background: url("../../images/U.svg") no-repeat;
+}
+
+.jimu-widget-grg-setting .style-selector .underline.selected {
+ background: url("../../images/U_selected.svg") no-repeat;
+}
+
+.jimu-widget-grg-setting .switch-toggle-group {
+ padding: 5px;
+}
+.jimu-widget-grg-setting .switch-toggle-group .checkbox-inline {
+ padding-left: 36px;
+ vertical-align: top;
+}
+.jimu-widget-grg-setting .switch-toggle-group .switch-toggle.dijitCheckBox {
+ margin-left: -36px;
+}
+
+.jimu-widget-grg-setting .switch-toggle.dijitCheckBox {
+ height: 16px;
+ width: 28px;
+ border: 0 none;
+ background: #e04f1d;
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+}
+
+.jimu-widget-grg-setting .switch-toggle.dijitCheckBox:before {
+ content: "";
+ background: #f8f8f8;
+ position: absolute;
+ padding: 0;
+ height: 12px;
+ width: 12px;
+ left: auto;
+ right: 2px;
+ top: 2px;
+ z-index: 1;
+ -webkit-transition: right 0.3s;
+ -moz-transition: right 0.3s;
+ -o-transition: right 0.3s;
+ transition: right 0.3s;
+ -moz-border-radius: 50%;
+ -webkit-border-radius: 50%;
+ border-radius: 50%;
+}
+.jimu-widget-grg-setting .switch-toggle.dijitCheckBox input {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ z-index: 2;
+}
+.jimu-widget-grg-setting .switch-toggle.dijitCheckBox.dijitCheckBoxChecked {
+ background: #50ad4e;
+}
+.jimu-widget-grg-setting .switch-toggle.dijitCheckBox.dijitCheckBoxChecked:before {
+ right: 14px;
+}
+
+.jimu-widget-grg-setting .halo-toggle-group {
+ padding: 5px;
+}
+.jimu-widget-grg-setting .halo-toggle-group .checkbox-inline {
+ padding-left: 36px;
+ vertical-align: top;
+}
+.jimu-widget-grg-setting .halo-toggle-group .halo-toggle.dijitCheckBox {
+ margin-left: -36px;
+}
+
+.jimu-widget-grg-setting .halo-toggle.dijitCheckBox {
+ height: 16px;
+ width: 28px;
+ border: 0 none;
+ background: #e04f1d;
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+ margin-top: 6px;
+ margin-left: 5px;
+}
+
+.jimu-widget-grg-setting .halo-toggle.dijitCheckBox:before {
+ content: "";
+ background: #f8f8f8;
+ position: absolute;
+ padding: 0;
+ height: 12px;
+ width: 12px;
+ left: auto;
+ right: 2px;
+ top: 2px;
+ z-index: 1;
+ -webkit-transition: right 0.3s;
+ -moz-transition: right 0.3s;
+ -o-transition: right 0.3s;
+ transition: right 0.3s;
+ -moz-border-radius: 50%;
+ -webkit-border-radius: 50%;
+ border-radius: 50%;
+}
+.jimu-widget-grg-setting .halo-toggle.dijitCheckBox input {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ z-index: 2;
+}
+.jimu-widget-grg-setting .halo-toggle.dijitCheckBox.dijitCheckBoxChecked {
+ background: #50ad4e;
+}
+.jimu-widget-grg-setting .halo-toggle.dijitCheckBox.dijitCheckBoxChecked:before {
+ right: 14px;
+}
+
+.claro .dijitSelectLabel {
+ font-size: 9pt;
+}
\ No newline at end of file
diff --git a/GRG/setting/nls/strings.js b/GRG/setting/nls/strings.js
new file mode 100644
index 0000000..3f296ef
--- /dev/null
+++ b/GRG/setting/nls/strings.js
@@ -0,0 +1,65 @@
+define({
+ root: ({
+ //Tab Labels
+ "gridTabLabel": "Grid", // Shown as tab label for grid settings
+ "labelTabLabel": "Labels", // Shown as tab label for label settings
+ "referenceSystemTabLabel": "Reference System", // Shown as tab label for reference system settings
+
+
+ //Grid Tab Contents
+ "gridTabDescription": "Set the appearance and behavior of the grid cells.", // Shown as description for grid settings
+ "cellOutlineColor": "Cell Outine color", // Shown as label above cell outline color picker
+ "cellFillColor": "Cell Fill color", // Shown as label above cell fill color picker
+ "transparency": "Transparency", // Shown as label for transparency
+
+ "cellShapeDropDown": "Cell Shape", // Shown as label above cell shape dropdown
+ "default": "Rectangle", // Shown as label for default in cell shape dropdown
+ "hexagon": "Hexagon", // Shown as label for hexagon in cell shape dropdown
+
+ "cellUnitsDropDown": "Cell Units", // Shown as label above cell units dropdown
+ "miles": 'Miles', // Shown as label for miles in cell units dropdown
+ "kilometers": 'Kilometers', // Shown as label for kilometers in cell units dropdown
+ "feet": 'Feet', // Shown as label for feet in cell units dropdown
+ "meters": 'Meters', // Shown as label for meters in cell units dropdown
+ "yards": 'Yards', // Shown as label for yards in cell units dropdown
+ "nautical-miles": 'Nautical Miles', // Shown as label for nauticalMiles in cell units dropdown
+
+ "gridOriginDropDown": "Grid Origin", // Shown as label above grid origin dropdown
+ "lowerLeft": 'Lower-Left', // Shown as label for lower left in label start position and grid origin dropdowns
+ "lowerRight": 'Lower-Right', // Shown as label for lower right in label start position and grid origin dropdowns
+ "upperLeft": 'Upper-Left', // Shown as label for upper left in label start position and grid origin dropdowns
+ "upperRight": 'Upper-Right', // Shown as label for upper right in label start position and grid origin dropdowns
+ "center": 'Center', // Shown as label for center in grid origin dropdown
+
+
+ //Label Tab Contents
+ "labelTabDescription": "Set the appearance and behavior of the grid labels.", // Shown as description for grid settings
+ "labelSettings": "Label Style", // Shown as label above label settings
+ "font": 'Font', // Shown as label for font type
+ "textSize": 'Text Size', // Shown as label for font size
+ "textColor": 'Text Color', // Shown as label for font colour
+ "halo": 'Halo', // Shown as label for halo settings
+ "show": 'Show', // Shown as label for halo settings
+
+ "labelTypeDropDown": "Label Type", // Shown as label above label type dropdown
+ "alphaNumeric": 'Alpha-Numeric', // Shown as label for Alpha-Numeric in label type dropdown
+ "alphaAlpha": 'Alpha-Alpha', // Shown as label for Alpha-Alpha in label type dropdown
+ "numeric": 'Numeric', // Shown as label for Numeric in label type dropdown
+
+ "labelDirectionDropDown": "Label Direction", // Shown as label above label direction dropdown
+ "horizontal": 'Horizontal', // Shown as label for Horizontal in label direction dropdown
+ "vertical": 'Vertical', // Shown as label for Vertical in label direction dropdown
+
+ "labelOriginDropDown": "Label Origin", // Shown as label above label type dropdown
+
+ //Reference System Tab Contents
+ "referenceSystemlTabDescription": "Set the default reference system.", // Shown as description for grid settings
+
+ "MGRS": 'MGRS', // Shown as label for MGRS in reference system dropdown
+ "USNG": 'USNG', // Shown as label for USNG in reference system dropdown
+
+
+ // Lock Settings
+ "lockSettings": "Lock Settings - This will prevent the user from being able to change any of the configured settings within the widget" // Shown as description next to locak settings toggle
+ })
+});
\ No newline at end of file
diff --git a/GRG/templates/ColorPickerEditor.html b/GRG/templates/ColorPickerEditor.html
new file mode 100644
index 0000000..33aaab2
--- /dev/null
+++ b/GRG/templates/ColorPickerEditor.html
@@ -0,0 +1,9 @@
+
+
+
${nls.transparency}
+
+
+
%
+
+
diff --git a/GRG/templates/ConfirmNotation.html b/GRG/templates/ConfirmNotation.html
new file mode 100644
index 0000000..d7d8820
--- /dev/null
+++ b/GRG/templates/ConfirmNotation.html
@@ -0,0 +1,9 @@
+
diff --git a/GRG/templates/EditOutputCoordinate.html b/GRG/templates/EditOutputCoordinate.html
new file mode 100644
index 0000000..32f31e4
--- /dev/null
+++ b/GRG/templates/EditOutputCoordinate.html
@@ -0,0 +1,27 @@
+
+
${nls.setCoordFormat}
+
+
+ DD
+ DDM
+ DMS
+ GARS
+ GEOREF
+ MGRS
+ USNG
+ UTM
+ UTM (H)
+
+
+
+
+
+
+
+
+
${nls.cancelBtn}
+
${nls.applyBtn}
+
+
diff --git a/GRG/templates/FontSetting.html b/GRG/templates/FontSetting.html
new file mode 100644
index 0000000..641fbe6
--- /dev/null
+++ b/GRG/templates/FontSetting.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
${nls.transparency}
+
+
+
+
\ No newline at end of file
diff --git a/GRG/templates/GridSettings.html b/GRG/templates/GridSettings.html
new file mode 100644
index 0000000..65de2be
--- /dev/null
+++ b/GRG/templates/GridSettings.html
@@ -0,0 +1,102 @@
+
+
+
+
+ ${nls.gridSettingsLabel}
+
+
+
+
+
+
+
+
+ ${nls.gridSettings.cellShape}
+
+
+
+
+
+
+
+ ${nls.gridSettings.cellUnits}
+
+
+
+
+
+
+
+ ${nls.gridSettings.gridOrigin}
+
+
+
+
+
+
+
+ ${nls.gridSettings.gridReferenceSystem}
+
+ ${nls.gridSettings.gridDatum}
+
+
+
+
+
+
+
+ ${nls.gridSettings.cellOutline}
+
+
+
+
+
+
+ ${nls.gridSettings.cellFill}
+
+
+
+
+
+
+
+ ${nls.labelSettingsLabel}
+
+
+
+
+
+
+
+
+
+ ${nls.gridSettings.labelStartPosition}
+
+
+
+
+
+
+
+ ${nls.gridSettings.labelType}
+
+
+
+
+
+
+
+ ${nls.gridSettings.labelDirection}
+
+
+
+
+
+
+
+ ${nls.labelStyle}
+
+
+
+
+
\ No newline at end of file
diff --git a/GRG/templates/TransparencyEditor.html b/GRG/templates/TransparencyEditor.html
new file mode 100644
index 0000000..9ef4677
--- /dev/null
+++ b/GRG/templates/TransparencyEditor.html
@@ -0,0 +1,7 @@
+
+
diff --git a/GRG/version.txt b/GRG/version.txt
new file mode 100644
index 0000000..6714917
--- /dev/null
+++ b/GRG/version.txt
@@ -0,0 +1,3 @@
+ArcGIS Solutions - September 2016 Release
+This version.txt reflects when the widget code was released.
+Other parts of the solution (e.g. map document or sample data) may have updated in a later release.
diff --git a/ISSUE_TEMPLATE b/ISSUE_TEMPLATE
new file mode 100644
index 0000000..1943845
--- /dev/null
+++ b/ISSUE_TEMPLATE
@@ -0,0 +1,5 @@
+### Bug or Enhancement
+
+### Repo Steps or Enhancement details
+
+### Screenshots
diff --git a/LICENSE b/LICENSE
index 8dada3e..e898610 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright {yyyy} {name of copyright owner}
+ Copyright 2017 Esri
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 99cdd5b..4c8e539 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,45 @@
# GRG Widget
A GRG (Grid Reference Graphic) is a grid overlay used for a common reference point in many situations - from cordon and search operations to security for presidential inaugurations.
+![App](solutions-grg-widget.png)
+
+[View it live](https://nationalsecurity.esri.com/solutionsweb/grg/)
+
## Sections
* [Features](#features)
-* [Requirements](#requirements)
* [Instructions](#instructions)
+* [Requirements](#requirements)
* [Resources](#resources)
* [Issues](#issues)
* [Contributing](#contributing)
* [Licensing](#licensing)
## Features
-* Allows users to create a grid overlay from an extent or a point on a map.
+Allows users to create an gridded reference graphic from:
+ * An area
+ * By Dimension
+ * By Reference System
+ * A point
+ * By Dimension
+ * By Reference System
+
+## Instructions
+In order to develop and test widgets you need to deploy the GRG directory to the stemapp/widgets directory in your WebApp Builder installation.
## Requirements
-* Minimum requiremnet is ArcGIS WebApp Builder v.1.0. Widget has been updated to v.2.2.
+* Minimum requirement is ArcGIS WebApp Builder v.1.0.
+* Widget has been updated to v.2.6.
-## Instructions
-In order to develop and test widgets you need to deploy the GRG directory to the stemapp/widgets directory in your WebApp Builder installation.
+## Resources
+* [Web AppBuilder for ArcGIS (Developer Edition)](https://developers.arcgis.com/web-appbuilder/)
+* [ArcGIS Solutions](http://solutions.arcgis.com/)
+* [ArcGIS for JavaScript API Resource Center](http://help.arcgis.com/en/webapi/javascript/arcgis/index.html)
+* [ArcGIS Blog](http://blogs.esri.com/esri/arcgis/)
+* [twitter@esri](http://twitter.com/esri)
## Issues
-* Find a bug or want to request a new feature? Please let us know by submitting an issue.
+Find a bug or want to request a new feature? Please let us know by submitting an [issue](https://github.com/ArcGIS/solutions-grg-widget/issues/new).
## Contributing
Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](https://github.com/esri/contributing).
@@ -30,7 +48,7 @@ If you are using [JS Hint](http://http://www.jshint.com/) there is a .jshintrc f
We allow for 120 characters per line instead of the highly restrictive 80.
## Licensing
-Copyright 2013 Esri
+Copyright 2017 Esri
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -45,7 +63,4 @@ See the License for the specific language governing permissions and
limitations under the License.
A copy of the license is available in the repository's
-[license.txt](license.txt) file.
-
-[](Esri Tags: ArcGISSolutions ArcGIS Defense and Intelligence Military Environment Planning Analysis Emergency Management Local-Government Local Government State-Government State Government Utilities)
-[](Esri Language: Javascript)
+[LICENSE](LICENSE) file.
diff --git a/jshintrc_other b/jshintrc_other
new file mode 100644
index 0000000..90754b2
--- /dev/null
+++ b/jshintrc_other
@@ -0,0 +1,80 @@
+{
+ // JSHint Default Configuration File (as on JSHint website)
+ // See http://jshint.com/docs/ for more details
+ // The following options have been deprecated and will be removed in the next
+ // major release of jshint. You can use JSCS to enforce rules relating to code style
+ // "camelcase", "enforceall", "immed", "indent", "maxlen", "newcap", "noempty",
+ // "quotmark", "laxbreak", "laxcomma", "multistr", "sub"
+
+ "maxerr" : 50, // {int} Maximum error before stopping
+
+ // Enforcing
+ "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
+ "curly" : true, // true: Require {} for every new block or scope
+ "eqeqeq" : true, // true: Require triple equals (===) for comparison
+ "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty()
+ "latedef" : false, // true: Require variables/functions to be defined before being used
+ "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
+ "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
+ "plusplus" : false, // true: Prohibit use of `++` & `--`
+ "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
+ "unused" : "strict", // true: Require all defined variables be used
+ "strict" : false, // true: Requires all functions run in ES5 Strict Mode
+ "trailing" : true, // true: Prohibit trailing whitespaces
+ "maxparams" : false, // {int} Max number of formal params allowed per function
+ "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
+ "maxstatements" : false, // {int} Max number statements per function
+ "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
+
+ // Relaxing
+ "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
+ "boss" : false, // true: Tolerate assignments where comparisons would be expected
+ "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
+ "eqnull" : false, // true: Tolerate use of `== null`
+ "es3" : true,
+ "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
+ "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
+ "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
+ // (ex: `for each`, multiple try/catch, function expression)
+ "evil" : false, // true: Tolerate use of `eval` and `new Function()`
+ "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
+ "funcscope" : false, // true: Tolerate defining variables inside control statements"
+ "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
+ "iterator" : false, // true: Tolerate using the `__iterator__` property
+ "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
+ "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
+ "laxcomma" : false, // true: Tolerate comma-first style coding
+ "loopfunc" : false, // true: Tolerate functions being defined in loops
+ "multistr" : false, // true: Tolerate multi-line strings
+ "proto" : false, // true: Tolerate using the `__proto__` property
+ "scripturl" : false, // true: Tolerate script-targeted URLs
+ "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment
+ "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
+ "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
+ "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
+ "validthis" : false, // true: Tolerate using this in a non-constructor function
+
+ // Environments
+ "browser" : true, // Web Browser (window, document, etc)
+ "couch" : false, // CouchDB
+ "devel" : true, // Development/debugging (alert, confirm, etc)
+ "dojo" : false, // Dojo Toolkit
+ "jquery" : false, // jQuery
+ "mootools" : false, // MooTools
+ "node" : false, // Node.js
+ "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
+ "prototypejs" : false, // Prototype and Scriptaculous
+ "rhino" : false, // Rhino
+ "worker" : false, // Web Workers
+ "wsh" : false, // Windows Scripting Host
+ "yui" : false, // Yahoo User Interface
+
+ // Legacy
+ "nomen" : false, // true: Prohibit dangling `_` in variables
+ "onevar" : false, // true: Allow only one `var` statement per function
+ "passfail" : false, // true: Stop on first error
+ "white" : false, // true: Check against strict whitespace and indentation rules
+
+ // Custom Globals
+ "predef" : ["exports", "require", "define", "main", "builderNls", "JSON"] // additional predefined global variables
+}
\ No newline at end of file
diff --git a/solutions-grg-widget.png b/solutions-grg-widget.png
new file mode 100644
index 0000000..031f031
Binary files /dev/null and b/solutions-grg-widget.png differ