├── .eslintrc
├── .gitignore
├── CONTRIBUTING.md
├── Gruntfile.js
├── Jenkinsfile
├── License.txt
├── README.md
├── enterprise-build-sample-js.png
├── karma.conf.js
├── package-lock.json
├── package.json
├── spec
├── ToolbarSpec.js
└── main.js
├── test-reports
└── HeadlessChrome_64.0.3282_(Windows_10.0.0)
│ └── test-results.xml
├── web
├── buildProject.css
├── index.html
├── index.js
└── js
│ ├── buildProject
│ ├── ChartingPane.js
│ ├── InfoGrid.js
│ ├── SiteManager.js
│ ├── Toolbar.js
│ ├── ToolbarSkeleton.js
│ ├── TravelRingDialog.js
│ ├── TravelRingTool.js
│ ├── _buildProject.profile.js
│ ├── buildProject.js
│ ├── package.json
│ └── templates
│ │ ├── ChartingPane.html
│ │ ├── InfoGrid.html
│ │ ├── Toolbar.html
│ │ └── _TravelRingDialog.html
│ ├── data
│ ├── config.json
│ └── sampleData.json
│ └── images
│ └── logo.jpg
└── webpack.config.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "env": {
4 | "browser": true
5 | },
6 | "rules": {
7 | "no-console": "off",
8 | "semi": ["error", "always"],
9 | "quotes": "off",
10 | "no-unused-vars": "off",
11 | "no-mixed-spaces-and-tabs":"off"
12 | }
13 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | arcgis-js-api/
4 | enterprise-build-sample-js.sublime-project
5 | enterprise-build-sample-js.sublime-workspace
6 | build-src/
7 | build-temp/
8 | Chrome_*/
9 | coverage/
10 | test-reports/
11 | test-results.xml
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](https://github.com/esri/contributing).
2 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | module.exports = function (grunt) {
4 | // Build customizations would be left up to developer to implement.
5 | grunt.loadNpmTasks('grunt-karma');
6 | grunt.loadNpmTasks('grunt-contrib-watch');
7 | grunt.loadNpmTasks('grunt-eslint');
8 | grunt.loadNpmTasks('grunt-tomcat-deploy');
9 | grunt.loadNpmTasks('grunt-zip');
10 |
11 | var servePort = grunt.option('servePort') || 8000;
12 | var port = grunt.option('port') || 8080;
13 | var host = grunt.option('host') || 'localhost';
14 | var path = grunt.option('path') || 'sample';
15 |
16 | grunt.initConfig({
17 | karma: {
18 | options: {
19 | // get defaults from karma config
20 | configFile: 'karma.conf.js',
21 | // run all tests once then exit
22 | singleRun: true,
23 | // only show error messages
24 | logLevel: 'ERROR',
25 | },
26 | unit: {
27 | options:{
28 | singleRun: true,
29 | captureTimeout:30000,
30 | reporters : ['junit', 'progress'],
31 | junitReporter: {
32 | outputDir: 'test-reports', // results will be saved as $outputDir/$browserName.xml
33 | outputFile: undefined, // if included, results will be saved as $outputDir/$browserName/$outputFile
34 | suite: '', // suite will become the package name attribute in xml testsuite element
35 | useBrowserName: true // add browser name to report and classes names
36 | }
37 | }
38 | }
39 | },
40 | eslint: {
41 | files: [ 'web/js/buildProject/**/*.js' ]
42 | },
43 | watch: {
44 | options: {
45 | livereload: true
46 | },
47 | js: {
48 | files: [ 'Gruntfile.js', 'web/js/buildProject/**/*.js', 'spec/**/*.js' ],
49 | tasks: ['test']
50 | },
51 | html: {
52 | files: [ 'web/index.html']
53 | }
54 | },
55 |
56 | // Tomcat redeploy task still gets its config from tomcat_deploy
57 | // config item
58 | tomcat_deploy: {
59 | host: host,
60 | login: 'tomcat',
61 | password: 'tomcat',
62 | path: '/' + path,
63 | port: port,
64 | war: 'sample.war',
65 | deploy: '/manager/text/deploy',
66 | undeploy: '/manager/text/undeploy'
67 | },
68 |
69 | zip: {
70 | war: {
71 | cwd: 'dist',
72 | dest: 'sample.war',
73 | src: ['dist/**']
74 | }
75 | }
76 | });
77 |
78 | // Serve dev app locally
79 | grunt.registerTask('serve', [ 'watch' ]);
80 |
81 | grunt.registerTask('deploy', ['tomcat_redeploy']);
82 |
83 | grunt.registerTask('test', ['eslint', 'karma']);
84 |
85 | // JS task
86 | grunt.registerTask('js', [ 'eslint']);
87 |
88 | };
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | pipeline {
2 | agent { label 'windows' }
3 | stages {
4 | stage('test') {
5 | steps {
6 | bat 'npm install'
7 | bat 'grunt test -v'
8 | }
9 | post {
10 | success {
11 | junit 'test-reports/**/*.xml'
12 | }
13 | }
14 | }
15 | stage('build') {
16 | steps {
17 | bat 'npm install'
18 | bat 'bower install'
19 | bat 'grunt build zip -v'
20 | }
21 | post {
22 | success {
23 | stash includes: '*.war', name: 'app'
24 | }
25 | }
26 | }
27 | stage('deploy QA') {
28 | steps {
29 | unstash 'app'
30 | bat 'grunt deploy'
31 | }
32 | }
33 | stage('deploy Prod') {
34 | steps {
35 | milestone(3)
36 | input message: 'Deploy?'
37 | unstash 'app'
38 | bat 'grunt deploy --port=8081'
39 | milestone(4)
40 | }
41 | }
42 | }
43 | post {
44 | failure {
45 | mail to: 'randy_jones@esri.com', subject: 'The Pipeline failed', body: 'The Pipeline failed'
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 | Apache License - 2.0
2 |
3 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
4 |
5 | 1. Definitions.
6 |
7 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
8 |
9 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
10 |
11 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control
12 | with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management
13 | of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
14 | ownership of such entity.
15 |
16 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
17 |
18 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source,
19 | and configuration files.
20 |
21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to
22 | compiled object code, generated documentation, and conversions to other media types.
23 |
24 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice
25 | that is included in or attached to the work (an example is provided in the Appendix below).
26 |
27 | "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
28 | editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes
29 | of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of,
30 | the Work and Derivative Works thereof.
31 |
32 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work
33 | or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual
34 | or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
35 | electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on
36 | electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for
37 | the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing
38 | by the copyright owner as "Not a Contribution."
39 |
40 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and
41 | subsequently incorporated within the Work.
42 |
43 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
44 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display,
45 | publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
46 |
47 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide,
48 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell,
49 | sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are
50 | necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was
51 | submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work
52 | or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You
53 | under this License for that Work shall terminate as of the date such litigation is filed.
54 |
55 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications,
56 | and in Source or Object form, provided that You meet the following conditions:
57 |
58 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
59 |
60 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
61 |
62 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices
63 | from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
64 |
65 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a
66 | readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the
67 | Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the
68 | Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever
69 | such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License.
70 | 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,
71 | provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to
72 | Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your
73 | modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with
74 | the conditions stated in this License.
75 |
76 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You
77 | to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above,
78 | nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
79 |
80 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except
81 | as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
82 |
83 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides
84 | its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation,
85 | any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for
86 | determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under
87 | this License.
88 |
89 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required
90 | by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages,
91 | including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the
92 | use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
93 | any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
94 |
95 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a
96 | fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting
97 | 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
98 | to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your
99 | accepting any such warranty or additional liability.
100 |
101 | END OF TERMS AND CONDITIONS
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # enterprise-build-sample-js
2 |
3 | This sample application shows how to apply webpack on a legacy 4.x ArcGIS API for JavaScript application to get it ready for production. This sample is using the 4.10 version of the ArcGIS API for JavaScript.
4 |
5 | 
6 |
7 | ## Features
8 | * Sample Enterprise Application - Formatted and developed to work with Automated Webpack Builds
9 | * Sample Webpack Config - Sample webpack files to be adapted to your own applications
10 |
11 | ## Instructions
12 |
13 | 1. install [git](https://git-scm.com/)
14 | 2. install [Node.js](https://nodejs.org/)
15 | 3. Fork and then clone this repository.
16 | 4. Navigate to the folder project was cloned to.
17 | 5. Install local node packages into your project by running `npm install`
18 | 8. Run the webpack build using grunt by running `npm run build`
19 | 9. When the build is complete the dist directory should be a production ready version of the application
20 |
21 | ## Requirements
22 |
23 | * Notepad or your favorite HTML editor
24 | * [Node.js](https://nodejs.org/)
25 | * Web browser with access to the Internet
26 |
27 | ## Resources
28 |
29 | * [ArcGIS for JavaScript API Resource Center](https://js.arcgis.com/)
30 | * [ArcGIS WebPack Plugin Documentation](https://developers.arcgis.com/javascript/latest/guide/using-webpack/)
31 | * [ArcGIS WebPack Plugin Source](https://github.com/esri/arcgis-webpack-plugin)
32 | * [ArcGIS Blog](http://blogs.esri.com/esri/arcgis/)
33 | * [twitter@esri](http://twitter.com/esri)
34 | * [Dev Summit 2018 Build Presentation](https://www.youtube.com/watch?v=KGJs4au30Zk)
35 | * [Dev Summit 2017 Build Presentation](https://www.youtube.com/watch?v=3H_de4pAs70)
36 | * [Dev Summit 2017 Testing Presentation](https://www.youtube.com/watch?v=QJIQxx79MhE)
37 |
38 | ## Issues
39 |
40 | Find a bug or want to request a new feature? Please let us know by submitting an issue.
41 |
42 | ## Contributing
43 |
44 | Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](https://github.com/esri/contributing).
45 |
46 | ## Licensing
47 | Copyright 2015 Esri
48 |
49 | Licensed under the Apache License, Version 2.0 (the "License");
50 | you may not use this file except in compliance with the License.
51 | You may obtain a copy of the License at
52 |
53 | http://www.apache.org/licenses/LICENSE-2.0
54 |
55 | Unless required by applicable law or agreed to in writing, software
56 | distributed under the License is distributed on an "AS IS" BASIS,
57 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
58 | See the License for the specific language governing permissions and
59 | limitations under the License.
60 |
61 | A copy of the license is available in the repository's [license.txt](License.txt?raw=true) file.
62 |
--------------------------------------------------------------------------------
/enterprise-build-sample-js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Esri/enterprise-build-sample-js/d3ded8d09e4cbf18cbcde9ae4ecde56027fe77db/enterprise-build-sample-js.png
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | module.exports = function(config) {
4 | config.set({
5 | // base path, that will be used to resolve files and exclude
6 | basePath: '',
7 |
8 | frameworks: ['jasmine', 'dojo'],
9 |
10 | // list of files / patterns to load in the browser
11 | files: [
12 | 'spec/main.js',
13 |
14 | // all the sources, tests
15 | {pattern: 'web/js/buildProject/**/*', included: false},
16 | {pattern: 'spec/*.js', included: false}
17 | ],
18 |
19 |
20 | // uncomment the following for code coverage
21 | // preprocessors: {
22 | // // source files, that you wanna generate coverage for
23 | // // do not include tests or libraries
24 | // // (these files will be instrumented by Istanbul)
25 | // 'src/**/*.js': ['coverage']
26 | // },
27 |
28 |
29 | // test results reporter to use
30 | // possible values: dots || progress
31 | reporters: [
32 | 'dots', 'junit'
33 | // uncomment the following line for code coverage
34 | // , 'coverage'
35 | ],
36 |
37 | junitReporter : {
38 | outputFile: 'test-results.xml'
39 | },
40 |
41 |
42 | // web server port
43 | port: 9876,
44 |
45 | // proxy for cross domain requests
46 | proxies: {
47 | '/arcgis/': 'http://imagery.arcgisonline.com/arcgis/'
48 | },
49 |
50 |
51 | // cli runner port
52 | runnerPort: 9100,
53 |
54 |
55 | // enable / disable colors in the output (reporters and logs)
56 | colors: true,
57 |
58 |
59 | // level of logging
60 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
61 | logLevel: config.LOG_INFO,
62 |
63 |
64 | // enable / disable watching file and executing tests whenever any file changes
65 | autoWatch: false,
66 |
67 | // Start these browsers, currently available:
68 | // - Chrome
69 | // - ChromeCanary
70 | // - Firefox
71 | // - Opera
72 | // - Safari
73 | // - PhantomJS
74 | // NOTE: you may need to first set it's path in an environment vairable, for example:
75 | // set FIREFOX_BIN="c:\Program Files (x86)\Mozilla Firefox\firefox.exe"
76 | // see: http://karma-runner.github.io/0.10/config/browsers.html
77 | browsers: [
78 | 'ChromeHeadless'
79 | // add the name (from above) for each additional
80 | // browser you want to test below
81 | // , 'Firefox'
82 | ],
83 |
84 |
85 | // uncomment the following for coverage options
86 | // see: https://github.com/karma-runner/karma-coverage#options
87 | // coverageReporter: {
88 | // type : 'text',
89 | // dir: 'coverage/'
90 | // },
91 |
92 |
93 | // Continuous Integration mode
94 | // if true, it capture browsers, run tests and exit
95 | singleRun: true
96 | });
97 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "enterprise-test-sample",
3 | "version": "2.0.0",
4 | "description": "Here is a sample application, bundled with current versions of the patched Dojo source and ESRI JavaScript API AMD Build. The sample uses ArcGIS Online basemaps and services. Learn more [here](http://www.arcgis.com/about/).",
5 | "main": "Gruntfile.js",
6 | "scripts": {
7 | "test": "grunt test",
8 | "test:watch": "grunt watch",
9 | "start": "npm-run-all --parallel serve:dev test test:watch",
10 | "build": "webpack --mode production",
11 | "serve": "webpack-dev-server --mode production --open --https --compress",
12 | "serve:dev": "webpack-dev-server --mode development --open"
13 | },
14 | "devDependencies": {
15 | "clean-webpack-plugin": "^2.0.0",
16 | "copy-webpack-plugin": "^5.0.0",
17 | "css-loader": "^2.1.0",
18 | "dojo-themes": "^1.13.0",
19 | "grunt": "^1.0.3",
20 | "grunt-contrib-watch": "^1.1.0",
21 | "grunt-eslint": "^20.1.0",
22 | "grunt-karma": "^3.0.1",
23 | "grunt-tomcat-deploy": "git://github.com/rsjones/grunt-tomcat-deploy.git",
24 | "grunt-zip": "^0.10.2",
25 | "html-loader": "^0.5.5",
26 | "html-webpack-plugin": "^3.2.0",
27 | "jasmine-core": "^3.3.0",
28 | "karma": "^4.0.1",
29 | "karma-chrome-launcher": "^2.2.0",
30 | "karma-coverage": "^1.1.2",
31 | "karma-dojo": "0.0.1",
32 | "karma-jasmine": "^2.0.1",
33 | "karma-junit-reporter": "^1.2.0",
34 | "mini-css-extract-plugin": "^0.5.0",
35 | "npm-run-all": "^4.1.5",
36 | "raw-loader": "^1.0.0",
37 | "requirejs": "^2.3.6",
38 | "uglifyjs-webpack-plugin": "^2.1.2",
39 | "webpack": "^4.29.6",
40 | "webpack-cli": "^3.2.3",
41 | "webpack-dev-server": "^3.2.1"
42 | },
43 | "dependencies": {
44 | "@arcgis/webpack-plugin": "^4.10.5"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/spec/ToolbarSpec.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'buildProject/Toolbar',
3 | 'esri/layers/TileLayer'
4 | ], function(
5 | Toolbar,
6 | TileLayer
7 | ) {
8 |
9 | describe('components: Toolbar ', function() {
10 | var testArgs = {
11 | "view": {
12 | get:function(){},
13 | watch:function(){}
14 | },
15 | "config": {},
16 | "map": {}
17 | };
18 |
19 | // create the map
20 | beforeEach(function() {
21 | toolbar = new Toolbar(testArgs);
22 | });
23 |
24 | // destroy the map
25 | afterEach(function() {
26 | toolbar.destroy();
27 | });
28 |
29 | it('clears graphics and info window', function(){
30 |
31 | toolbar.view.graphics = jasmine.createSpyObj('toolbar.view.graphics',["removeAll"]);
32 | spyOn(toolbar,"hidePopup");
33 |
34 | toolbar.clearGraphics();
35 |
36 | expect(toolbar.view.graphics.removeAll).toHaveBeenCalled();
37 | expect(toolbar.hidePopup).toHaveBeenCalled();
38 |
39 | });
40 |
41 | it('toggles street map', function(){
42 | expect(toolbar.viewingStreets).toBe(false);
43 |
44 | var hideStreetMapCounter = 0;
45 | var showStreetMapCounter = 0;
46 |
47 |
48 | spyOn(toolbar,"_createStreetMapLayer");
49 | spyOn(toolbar,"_hideStreetMapLayer");
50 | spyOn(toolbar,"_showStreetMapLayer");
51 |
52 | toolbar.toggleStreetMap();
53 |
54 | expect(toolbar._createStreetMapLayer).toHaveBeenCalled();
55 | expect(toolbar._showStreetMapLayer).toHaveBeenCalled();
56 |
57 | toolbar.toggleStreetMap();
58 |
59 | expect(toolbar._hideStreetMapLayer).toHaveBeenCalled();
60 |
61 | toolbar.toggleStreetMap();
62 | expect(toolbar._showStreetMapLayer).toHaveBeenCalled();
63 |
64 | });
65 |
66 | it('enables assets button', function(){
67 | // 1. Toolbar should be disabled for zoom levels < 6
68 |
69 |
70 | // 2. Toolbar should be enabled for zoom levels >= 6
71 |
72 |
73 | //expect(toolbar.toggleAssetsButton.get("disabled")).toBeTruthy();
74 | });
75 |
76 | it('created Street Map Layer', function(){
77 |
78 | toolbar.map = jasmine.createSpyObj('toolbar.map',['add']);
79 | toolbar._createStreetMapLayer();
80 |
81 | expect(toolbar.streetMapLayer instanceof TileLayer).toBe(true);
82 | expect(toolbar.map.add).toHaveBeenCalled();
83 | });
84 |
85 | });
86 | });
--------------------------------------------------------------------------------
/spec/main.js:
--------------------------------------------------------------------------------
1 | (function(window) {
2 | 'use strict';
3 |
4 | var allTestFiles = [];
5 | var TEST_REGEXP = /.*Spec\.js$/;
6 |
7 | for (var file in window.__karma__.files) {
8 | if (TEST_REGEXP.test(file)) {
9 | allTestFiles.push(file);
10 | }
11 | }
12 |
13 | window.dojoConfig = {
14 | packages: [
15 | // local pacakges to test
16 | {
17 | name:"buildProject",
18 | location:"../../../web/js/buildProject"
19 | },
20 |
21 | // esri/dojo packages
22 | {
23 | name: 'dgrid',
24 | location: 'http://js.arcgis.com/4.6/dgrid'
25 | }, {
26 | name: 'dijit',
27 | location: 'http://js.arcgis.com/4.6/dijit'
28 | }, {
29 | name: 'esri',
30 | location: 'http://js.arcgis.com/4.6/esri'
31 | }, {
32 | name: 'dojo',
33 | location: 'http://js.arcgis.com/4.6/dojo'
34 | }, {
35 | name: 'dojox',
36 | location: 'http://js.arcgis.com/4.6/dojox'
37 | }, {
38 | name: 'moment',
39 | location: 'http://js.arcgis.com/4.6/moment'
40 | }
41 | ],
42 | };
43 |
44 |
45 | /**
46 | * This function must be defined and is called back by the dojo adapter
47 | * @returns {string} a list of dojo spec/test modules to register with your testing framework
48 | */
49 | window.__karma__.dojoStart = function() {
50 | return allTestFiles;
51 | };
52 | })(window);
--------------------------------------------------------------------------------
/test-reports/HeadlessChrome_64.0.3282_(Windows_10.0.0)/test-results.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/web/buildProject.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | width: 100%;
4 | margin: 0;
5 | padding: 0;
6 | overflow: hidden;
7 | }
8 |
9 |
10 | #map{
11 | padding:0;
12 | }
13 |
14 | .toolbar {
15 | background:white;
16 | border-style:solid;
17 | border-width:1px;
18 | position:absolute;
19 | top:5px;
20 | right:5px;
21 | z-index:999;
22 | padding: 0px 2px 5px;
23 | width: 185px;
24 | }
25 |
26 | .toolbar .header {
27 | cursor: move;
28 | border-bottom-style:solid;
29 | border-bottom-color:black;
30 | border-bottom-width:1px;
31 | }
32 |
33 | .assetDialog {
34 | height: 500px;
35 | width: 500px;
36 | }
37 |
38 | .areaDialog {
39 | height: 500px;
40 | width: 500px;
41 | }
42 |
43 | .toolbar .dijitButtonNode {
44 | width: 170px;
45 | }
46 |
47 | .chartingPane {
48 |
49 | width:360px;
50 | background:white;
51 | border-style:solid;
52 | border-width:1px;
53 | position:absolute;
54 | top:5px;
55 | right:205px;
56 | z-index:999;
57 | }
58 | .chart {
59 | height:153px;
60 | width:200px;
61 | }
62 |
63 | .titleNode {
64 | font-weight:bold;
65 | font-face:arial;
66 | font-size:15px;
67 | border-bottom-style: solid;
68 | border-bottom-color: black;
69 | border-bottom-width: 1px;
70 | padding-left: 10px;
71 | }
72 |
73 | .flat .dijitTextBox {
74 | width: 60px !important;
75 | }
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/web/index.js:
--------------------------------------------------------------------------------
1 | require([
2 | "dojo/_base/kernel",
3 | "./js/buildProject/SiteManager"
4 | ], function (kernel, SiteManager) {
5 | kernel.global.site = new SiteManager();
6 | kernel.global.site.init();
7 | });
--------------------------------------------------------------------------------
/web/js/buildProject/ChartingPane.js:
--------------------------------------------------------------------------------
1 | /*global define,dojo,dijit,dojox,buildProject,esri*/
2 |
3 | define([
4 | "dojo/_base/declare",
5 | "dojo/_base/lang",
6 | "dojo/on",
7 | "dojo/dnd/Moveable",
8 | "dojox/charting/Chart2D",
9 | "dojox/charting/action2d/Highlight",
10 | "dojox/charting/action2d/MoveSlice",
11 | "dojox/charting/action2d/Tooltip",
12 | "dojox/charting/themes/MiamiNice",
13 | "esri/tasks/support/Query",
14 | "esri/tasks/QueryTask",
15 | // Our Project's classes ---------------------------------------------
16 | "./buildProject",
17 | // Widget base classes -----------------------------------------------
18 | "dijit/_WidgetBase",
19 | "dijit/_TemplatedMixin",
20 | "dijit/_WidgetsInTemplateMixin",
21 | // Widget template ---------------------------------------------------
22 | "dojo/text!./templates/ChartingPane.html"
23 | ], function (
24 | declare,
25 | lang,
26 | on,
27 | Moveable,
28 | Chart2D,
29 | Highlight,
30 | MoveSlice,
31 | Tooltip,
32 | MiamiNice,
33 | Query,
34 | QueryTask,
35 | buildProject,
36 | _WidgetBase,
37 | _TemplatedMixin,
38 | _WidgetsInTemplateMixin,
39 | template) {
40 | return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
41 | // summary:
42 | // Floating pane that displays a pie chart when users click on
43 | // an info grid row.
44 | // templateString: String
45 | // HTML template of the widget (imported using dojo/text)
46 | // chart: dojox.charting.Chart2D
47 | // Pie chart object
48 | // queryTask: esri.tasks.QueryTask
49 | // Query Task used to fetch geometry from a given district id. This is used on slice clicks.
50 | // data: Object
51 | // Data object loaded to populate pie chart.
52 | // map: esri.Map
53 | // The application's map object.
54 | // config: Object
55 | // The application's configuration object.
56 | // infoGrid: buildProject.InfoGrid
57 | // InfoGrid object that will interact with this pane.
58 | // (This should probably be changed to use subscribe/publish functionality in the future)
59 | templateString : template,
60 | chart: null,
61 | queryTask: null,
62 | data: null,
63 | map: null,
64 | config: null,
65 | infoGrid: null,
66 | postCreate: function(){
67 | // summary:
68 | // Runs after the widget is completely formed.
69 | // description:
70 | // Runs after the widget is completely formed. Sets up the floating behavior and creates the query task.
71 |
72 | var moveable = new Moveable(this.domNode,{handle:this.header});
73 |
74 | // Note: The 1 is appended to the entityDistrictUrl to run the query on Districts.
75 | // This can be modified to change the layer. To run query tasks on multiple layers,
76 | // new query tasks will have to be constructed.
77 | this.queryTask = new QueryTask(this.config.entityDistrictUrl + "/" + this.config.entityDistrictLayer);
78 | },
79 | show: function(/*String*/field,/*String*/title,/*Object*/data,/*int*/layerId){
80 | // summary:
81 | // Displays the charting pane and sets up the pie chart.
82 | // field: String
83 | // Statistic field clicked on from the Info Grid.
84 | // title: String
85 | // Label for the feature being described in the pie chart.
86 | // data: Object
87 | // Data object orginally used by the Info Grid. This should probably be changed to be fetched dynamically from a servlet.
88 | // layerId: int
89 | // Map layer that was identified to for the Info Grid that called this function.
90 |
91 | // Show the pane and set its title.
92 | this.domNode.style.display = "";
93 | this.titleDiv.innerHTML = title + " " + field + " Results";
94 |
95 | var dc = dojox.charting;
96 | // dojox.charting can be unpredictable, so it is usually cleaner to completely destroy
97 | // the object and re-instantiate then adjusting the values.
98 | if (this.chart){
99 | this.chart.destroy();
100 | }
101 | this.chart = new Chart2D(this.chartPane);
102 | var seriesData = [];
103 |
104 | // populating random data for each district as listed in the data file.
105 | // TODO: This needs to be changed to use actual data.
106 | for (var i=0;i 0) || identifyResults.length === undefined) {
66 | if (identifyResults[0]){
67 | this.identifyResults = identifyResults[0];
68 | } else {
69 | this.identifyResults = identifyResults;
70 | }
71 | this.view.graphics.removeAll();
72 | this.view.get("popup").set("visible",false);
73 |
74 | // Destroy the grid and store since dojox is strange.
75 | if (this.grid){
76 | this.grid.destroyRecursive();
77 | delete this.store;
78 | }
79 |
80 | // Call to retrieve sample data. xhr.get cannot be used on different domains.
81 | // If you are using a servlet or data on another server, look into switching to dojo.io.script.
82 |
83 | xhr.get({
84 | url: require.toUrl("js/data/sampleData.json"),
85 | handleAs: "json",
86 | load: lang.partial(dojo.hitch(this,this._finalPopulate),point),
87 | error: buildProject.displayError
88 | }, true);
89 | } else {
90 | buildProject.displayError("No results were returned from identify.");
91 | }
92 | } catch(e){
93 | console.debug("ERROR",e);
94 | }
95 | },
96 | _finalPopulate: function(/*esri.geometry.Point*/point,/*Object*/jsonResults){
97 | // summary:
98 | // Finishes creating the chart. Called when the data object is returned from the server.
99 | // point: esri.geometry.Point
100 | // Point of map click event
101 | // jsonResults: Object
102 | // Data returned from the server.
103 |
104 | var data,attr = this.identifyResults.feature.attributes;
105 |
106 | // check to see if the layer being identified is an entity.
107 | // if it is, set the data to results attached to districts.
108 | // otherwise, assign arbitrary data.
109 | // TODO: Expand for actual data collected from server.
110 |
111 | if (this.identifyResults.layerId === 0){
112 | data = jsonResults.entities[attr.dist_region_entity_ENTITY_ID].stats;
113 | this.data = jsonResults.entities[attr.dist_region_entity_ENTITY_ID];
114 | } else {
115 | data = jsonResults.entities[9110].stats;
116 | this.data = jsonResults.entities[9110];
117 | }
118 | var obj = {"label":"id",
119 | "identifier":"id",
120 | "items":data};
121 |
122 | this.store = new ItemFileReadStore({data:obj});
123 | var layout = [{"field":"id",
124 | "title":"Field",
125 | "width":"auto" },
126 | { "field":"value",
127 | "title":"Value",
128 | "width":"auto" }];
129 |
130 | var feature = this.identifyResults.feature;
131 | var graphic = new Graphic({
132 | "geometry": feature.geometry,
133 | "symbol": new SimpleFillSymbol(),
134 | "attributes": feature.attributes
135 | });
136 | this.view.graphics.add(graphic);
137 |
138 | // Setup the popup so that it can hold the datagrid.
139 | var popup = this.view.get("popup");
140 |
141 | popup.set("title",graphic.attributes[this.identifyResults.displayFieldName]);
142 | popup.set("content",this.domNode);
143 |
144 | popup.open({
145 | "location": point
146 | });
147 |
148 | this.grid = new DataGrid({
149 | store: this.store,
150 | structure: layout,
151 | canSort: function(){return false;}
152 | },domConstruct.create("div"));
153 |
154 | domConstruct.place(this.gridDomNode,this.domNode);
155 | this.gridDomNode.appendChild(this.grid.domNode);
156 | this.grid.startup();
157 |
158 | window.setTimeout(lang.hitch(this.grid,this.grid.resize),500);
159 |
160 | // Setup click event behavior.
161 | this.grid.own(this.grid.on("RowClick", lang.hitch(this, function (evt) {
162 | var item = this.store._arrayOfAllItems[evt.rowIndex];
163 | if (!this.chartingPane){
164 | this.chartingPane = new ChartingPane({"id":"chartingPane","map":this.map,"config":this.config,"infoGrid":this},domConstruct.create('div'));
165 | document.body.appendChild(this.chartingPane.domNode);
166 | }
167 | this.chartingPane.show(this.store.getValue(item,"id"),graphic.attributes[this.identifyResults.displayFieldName],this.data,this.identifyResults.layerId);
168 | })));
169 | }
170 | });
171 | });
--------------------------------------------------------------------------------
/web/js/buildProject/SiteManager.js:
--------------------------------------------------------------------------------
1 | /*global define, require, dojo,dijit,esri,buildProject*/
2 | define([
3 | "dojo/_base/declare",
4 | "dojo/_base/kernel",
5 | "dojo/_base/lang",
6 | "dojo/_base/xhr",
7 | "dojo/dom",
8 | "dojo/on",
9 | "esri/Map",
10 | "esri/views/MapView",
11 | "esri/geometry/Extent",
12 | "esri/tasks/support/IdentifyParameters",
13 | "esri/tasks/IdentifyTask",
14 | // Our Project's classes ---------------------------------------------
15 | "./buildProject",
16 | "./InfoGrid",
17 | "./Toolbar"
18 | ], function (
19 | declare,
20 | kernel,
21 | lang,
22 | xhr,
23 | dom,
24 | on,
25 | Map,
26 | MapView,
27 | Extent,
28 | IdentifyParameters,
29 | IdentifyTask,
30 | buildProject,
31 | InfoGrid,
32 | Toolbar) {
33 | return declare (null, {
34 | // summary:
35 | // Loader class. Initializes the site and several essential widgets.
36 | // toolbar: String | buildProject.Toolbar
37 | // Initially the id of a DOM Node to create the toolbar in.
38 | // infoGrid: buildProject.InfoGrid
39 | // Chart to be displayed inside info window on identify
40 | // map: esri.Map
41 | // The application's map object
42 | // identifyTask: esri.tasks.IdentifyTask
43 | // Task used to identify entities, districts, and zip codes.
44 | // identifyParams: esri.tasks.support.IdentifyParameters
45 | // Parameters used by the Identify Task object
46 | // config: Object
47 | // Configuration object loaded from data/config.json
48 | // identifyConnect: dojo.connect
49 | // Keeps track of the on click behavior for entities, districts, and zip codes.
50 |
51 | toolbar: "toolbarNode",
52 | infoGrid: null,
53 | map: null,
54 | identifyTask: null,
55 | identifyParams: null,
56 | config: null,
57 | identifyConnect: null,
58 | init: function(){
59 | // summary:
60 | // Loades the flat config file and initializes several widgets.
61 |
62 |
63 | xhr.get({
64 | "url": require.toUrl("js/data/config.json"),
65 | "handleAs":"json",
66 | "load": lang.hitch(this,function(config){
67 | this.config = config;
68 |
69 | this.setupMap();
70 |
71 | this.setupToolbar();
72 |
73 | this.setupInfoGrid();
74 | }),
75 | "error": buildProject.displayError
76 | });
77 | },
78 | setupMap: function(){
79 | // summary:
80 | // Sets up the map starting pararmeters and loads all standard layers onto the map.
81 |
82 | var initExtent = new Extent({
83 | "xmin":-8585309.048629632,
84 | "ymin":4702297.046680435,
85 | "xmax":-8560849.19957841,
86 | "ymax":4714259.441607048,
87 | "spatialReference":{"wkid":102100}
88 | });
89 |
90 | this.map = new Map({
91 | "basemap": "dark-gray"
92 | });
93 |
94 |
95 | var lods = this.config.mapLods;
96 | this.view = new MapView({
97 | "container": "map",
98 | "map": this.map,
99 | "extent": initExtent,
100 | "lods": lods
101 | });
102 | //resize the map when the browser resizes - view the 'Resizing and repositioning the map' section in
103 | //the following help topic for more details http://help.esri.com/EN/webapi/javascript/arcgis/help/jshelp_start.htm#jshelp/inside_guidelines.htm
104 | var resizeTimer;
105 | this.map.on('load', lang.hitch(this, function(theMap) {
106 | on(kernel.global, "onresize", lang.hitch(this, function(){ //resize the map if the div is resized
107 | clearTimeout(resizeTimer);
108 | resizeTimer = setTimeout( lang.hitch(this,function(){
109 | this.map.resize();
110 | this.map.reposition();
111 | }), 250);
112 | }));
113 | }));
114 |
115 | },
116 | setupToolbar: function(){
117 | // summary:
118 | // Initializes the toolbar widget.
119 |
120 | this.toolbar = dom.byId(this.toolbar);
121 | if (this.toolbar){
122 | this.toolbar = new Toolbar({
123 | "id":"toolbar",
124 | "map":this.map,
125 | "view": this.view,
126 | "config":this.config
127 | },this.toolbar);
128 | }
129 | },
130 | setupInfoGrid: function(){
131 | // summary:
132 | // Initializes the InfoGrid widget and sets up the Identify Task.
133 |
134 | this.identifyTask = new IdentifyTask(this.config.entityDistrictUrl);
135 | this.identifyParams = new IdentifyParameters();
136 |
137 | this.identifyParams.tolerance = 1;
138 | this.identifyParams.returnGeometry = true;
139 |
140 | this.infoGrid = new InfoGrid({
141 | "id":"infoGrid",
142 | "map":this.map,
143 | "config":this.config,
144 | "view": this.view
145 | });
146 |
147 | this.enableIdentifyConnect();
148 | },
149 | disableIdentifyConnect: function(){
150 | // summary:
151 | // Disables the click to identify behavior for Entities, Districts, and Zip Codes.
152 | // description:
153 | // Disables the click to identify behavior for Entities, Districts, and Zip Codes.
154 | // This is used by the travel ring tool, and asset connections to allow us to enable
155 | // other map click actions.
156 |
157 | this.identifyConnect.remove();
158 | },
159 | enableIdentifyConnect: function(){
160 | // summary:
161 | // Enables the click to identify behavior for Entities, Districts, and Zip Codes.
162 | // description:
163 | // Enables the click to identify behavior for Entities, Districts, and Zip Codes.
164 | // This is used by the travel ring tool, and asset connections to allow us to restore
165 | // default functionality when they are done with the map.
166 |
167 | this.identifyConnect = on(this.view,"click",lang.hitch(this,this.identify));
168 | },
169 | identify: function(evt){
170 | // summary:
171 | // Runs an identify task on the given point.
172 | // description:
173 | // Runs an identify task on the given point.This is run by the identify
174 | // connect handler whenever a user clicks on the map.
175 | // evt: Event
176 | // Mouse click event.
177 |
178 | this.identifyParams.geometry = evt.mapPoint;
179 | this.identifyParams.mapExtent = this.view.get("extent");
180 |
181 | // This is used to determine which map layer we are running the identify on
182 | // and is based on the zoom level of the map.
183 | // 0: Entities
184 | // 1: Districts
185 | // 2: Zip Codes
186 |
187 | var level = this.view.get("zoom");
188 | this.identifyParams.layerIds = [this.config.entityDistrictLayer];
189 |
190 | this.identifyTask.execute(this.identifyParams).then(
191 | lang.partial(dojo.hitch(this.infoGrid,this.infoGrid.populate),evt.mapPoint),
192 | buildProject.displayError
193 | );
194 | }
195 | });
196 | });
--------------------------------------------------------------------------------
/web/js/buildProject/Toolbar.js:
--------------------------------------------------------------------------------
1 | /*global define, dojo,dijit,esri,buildProject,site*/
2 |
3 | define([
4 | "dojo/_base/declare",
5 | "dojo/_base/kernel",
6 | "dojo/_base/lang",
7 | "dojo/dom",
8 | "dojo/on",
9 | "dojo/dnd/Moveable",
10 | "esri/PopupTemplate",
11 | "esri/layers/MapImageLayer",
12 | "esri/layers/TileLayer",
13 | "esri/symbols/SimpleMarkerSymbol",
14 | "esri/tasks/support/IdentifyParameters",
15 | "esri/tasks/IdentifyTask",
16 | // Our Project's classes ---------------------------------------------
17 | "./buildProject",
18 | "./TravelRingTool",
19 | // Widget base classes -----------------------------------------------
20 | "dijit/_WidgetBase",
21 | "dijit/_TemplatedMixin",
22 | "dijit/_WidgetsInTemplateMixin",
23 | // Widget template ---------------------------------------------------
24 | "dojo/text!./templates/Toolbar.html",
25 | // Widgets in template (do not need to be included in function () ----
26 | "dijit/form/Button"
27 | ], function (
28 | declare,
29 | kernel,
30 | lang,
31 | dom,
32 | on,
33 | Moveable,
34 | PopupTemplate,
35 | MapImageLayer,
36 | TileLayer,
37 | SimpleMarkerSymbol,
38 | IdentifyParameters,
39 | IdentifyTask,
40 | buildProject,
41 | TravelRingTool,
42 | _WidgetBase,
43 | _TemplatedMixin,
44 | _WidgetsInTemplateMixin,
45 | template) {
46 | return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
47 | // summary:
48 | // Toolbar widget. Also handles the activation of several tools.
49 | // templateString: String
50 | // HTML template of the widget (imported using dojo/text)
51 | // streetMapLayer: esri.layers.TileLayer
52 | // Transportation layer to be displayed on Toggle Streets
53 | // viewingStreets: boolean
54 | // Flag to keep track of which layers should be on the map
55 | // viewingAssets: boolean
56 | // Flag to keep track of which layers should be on the map
57 | // travelRingTool: buildProject.TravelRingTool
58 | // Tool for adding a travel ring to the map.
59 | // identifyTask: esri.tasks.IdentifyTasks
60 | // Identify task used for the assets layer.
61 | // identifyParams: esri.tasks.IdentifyParameters
62 | // Parameters used for the assets layer identify task.
63 | // assetConnect: dojo.connect
64 | // Keeps track of the onclick event for the assets layer.
65 | templateString : template,
66 | streetMapLayer: null,
67 | viewingStreets: false,
68 | viewingAssets: false,
69 | travelRingTool: null,
70 | identifyTask: null,
71 | identifyParams: null,
72 | assetConnect: null,
73 | postCreate: function(){
74 | // summary:
75 | // Runs after the widget is completely formed.
76 | // description:
77 | // Runs after the widget is completely formed. Sets up the floating behavior.
78 |
79 | var moveable = new Moveable(this.domNode,{handle:this.header});
80 |
81 | var setAssetButtonState = lang.hitch(this,function(zoom){
82 | if (zoom <= 6){
83 | this.toggleAssetsButton.set("disabled",true);
84 | } else {
85 | this.toggleAssetsButton.set("disabled",false);
86 | }
87 | });
88 |
89 | // Set initial assets Button state
90 | setAssetButtonState(this.view.get("zoom"));
91 | //reset assets
92 | this.view.watch("zoom", setAssetButtonState);
93 | },
94 | toggleStreetMap: function(){
95 | // summary:
96 | // Turns the street map on and off when the appropriate button is clicked.
97 | // Also makes sure the zip code layer is hidden when the street map is not.
98 |
99 |
100 | this._createStreetMapLayer();
101 |
102 | if (this.viewingStreets){
103 | this._hideStreetMapLayer();
104 | } else {
105 | this._showStreetMapLayer();
106 | }
107 |
108 | this.viewingStreets = !this.viewingStreets;
109 | },
110 | _createStreetMapLayer: function(){
111 | if (!this.streetMapLayer){
112 | this.streetMapLayer = new TileLayer({
113 | "url": this.config.transportationUrl,
114 | "visible": false
115 | });
116 |
117 | this.map.add(this.streetMapLayer);
118 | }
119 | },
120 | _hideStreetMapLayer: function(){
121 | this.streetMapLayer.set("visible",false);
122 | this.toggleStreetsButton.set("label","Show Transportation");
123 | },
124 | _showStreetMapLayer: function(){
125 | this.streetMapLayer.set("visible",true);
126 | this.toggleStreetsButton.set("label","Hide Transportation");
127 | },
128 | toggleAssetLayer: function(){
129 | // summary:
130 | // Turns the asset layer on and off when the appropriate button is clicked.
131 | // description:
132 | // Turns the asset layer on and off when the appropriate button is clicked.
133 | // There is a click to identify behavior associated with the assets layer. This
134 | // function also handles the toggling of that and ensures the right layer is being
135 | // used for click to identify.
136 |
137 | if (!this.assetLayer){
138 | this.assetLayer = new MapImageLayer({
139 | "url": this.config.assetsUrl,
140 | "sublayers": [
141 | {
142 | id: 0,
143 | visible: true
144 | }
145 | ]
146 | });
147 |
148 | this.map.add(this.assetLayer);
149 | }
150 | if (this.viewingAssets){
151 |
152 | this.assetLayer.set("visible",false);
153 | this.toggleAssetsButton.set("label","Show Assets");
154 | this.disableAssetConnect();
155 | kernel.global.site.enableIdentifyConnect();
156 |
157 | } else {
158 | this.assetLayer.set("visible",true);
159 | this.toggleAssetsButton.set("label","Hide Assets");
160 |
161 | if (!this.identifyTask){
162 | this.identifyTask = new IdentifyTask(this.config.assetsUrl);
163 |
164 | this.identifyParams = new IdentifyParameters();
165 |
166 | this.identifyParams.tolerance = 2;
167 | this.identifyParams.layerIds = [0];
168 | this.identifyParams.returnGeometry = true;
169 | this.identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
170 | }
171 | this.enableAssetConnect();
172 | kernel.global.site.disableIdentifyConnect();
173 |
174 | }
175 |
176 |
177 |
178 | this.viewingAssets = !this.viewingAssets;
179 | },
180 | enableAssetConnect: function(){
181 | // summary:
182 | // Enables the identify connect behavior for asset layers.
183 |
184 | // Make sure the sites identify connect is turned off.
185 | kernel.global.site.disableIdentifyConnect();
186 |
187 | this.assetConnect = this.map.on("click", lang.hitch(this,function(evt){
188 | this.identifyParams.geometry = evt.mapPoint;
189 | this.identifyParams.mapExtent = this.map.extent;
190 |
191 | // when the identify task is completed we create a poopup for the given asset.
192 | this.identifyTask.execute(this.identifyParams,lang.hitch(this,function(identifyResults){
193 | if (identifyResults.length === 0){
194 | buildProject.displayError("No assets found at click location");
195 | } else {
196 | var feature = identifyResults[0].feature;
197 | feature.set("symbol",new SimpleMarkerSymbol());
198 | feature.set("popupTemplate",new PopupTemplate({"title":"Asset","content":"${*}"}));
199 |
200 | this.view.graphics.add(feature);
201 | var screenPt = this.map.toScreen(feature.geometry);
202 |
203 | var popup = this.view.get("popup");
204 | popup.set("title","Asset");
205 | popup.set("content",feature.getContent());
206 | popup.show(screenPt,this.map.getInfoWindowAnchor(screenPt));
207 | }
208 | }),buildProject.displayError);
209 | }));
210 |
211 |
212 | },
213 | disableAssetConnect: function(){
214 | // summary:
215 | // Disables the identify connect behavior for asset layers.
216 |
217 | this.view.get("popup").set("visible",false);
218 | this.assetConnect.remove();
219 | },
220 | toggleTravelRingTool: function(){
221 | // summary:
222 | // Turns the travel ring tool on and off when the appropriate button is clicked.
223 |
224 | if (!this.travelRingTool){
225 | this.travelRingTool = new TravelRingTool({
226 | map:this.map,
227 | config:this.config,
228 | toolbar:this,
229 | "view": this.view});
230 | }
231 | if (this.travelRingTool.isActive){
232 | this.toggleTravelRingButton.containerNode.style.fontWeight = "";
233 | this.toggleTravelRingButton.domNode.firstChild.style.backgroundColor = "";
234 | this.travelRingTool.deactivate();
235 | } else {
236 | this.toggleTravelRingButton.containerNode.style.fontWeight = "bold";
237 | this.toggleTravelRingButton.domNode.firstChild.style.backgroundColor = "#AFD9FF";
238 | this.travelRingTool.activate();
239 | }
240 | },
241 | clearGraphics: function(){
242 | // summary:
243 | // Clears all graphics from the map.
244 |
245 | this.view.graphics.removeAll();
246 | this.hidePopup();
247 | },
248 | hidePopup: function(){
249 | this.view.get("popup").set("visible",false);
250 | }
251 | });
252 | });
--------------------------------------------------------------------------------
/web/js/buildProject/ToolbarSkeleton.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | "dojo/_base/declare",
4 | "dojo/on",
5 | "dojo/_base/lang"
6 | ],
7 | function(declare, on, lang) {
8 | return {
9 | postCreate: function(){
10 |
11 | this.makeToolbarDraggable();
12 |
13 | on(this.toggleTransportationButton,"click",lang.hitch(this,this.toggleTransportation));
14 |
15 | on(this.toggleAssetsButton,"click",lang.hitch(this,this.toggleAssets));
16 |
17 | on(this.createTravelRingButton,"click",lang.hitch(this,this.toggleTravelRingTool));
18 |
19 | on(this.clearGraphicsButton,"click",lang.hitch(this,this.clearGraphics));
20 | },
21 | makeToolbarDraggable: function(){
22 | },
23 | toggleTransportation: function(){
24 | if(this.isTransportationVisible()){
25 | this.hideTransportation();
26 | } else {
27 | this.showTransportation();
28 | }
29 | },
30 | isTransportationVisible: function(){
31 | },
32 | hideTransportation: function(){
33 | },
34 | showTransportation: function(){
35 | },
36 | toggleAssetsButton: function(){
37 | if (this.areAssetsVisible()){
38 | this.hideAssets();
39 | } else {
40 | this.showAssets();
41 | }
42 | },
43 | areAssetsVisible: function(){
44 | },
45 | hideAssets: function(){
46 | },
47 | showAssets: function(){
48 | },
49 | toggleTravelRingTool: function(){
50 | if (this.isTravelRingToolActive()){
51 | this.activateTravelRingTool();
52 | } else {
53 | this.deactivateTravelRingTool();
54 | }
55 | },
56 | isTravelRingToolActive: function(){
57 | },
58 | activateTravelRingTool: function(){
59 | },
60 | deactivateTravelRingTool: function(){
61 | },
62 | clearGraphics: function() {
63 | }
64 | };
65 | }
66 | );
--------------------------------------------------------------------------------
/web/js/buildProject/TravelRingDialog.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 |
3 | define([
4 | "dojo/_base/Color",
5 | "dojo/_base/declare",
6 | "dojo/_base/lang",
7 | "esri/Graphic",
8 | "esri/symbols/SimpleFillSymbol",
9 | "esri/symbols/SimpleLineSymbol",
10 | "esri/symbols/SimpleMarkerSymbol",
11 | "esri/tasks/support/FeatureSet",
12 | // Our Project's classes ---------------------------------------------
13 | "./buildProject",
14 | // Widget base classes -----------------------------------------------
15 | "dijit/_WidgetBase",
16 | "dijit/_TemplatedMixin",
17 | "dijit/_WidgetsInTemplateMixin",
18 | // Widget template ---------------------------------------------------
19 | "dojo/text!./templates/_TravelRingDialog.html",
20 | // Widgets in template (do not need to be included in function () ----
21 | "dijit/Dialog",
22 | "dijit/form/NumberSpinner",
23 | "dojox/form/BusyButton"
24 | ], function (
25 | Color,
26 | declare,
27 | lang,
28 | Graphic,
29 | SimpleFillSymbol,
30 | SimpleLineSymbol,
31 | SimpleMarkerSymbol,
32 | FeatureSet,
33 | buildProject,
34 | _WidgetBase,
35 | _TemplatedMixin,
36 | _WidgetsInTemplateMixin,
37 | template) {
38 | return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
39 | // summary:
40 | // Internal dialog used by the Travel Ring Tool.
41 | // description:
42 | // This dialog handles all the major functionality of the Travel Ring
43 | // and accepts user input.
44 | // templateString: String
45 | // HTML template of the widget (imported using dojo/text)
46 | // geometry: esri.geometry.Point
47 | // Point to draw the travel ring around.
48 | templateString : template,
49 | geometry: null,
50 |
51 | show: function(/*esri.geometry.Point*/geometry){
52 | // summary:
53 | // Opens the dialog.
54 | // geometry: esri.geometry.Point
55 | // Point to draw the travel ring around.
56 |
57 | this.innerDialog.show();
58 | this.geometry = geometry;
59 | this.submitButton.cancel();
60 | },
61 | getRing: function(/*Event*/evt){
62 | // summary:
63 | // Once the user has submitted the form, this function creates the travel ring.
64 | // evt: Event
65 | // Click event on the submit button.
66 |
67 | // First use dijit to make sure the form is valid
68 | if (this.timeInput.isValid()){
69 | var featureSet = new FeatureSet();
70 | featureSet.geometryType = "point";
71 | featureSet.features = [new Graphic({
72 | "geometry":this.geometry,
73 | "symbol": new SimpleMarkerSymbol(),
74 | "attributes": {}
75 | })];
76 |
77 | var inputParams = {
78 | "Input_Location": featureSet,
79 | "Drive_Times": this.timeInput.get("value")
80 | };
81 |
82 | // Submit the job and check on its results once the tool returns a completion message.
83 | this.driveTimesTask.execute(inputParams).then(lang.hitch(this,function(response){
84 |
85 | console.debug("FINISHED WITH EXECUTE");
86 | console.debug(response);
87 | // Add the input points and result polygons to the map.
88 | // Note: This function loops through even though there will only be one polygon.
89 | // This will make it easier to add multiple points or the option to enter
90 | // multiple time values in the future.
91 |
92 | var results = response.results;
93 | try{
94 | var polygons = results[0];
95 | for (var i=0;i
2 |