├── .gitignore
├── .jshintrc
├── Examples
├── .gitignore
├── Build
│ └── amd.min.js
├── README.md
├── Source
│ ├── SpirographPositionProperty.js
│ ├── SpirographPositionProperty_amd-build.js
│ ├── SpirographPositionProperty_amd-source.js
│ ├── amd
│ │ ├── main-build.js
│ │ └── main-source.js
│ └── mainConfig.js
├── amd_build.html
├── amd_except_cesium.html
├── amd_source.html
├── build.js
├── index.html
├── models
│ ├── Cesium_Air.glb
│ └── Cesium_Ground.glb
├── server.js
├── sources.html
└── standalone.html
├── README.md
├── Source
├── CesiumNavigation.js
├── Core
│ ├── KnockoutHammerBinding.js
│ ├── KnockoutMarkdownBinding.js
│ ├── Utils.js
│ ├── createFragmentFromTemplate.js
│ ├── loadView.js
│ └── registerKnockoutBindings.js
├── Styles
│ ├── Core.less
│ ├── DistanceLegend.less
│ ├── Floating.less
│ ├── Navigation.less
│ └── cesium-navigation.less
├── SvgPaths
│ ├── svgCompassGyro.js
│ ├── svgCompassOuterRing.js
│ ├── svgCompassRotationMarker.js
│ └── svgReset.js
├── ViewModels
│ ├── DistanceLegendViewModel.js
│ ├── NavigationControl.js
│ ├── NavigationViewModel.js
│ ├── ResetViewNavigationControl.js
│ ├── UserInterfaceControl.js
│ └── ZoomNavigationControl.js
├── copyrightHeader.js
└── viewerCesiumNavigationMixin.js
├── bower.json
├── build.js
├── mainConfig.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | Thumbs.db
3 | node_modules/*
4 | *~
5 | bower_components/*
6 | node_modules/*
7 |
8 | # Created by https://www.gitignore.io/api/webstorm,netbeans,eclipse
9 |
10 | ### WebStorm ###
11 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
12 |
13 | *.iml
14 |
15 | ## Directory-based project format:
16 | .idea/
17 | # if you remove the above rule, at least ignore the following:
18 |
19 | # User-specific stuff:
20 | # .idea/workspace.xml
21 | # .idea/tasks.xml
22 | # .idea/dictionaries
23 | # .idea/shelf
24 |
25 | # Sensitive or high-churn files:
26 | # .idea/dataSources.ids
27 | # .idea/dataSources.xml
28 | # .idea/sqlDataSources.xml
29 | # .idea/dynamic.xml
30 | # .idea/uiDesigner.xml
31 |
32 | # Gradle:
33 | # .idea/gradle.xml
34 | # .idea/libraries
35 |
36 | # Mongo Explorer plugin:
37 | # .idea/mongoSettings.xml
38 |
39 | ## File-based project format:
40 | *.ipr
41 | *.iws
42 |
43 | ## Plugin-specific files:
44 |
45 | # IntelliJ
46 | /out/
47 |
48 | # mpeltonen/sbt-idea plugin
49 | .idea_modules/
50 |
51 | # JIRA plugin
52 | atlassian-ide-plugin.xml
53 |
54 | # Crashlytics plugin (for Android Studio and IntelliJ)
55 | com_crashlytics_export_strings.xml
56 | crashlytics.properties
57 | crashlytics-build.properties
58 | fabric.properties
59 |
60 |
61 | ### NetBeans ###
62 | nbproject/private/
63 | build/
64 | nbbuild/
65 | dist/
66 | nbdist/
67 | nbactions.xml
68 | .nb-gradle/
69 |
70 |
71 | ### Eclipse ###
72 |
73 | .metadata
74 | bin/
75 | tmp/
76 | *.tmp
77 | *.bak
78 | *.swp
79 | *~.nib
80 | local.properties
81 | .settings/
82 | .loadpath
83 |
84 | # Eclipse Core
85 | .project
86 |
87 | # External tool builders
88 | .externalToolBuilders/
89 |
90 | # Locally stored "Eclipse launch configurations"
91 | *.launch
92 |
93 | # PyDev specific (Python IDE for Eclipse)
94 | *.pydevproject
95 |
96 | # CDT-specific (C/C++ Development Tooling)
97 | .cproject
98 |
99 | # JDT-specific (Eclipse Java Development Tools)
100 | .classpath
101 |
102 | # Java annotation processor (APT)
103 | .factorypath
104 |
105 | # PDT-specific (PHP Development Tools)
106 | .buildpath
107 |
108 | # sbteclipse plugin
109 | .target
110 |
111 | # TeXlipse plugin
112 | .texlipse
113 |
114 | # STS (Spring Tool Suite)
115 | .springBeans
116 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "bitwise": false,
3 | "camelcase": false,
4 | "curly": true,
5 | "eqeqeq": true,
6 | "es3": true,
7 | "forin": true,
8 | "immed": true,
9 | "latedef": true,
10 | "newcap": true,
11 | "noarg": true,
12 | "noempty": false,
13 | "nonew": true,
14 | "plusplus": false,
15 | "quotmark": false,
16 | "regexp": false,
17 | "undef": true,
18 | "unused": false,
19 | "strict": true,
20 | "trailing": true,
21 | "asi": false,
22 | "boss": false,
23 | "debug": false,
24 | "eqnull": false,
25 | "esnext": false,
26 | "evil": false,
27 | "expr": false,
28 | "funcscope": false,
29 | "globalstrict": false,
30 | "iterator": false,
31 | "lastsemic": false,
32 | "laxbreak": false,
33 | "laxcomma": false,
34 | "loopfunc": false,
35 | "moz": false,
36 | "multistr": true,
37 | "proto": false,
38 | "regexdash": false,
39 | "scripturl": false,
40 | "smarttabs": false,
41 | "shadow": false,
42 | "sub": false,
43 | "supernew": false,
44 | "browser": true
45 | }
--------------------------------------------------------------------------------
/Examples/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | Thumbs.db
3 | node_modules/*
4 | *~
5 |
--------------------------------------------------------------------------------
/Examples/README.md:
--------------------------------------------------------------------------------
1 | Missing files
2 | ------------
3 |
4 | These examples are using Cesium and RequireJS so you have to run `npm install` to get these.
5 | The AMD example needs to be built in advance. To do so run `node build.js` from the `Examples` root directory
6 |
7 |
8 | Where are the dependencies from?
9 | ------------
10 |
11 | The root directory of the server is `Examples` but some files from the parent/main directory are needed.
12 | This is achieved by internal redirects:
13 | - `/` -> `../Source` (note that the mapping `/` -> `/` still exists)
14 | - `/dist` -> `../dist`
15 | - `/node_modules` -> `../node_modules`
16 | - `/bower_components` -> `../bower_components`
17 | - `/cesiumNavigationMainConfig` -> `../mainConfig.js`
18 |
19 | Using these redirects ensures that the examples are always running with the current build and/or sources of the main project.
20 | Furthermore it avoids redundant node modules and/or bower components
21 |
22 |
23 | Local server
24 | ------------
25 |
26 | A local HTTP server is required to run the app.
27 |
28 | Use the node.js server. To start it change to the `Examples` root directory and run
29 | `node server.js`
30 |
31 | Then browse to `http://localhost:8080/`
32 |
--------------------------------------------------------------------------------
/Examples/Source/SpirographPositionProperty.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by G.Cordes on 01.06.16.
3 | */
4 |
5 | (function (Cesium) {
6 | /**
7 | * A position property that simulates a spirograph
8 | * @constructor
9 | *
10 | * @param {Cesium.Cartographic} center The center of the spirograph
11 | * @param {Number} radiusMedian The radius of the median circle
12 | * @param {Number} radiusSubCircle the maximum distance to the median circle
13 | * @param {Number} durationMedianCircle The duration in milliseconds to orbit the median circle
14 | * @param {Number} durationSubCircle The duration in milliseconds to orbit the sub circle
15 | * @param {Cesium.Ellipsoid} [ellipsoid=Cesium.Ellipsoid.WGS84] The ellipsoid to convert cartographic to cartesian
16 | */
17 | var SpirographPositionProperty = function (center, radiusMedian, radiusSubCircle, durationMedianCircle, durationSubCircle, ellipsoid) {
18 | this._center = center;
19 | this._radiusMedian = radiusMedian;
20 | this._radiusSubCircle = radiusSubCircle;
21 |
22 | this._durationMedianCircle = durationMedianCircle;
23 | this._durationSubCircle = durationSubCircle;
24 |
25 | if (!Cesium.defined(ellipsoid)) {
26 | ellipsoid = Cesium.Ellipsoid.WGS84;
27 | }
28 | this._ellipsoid = ellipsoid;
29 |
30 | this._definitionChanged = new Cesium.Event();
31 | };
32 |
33 | Cesium.defineProperties(SpirographPositionProperty.prototype, {
34 | /**
35 | * Gets a value indicating if this property is constant. A property is considered
36 | * constant if getValue always returns the same result for the current definition.
37 | * @memberof PositionProperty.prototype
38 | *
39 | * @type {Boolean}
40 | * @readonly
41 | */
42 | isConstant: {
43 | get: function () {
44 | return this._radiusMedian == 0 && this._radiusSubCircle == 0;
45 | }
46 | },
47 | /**
48 | * Gets the event that is raised whenever the definition of this property changes.
49 | * The definition is considered to have changed if a call to getValue would return
50 | * a different result for the same time.
51 | * @memberof PositionProperty.prototype
52 | *
53 | * @type {Event}
54 | * @readonly
55 | */
56 | definitionChanged: {
57 | get: function () {
58 | return this._definitionChanged;
59 | }
60 | },
61 | /**
62 | * Gets the reference frame that the position is defined in.
63 | * @memberof PositionProperty.prototype
64 | * @type {ReferenceFrame}
65 | */
66 | referenceFrame: {
67 | get: function () {
68 | return Cesium.ReferenceFrame.FIXED;
69 | }
70 | }
71 | });
72 |
73 | /**
74 | * Gets the value of the property at the provided time in the fixed frame.
75 | * @function
76 | *
77 | * @param {JulianDate} time The time for which to retrieve the value.
78 | * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
79 | * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
80 | */
81 | SpirographPositionProperty.prototype.getValue = function (time, result) {
82 | return this.getValueInReferenceFrame(time, Cesium.ReferenceFrame.FIXED, result);
83 | };
84 |
85 | var cartographicScratch = new Cesium.Cartographic();
86 |
87 | /**
88 | * Gets the value of the property at the provided time and in the provided reference frame.
89 | * @function
90 | *
91 | * @param {JulianDate} time The time for which to retrieve the value.
92 | * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
93 | * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
94 | * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
95 | */
96 | SpirographPositionProperty.prototype.getValueInReferenceFrame = function (time, referenceFrame, result) {
97 | var milliseconds = Cesium.JulianDate.toDate(time).getTime();
98 |
99 | var radius = this._radiusMedian + this._radiusSubCircle * Math.sin(2 * Math.PI * (milliseconds / this._durationSubCircle));
100 |
101 | cartographicScratch.latitude = this._center.latitude + radius * Math.cos(2 * Math.PI * (milliseconds / this._durationMedianCircle));
102 | cartographicScratch.longitude = this._center.longitude + radius * Math.sin(2 * Math.PI * (milliseconds / this._durationMedianCircle));
103 | cartographicScratch.height = this._center.height;
104 |
105 | result = this._ellipsoid.cartographicToCartesian(cartographicScratch, result);
106 |
107 | if (referenceFrame == Cesium.ReferenceFrame.FIXED) {
108 | return result;
109 | }
110 |
111 | return Cesium.PositionProperty.convertToReferenceFrame(time, result, Cesium.ReferenceFrame.FIXED, referenceFrame, result);
112 | };
113 |
114 | /**
115 | * Compares this property to the provided property and returns
116 | * true
if they are equal, false
otherwise.
117 | * @function
118 | *
119 | * @param {Property} [other] The other property.
120 | * @returns {Boolean} true
if left and right are equal, false
otherwise.
121 | */
122 | SpirographPositionProperty.prototype.equals = function (other) {
123 | return other instanceof SpirographPositionProperty
124 | && this._center.equals(other._center)
125 | && this._radiusMedian == other._radiusMedian
126 | && this._radiusSubCircle == other._radiusSubCircle
127 | && this._durationMedianCircle == other._durationMedianCircle
128 | && this._durationSubCircle == other._durationSubCircle
129 | && this._ellipsoid.equals(other._ellipsoid);
130 | };
131 |
132 | Cesium.SpirographPositionProperty = SpirographPositionProperty;
133 |
134 | })(Cesium);
--------------------------------------------------------------------------------
/Examples/Source/SpirographPositionProperty_amd-build.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by G.Cordes on 01.06.16.
3 | */
4 |
5 | define([
6 | 'Cesium'
7 | ], function (Cesium) {
8 | "use strict";
9 |
10 | /**
11 | * A position property that simulates a spirograph
12 | * @constructor
13 | *
14 | * @param {Cesium.Cartographic} center The center of the spirograph
15 | * @param {Number} radiusMedian The radius of the median circle
16 | * @param {Number} radiusSubCircle the maximum distance to the median circle
17 | * @param {Number} durationMedianCircle The duration in milliseconds to orbit the median circle
18 | * @param {Number} durationSubCircle The duration in milliseconds to orbit the sub circle
19 | * @param {Cesium.Ellipsoid} [ellipsoid=Cesium.Ellipsoid.WGS84] The ellipsoid to convert cartographic to cartesian
20 | */
21 | var SpirographPositionProperty = function(center, radiusMedian, radiusSubCircle, durationMedianCircle, durationSubCircle, ellipsoid) {
22 | this._center = center;
23 | this._radiusMedian = radiusMedian;
24 | this._radiusSubCircle = radiusSubCircle;
25 |
26 | this._durationMedianCircle = durationMedianCircle;
27 | this._durationSubCircle = durationSubCircle;
28 |
29 | if(!Cesium.defined(ellipsoid)) {
30 | ellipsoid = Cesium.Ellipsoid.WGS84;
31 | }
32 | this._ellipsoid = ellipsoid;
33 |
34 | this._definitionChanged = new Cesium.Event();
35 | };
36 |
37 | Cesium.defineProperties(SpirographPositionProperty.prototype, {
38 | /**
39 | * Gets a value indicating if this property is constant. A property is considered
40 | * constant if getValue always returns the same result for the current definition.
41 | * @memberof PositionProperty.prototype
42 | *
43 | * @type {Boolean}
44 | * @readonly
45 | */
46 | isConstant : {
47 | get : function() {
48 | return this._radiusMedian == 0 && this._radiusSubCircle == 0;
49 | }
50 | },
51 | /**
52 | * Gets the event that is raised whenever the definition of this property changes.
53 | * The definition is considered to have changed if a call to getValue would return
54 | * a different result for the same time.
55 | * @memberof PositionProperty.prototype
56 | *
57 | * @type {Event}
58 | * @readonly
59 | */
60 | definitionChanged : {
61 | get : function() {
62 | return this._definitionChanged;
63 | }
64 | },
65 | /**
66 | * Gets the reference frame that the position is defined in.
67 | * @memberof PositionProperty.prototype
68 | * @type {ReferenceFrame}
69 | */
70 | referenceFrame : {
71 | get : function() {
72 | return Cesium.ReferenceFrame.FIXED;
73 | }
74 | }
75 | });
76 |
77 | /**
78 | * Gets the value of the property at the provided time in the fixed frame.
79 | * @function
80 | *
81 | * @param {JulianDate} time The time for which to retrieve the value.
82 | * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
83 | * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
84 | */
85 | SpirographPositionProperty.prototype.getValue = function(time, result) {
86 | return this.getValueInReferenceFrame(time, Cesium.ReferenceFrame.FIXED, result);
87 | };
88 |
89 | var cartographicScratch = new Cesium.Cartographic();
90 |
91 | /**
92 | * Gets the value of the property at the provided time and in the provided reference frame.
93 | * @function
94 | *
95 | * @param {JulianDate} time The time for which to retrieve the value.
96 | * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
97 | * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
98 | * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
99 | */
100 | SpirographPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
101 | var milliseconds = Cesium.JulianDate.toDate(time).getTime();
102 |
103 | var radius = this._radiusMedian + this._radiusSubCircle * Math.sin(2 * Math.PI * (milliseconds / this._durationSubCircle));
104 |
105 | cartographicScratch.latitude = this._center.latitude + radius * Math.cos(2 * Math.PI * (milliseconds / this._durationMedianCircle));
106 | cartographicScratch.longitude = this._center.longitude + radius * Math.sin(2 * Math.PI * (milliseconds / this._durationMedianCircle));
107 | cartographicScratch.height = this._center.height;
108 |
109 | result = this._ellipsoid.cartographicToCartesian(cartographicScratch, result);
110 |
111 | if(referenceFrame == Cesium.ReferenceFrame.FIXED) {
112 | return result;
113 | }
114 |
115 | return Cesium.PositionProperty.convertToReferenceFrame(time, result, Cesium.ReferenceFrame.FIXED, referenceFrame, result);
116 | };
117 |
118 | /**
119 | * Compares this property to the provided property and returns
120 | * true
if they are equal, false
otherwise.
121 | * @function
122 | *
123 | * @param {Property} [other] The other property.
124 | * @returns {Boolean} true
if left and right are equal, false
otherwise.
125 | */
126 | SpirographPositionProperty.prototype.equals = function(other) {
127 | return other instanceof SpirographPositionProperty
128 | && this._center.equals(other._center)
129 | && this._radiusMedian == other._radiusMedian
130 | && this._radiusSubCircle == other._radiusSubCircle
131 | && this._durationMedianCircle == other._durationMedianCircle
132 | && this._durationSubCircle == other._durationSubCircle
133 | && this._ellipsoid.equals(other._ellipsoid);
134 | };
135 |
136 | return SpirographPositionProperty;
137 | });
--------------------------------------------------------------------------------
/Examples/Source/SpirographPositionProperty_amd-source.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by G.Cordes on 01.06.16.
3 | */
4 |
5 | define([
6 | 'Cesium/Cesium'
7 | ], function (Cesium) {
8 | "use strict";
9 |
10 | /**
11 | * A position property that simulates a spirograph
12 | * @constructor
13 | *
14 | * @param {Cesium.Cartographic} center The center of the spirograph
15 | * @param {Number} radiusMedian The radius of the median circle
16 | * @param {Number} radiusSubCircle the maximum distance to the median circle
17 | * @param {Number} durationMedianCircle The duration in milliseconds to orbit the median circle
18 | * @param {Number} durationSubCircle The duration in milliseconds to orbit the sub circle
19 | * @param {Cesium.Ellipsoid} [ellipsoid=Cesium.Ellipsoid.WGS84] The ellipsoid to convert cartographic to cartesian
20 | */
21 | var SpirographPositionProperty = function(center, radiusMedian, radiusSubCircle, durationMedianCircle, durationSubCircle, ellipsoid) {
22 | this._center = center;
23 | this._radiusMedian = radiusMedian;
24 | this._radiusSubCircle = radiusSubCircle;
25 |
26 | this._durationMedianCircle = durationMedianCircle;
27 | this._durationSubCircle = durationSubCircle;
28 |
29 | if(!Cesium.defined(ellipsoid)) {
30 | ellipsoid = Cesium.Ellipsoid.WGS84;
31 | }
32 | this._ellipsoid = ellipsoid;
33 |
34 | this._definitionChanged = new Cesium.Event();
35 | };
36 |
37 | Cesium.defineProperties(SpirographPositionProperty.prototype, {
38 | /**
39 | * Gets a value indicating if this property is constant. A property is considered
40 | * constant if getValue always returns the same result for the current definition.
41 | * @memberof PositionProperty.prototype
42 | *
43 | * @type {Boolean}
44 | * @readonly
45 | */
46 | isConstant : {
47 | get : function() {
48 | return this._radiusMedian == 0 && this._radiusSubCircle == 0;
49 | }
50 | },
51 | /**
52 | * Gets the event that is raised whenever the definition of this property changes.
53 | * The definition is considered to have changed if a call to getValue would return
54 | * a different result for the same time.
55 | * @memberof PositionProperty.prototype
56 | *
57 | * @type {Event}
58 | * @readonly
59 | */
60 | definitionChanged : {
61 | get : function() {
62 | return this._definitionChanged;
63 | }
64 | },
65 | /**
66 | * Gets the reference frame that the position is defined in.
67 | * @memberof PositionProperty.prototype
68 | * @type {ReferenceFrame}
69 | */
70 | referenceFrame : {
71 | get : function() {
72 | return Cesium.ReferenceFrame.FIXED;
73 | }
74 | }
75 | });
76 |
77 | /**
78 | * Gets the value of the property at the provided time in the fixed frame.
79 | * @function
80 | *
81 | * @param {JulianDate} time The time for which to retrieve the value.
82 | * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
83 | * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
84 | */
85 | SpirographPositionProperty.prototype.getValue = function(time, result) {
86 | return this.getValueInReferenceFrame(time, Cesium.ReferenceFrame.FIXED, result);
87 | };
88 |
89 | var cartographicScratch = new Cesium.Cartographic();
90 |
91 | /**
92 | * Gets the value of the property at the provided time and in the provided reference frame.
93 | * @function
94 | *
95 | * @param {JulianDate} time The time for which to retrieve the value.
96 | * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
97 | * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
98 | * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
99 | */
100 | SpirographPositionProperty.prototype.getValueInReferenceFrame = function(time, referenceFrame, result) {
101 | var milliseconds = Cesium.JulianDate.toDate(time).getTime();
102 |
103 | var radius = this._radiusMedian + this._radiusSubCircle * Math.sin(2 * Math.PI * (milliseconds / this._durationSubCircle));
104 |
105 | cartographicScratch.latitude = this._center.latitude + radius * Math.cos(2 * Math.PI * (milliseconds / this._durationMedianCircle));
106 | cartographicScratch.longitude = this._center.longitude + radius * Math.sin(2 * Math.PI * (milliseconds / this._durationMedianCircle));
107 | cartographicScratch.height = this._center.height;
108 |
109 | result = this._ellipsoid.cartographicToCartesian(cartographicScratch, result);
110 |
111 | if(referenceFrame == Cesium.ReferenceFrame.FIXED) {
112 | return result;
113 | }
114 |
115 | return Cesium.PositionProperty.convertToReferenceFrame(time, result, Cesium.ReferenceFrame.FIXED, referenceFrame, result);
116 | };
117 |
118 | /**
119 | * Compares this property to the provided property and returns
120 | * true
if they are equal, false
otherwise.
121 | * @function
122 | *
123 | * @param {Property} [other] The other property.
124 | * @returns {Boolean} true
if left and right are equal, false
otherwise.
125 | */
126 | SpirographPositionProperty.prototype.equals = function(other) {
127 | return other instanceof SpirographPositionProperty
128 | && this._center.equals(other._center)
129 | && this._radiusMedian == other._radiusMedian
130 | && this._radiusSubCircle == other._radiusSubCircle
131 | && this._durationMedianCircle == other._durationMedianCircle
132 | && this._durationSubCircle == other._durationSubCircle
133 | && this._ellipsoid.equals(other._ellipsoid);
134 | };
135 |
136 | return SpirographPositionProperty;
137 | });
--------------------------------------------------------------------------------
/Examples/Source/amd/main-build.js:
--------------------------------------------------------------------------------
1 | require([
2 | 'Cesium',
3 | 'Source/SpirographPositionProperty_amd-build',
4 | 'viewerCesiumNavigationMixin'
5 | ], function(
6 | Cesium,
7 | SpirographPositionProperty,
8 | viewerCesiumNavigationMixin) {
9 | "use strict";
10 |
11 | var cesiumViewer = new Cesium.Viewer('cesiumContainer');
12 |
13 | // extend our view by the cesium navigation mixin
14 | cesiumViewer.extend(viewerCesiumNavigationMixin, {});
15 | // you can access the cesium navigation by cesiumViewer.cesiumNavigation or cesiumViewer.cesiumWidget.cesiumNavigation
16 |
17 | function createSpirographEntity(url, longitude, latitude, height, radiusMedian, radiusSubCircle,
18 | durationMedianCircle, durationSubCircle) {
19 | var centerPosition = Cesium.Cartographic.fromDegrees(longitude, latitude, height);
20 | var spirographPositionProperty = new SpirographPositionProperty(centerPosition, radiusMedian, radiusSubCircle,
21 | durationMedianCircle, durationSubCircle, cesiumViewer.scene.globe.ellipsoid);
22 |
23 | cesiumViewer.entities.add({
24 | name : url,
25 | description: 'It is supposed to have a useful desciption here
but instead there is just a placeholder to get a larger info box',
26 | position: spirographPositionProperty,
27 | orientation: new Cesium.VelocityOrientationProperty(spirographPositionProperty, cesiumViewer.scene.globe.ellipsoid),
28 | model : {
29 | uri : url,
30 | minimumPixelSize : 96
31 | }
32 | });
33 | }
34 |
35 | createSpirographEntity('models/Cesium_Air.glb', -100, 44, 10000.0,
36 | Cesium.Math.toRadians(0.5), Cesium.Math.toRadians(2), 1e6, 2e5);
37 | createSpirographEntity('models/Cesium_Ground.glb', -122, 45, 0,
38 | Cesium.Math.toRadians(0.1), Cesium.Math.toRadians(1), 5e6, 7e5);
39 | });
--------------------------------------------------------------------------------
/Examples/Source/amd/main-source.js:
--------------------------------------------------------------------------------
1 | require([
2 | 'Cesium/Cesium',
3 | 'Source/SpirographPositionProperty_amd-source',
4 | 'viewerCesiumNavigationMixin'
5 | ], function(
6 | Cesium,
7 | SpirographPositionProperty,
8 | viewerCesiumNavigationMixin) {
9 | "use strict";
10 |
11 | var cesiumViewer = new Cesium.Viewer('cesiumContainer');
12 |
13 | // extend our view by the cesium navigation mixin
14 | cesiumViewer.extend(viewerCesiumNavigationMixin, {});
15 | // you can access the cesium navigation by cesiumViewer.cesiumNavigation or cesiumViewer.cesiumWidget.cesiumNavigation
16 |
17 | function createSpirographEntity(url, longitude, latitude, height, radiusMedian, radiusSubCircle,
18 | durationMedianCircle, durationSubCircle) {
19 | var centerPosition = Cesium.Cartographic.fromDegrees(longitude, latitude, height);
20 | var spirographPositionProperty = new SpirographPositionProperty(centerPosition, radiusMedian, radiusSubCircle,
21 | durationMedianCircle, durationSubCircle, cesiumViewer.scene.globe.ellipsoid);
22 |
23 | cesiumViewer.entities.add({
24 | name : url,
25 | description: 'It is supposed to have a useful desciption here
but instead there is just a placeholder to get a larger info box',
26 | position: spirographPositionProperty,
27 | orientation: new Cesium.VelocityOrientationProperty(spirographPositionProperty, cesiumViewer.scene.globe.ellipsoid),
28 | model : {
29 | uri : url,
30 | minimumPixelSize : 96
31 | }
32 | });
33 | }
34 |
35 | createSpirographEntity('models/Cesium_Air.glb', -100, 44, 10000.0,
36 | Cesium.Math.toRadians(0.5), Cesium.Math.toRadians(2), 1e6, 2e5);
37 | createSpirographEntity('models/Cesium_Ground.glb', -122, 45, 0,
38 | Cesium.Math.toRadians(0.1), Cesium.Math.toRadians(1), 5e6, 7e5);
39 | });
--------------------------------------------------------------------------------
/Examples/Source/mainConfig.js:
--------------------------------------------------------------------------------
1 | requirejs.config({
2 | baseUrl: '.',
3 | paths: {
4 | // IMPORTANT: this path has to be set because
5 | // viewerCesiumNavigationMixin uses 'Cesium/...' for dependencies
6 | Cesium: "../node_modules/cesium/Build/Cesium/Cesium",
7 | viewerCesiumNavigationMixin: "../dist/amd/viewerCesiumNavigationMixin"
8 | },
9 | shim: {
10 | "Cesium": {
11 | exports: "Cesium",
12 | // deps: [
13 | // "require-css!../../node_modules/cesium/Build/Cesium/Widgets/widgets.css"
14 | // ]
15 | }
16 | }
17 | });
--------------------------------------------------------------------------------
/Examples/amd_build.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cesium-Navigation Example (using requirejs.optimize)
5 |
6 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
44 |
45 |
--------------------------------------------------------------------------------
/Examples/amd_except_cesium.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cesium-Navigation Example (using AMD except Cesium)
5 |
6 |
7 |
8 |
14 |
20 |
21 |
22 |
23 |
61 |
62 |
71 |
72 |
--------------------------------------------------------------------------------
/Examples/amd_source.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cesium-Navigation Example (using requirejs.optimize)
5 |
6 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
40 |
41 |
--------------------------------------------------------------------------------
/Examples/build.js:
--------------------------------------------------------------------------------
1 | // This only builds the sources for the example amd.html
2 | // all other examples do not need to be built.
3 |
4 | var requirejs = require('requirejs');
5 |
6 | var config = {
7 | baseUrl: '.',
8 | optimize: 'uglify2',
9 | mainConfigFile: 'Source/mainConfig.js',
10 | name: "Source/amd/main-build",
11 | out: "Build/amd.min.js",
12 | paths: {
13 | // do not include Cesium in the build file but rather access it seperately from browser
14 | Cesium: "empty:"
15 | },
16 | logLevel: 0
17 | };
18 |
19 | requirejs.optimize(config);
--------------------------------------------------------------------------------
/Examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cesium-Navigation Examples
5 |
13 |
14 |
15 | Cesium-Navigation Examples
16 | Five examples are available where the output is always the same concerning only the user interface but they differ in how they were created.
17 |
18 | - Sources Example
19 | - Using the sources without building anything. This is also great for developing/debugging the sources since any changes are available on browser refresh.
20 | - Standalone Example
21 | - No AMD loader is needed but Cesium has to be defined as global variable.
22 | - Using AMD except for Cesium Example
23 | - Using AMD except for Cesium (so Cesium is not accessed via AMD but is a global variable). Since this mixin is accessed via AMD the AMD compatible version is used. The version automatically checks if Cesium is globally accessible and if so it does not try to load Cesium via AMD.
24 | - Asynchronous Module Definition (AMD) without requirejs.optimize Example
25 | - When using the AMD compatible version make sure to set 'Cesium' either to point to the Cesium source directory or to the built Cesium.js file.
26 | - Asynchronous Module Definition (AMD) with requirejs.optimize Example (needs to be built)
27 | - When using the AMD compatible version make sure to set 'Cesium' either to point to the Cesium source directory or to the built Cesium.js file.
28 |
29 |
30 |
39 |
40 |
--------------------------------------------------------------------------------
/Examples/models/Cesium_Air.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Larcius/cesium-navigation/2352771805b082f26df3a0b50a2863fc2ff4ef6e/Examples/models/Cesium_Air.glb
--------------------------------------------------------------------------------
/Examples/models/Cesium_Ground.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Larcius/cesium-navigation/2352771805b082f26df3a0b50a2863fc2ff4ef6e/Examples/models/Cesium_Ground.glb
--------------------------------------------------------------------------------
/Examples/server.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | "use strict";
3 | /*global console,require,__dirname,process*/
4 | /*jshint es3:false*/
5 |
6 | var express = require('express');
7 | var compression = require('compression');
8 | var path = require('path');
9 |
10 | var yargs = require('yargs').options({
11 | 'port' : {
12 | 'default' : process.env.PORT || 8080,
13 | 'description' : 'Port to listen on.'
14 | },
15 | 'public' : {
16 | 'type' : 'boolean',
17 | 'description' : 'Run a public server that listens on all interfaces.'
18 | },
19 | 'help' : {
20 | 'alias' : 'h',
21 | 'type' : 'boolean',
22 | 'description' : 'Show this help.'
23 | }
24 | });
25 | var argv = yargs.argv;
26 |
27 | if (argv.help) {
28 | return yargs.showHelp();
29 | }
30 |
31 | // eventually this mime type configuration will need to change
32 | // https://github.com/visionmedia/send/commit/d2cb54658ce65948b0ed6e5fb5de69d022bef941
33 | var mime = express.static.mime;
34 | mime.define({
35 | 'application/json' : ['czml', 'json', 'geojson', 'topojson', 'gltf'],
36 | 'text/plain' : ['glsl']
37 | });
38 |
39 | var app = express();
40 | app.use(compression());
41 | app.use(express.static(__dirname));
42 | // don't forget to copy necessary files when preparing the gh-pages on github since there is no redirecting
43 | app.use(express.static(path.join(__dirname, '..', 'Source')));
44 | app.use('/cesiumNavigationMainConfig.js', express.static(path.join(__dirname, '..', 'mainConfig.js')));
45 | app.use('/node_modules', express.static(path.join(__dirname, '..', 'node_modules')));
46 | app.use('/Cesium', express.static(path.join(__dirname, '..', 'node_modules/cesium/Build/Cesium')));
47 | app.use('/bower_components', express.static(path.join(__dirname, '..', 'bower_components')));
48 | app.use('/dist', express.static(path.join(__dirname, '..', 'dist')));
49 |
50 | var serverName = 'Cesium navigation examples server';
51 |
52 | var server = app.listen(argv.port, argv.public ? undefined : 'localhost', function() {
53 | if (argv.public) {
54 | console.log(serverName + ' is running publicly.');
55 | console.log('\tConnect to http://\:%d, e.g. http://localhost:%d', server.address().port, server.address().port);
56 | } else {
57 | console.log(serverName + ' is running locally.');
58 | console.log('\tConnect to http://localhost:%d', server.address().port);
59 | }
60 | });
61 |
62 | server.on('error', function (e) {
63 | if (e.code === 'EADDRINUSE') {
64 | console.log('Error: Port %d is already in use, select a different port.', argv.port);
65 | console.log('Example: node server.js --port %d', argv.port + 1);
66 | } else if (e.code === 'EACCES') {
67 | console.log('Error: This process does not have permission to listen on port %d.', argv.port);
68 | if (argv.port < 1024) {
69 | console.log('Try a port number higher than 1024.');
70 | }
71 | }
72 | console.log(e);
73 | process.exit(1);
74 | });
75 |
76 | // Maintain an array of all connected sockets
77 | var sockets = [];
78 | server.on('connection', function (socket) {
79 | // Add a newly connected socket
80 | sockets.push(socket);
81 |
82 | // Remove the socket when it closes
83 | socket.on('close', function () {
84 | sockets.splice(sockets.indexOf(socket), 1);
85 | });
86 | });
87 |
88 | var shutdownSever = function() {
89 | server.close();
90 |
91 | for (var i = 0; i < sockets.length; i++) {
92 | sockets[i].destroy();
93 | }
94 | };
95 |
96 | server.once('close', function() {
97 | console.log(serverName + ' has stopped.');
98 | process.exit();
99 | });
100 |
101 | process.once('SIGTERM', shutdownSever);
102 | process.once('SIGINT', shutdownSever);
103 |
104 | })();
105 |
106 |
--------------------------------------------------------------------------------
/Examples/sources.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cesium-Navigation from Sources
5 |
6 |
7 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Examples/standalone.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Cesium-Navigation Example (standalone)
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
53 |
54 |
63 |
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cesium-navigation
2 | This is a Cesium plugin that adds to the Cesium map a user friendly compass, navigator (zoom in/out), and
3 | distance scale graphical user interface.
4 |
5 | **Why did you build it?**
6 |
7 | First of all the Cesiumjs sdk does not include a compass, navigator (zoom in/out) nor distance scale. You can use the mouse to navigate on the map but this navigation plugin offers more navigation control and capabilities to the user.
8 | Some of the capabilities are:
9 | reset the compass to point to north, reset the orbit, and reset the view to a default bound.
10 |
11 | **How did you build it?**
12 |
13 | This plugin is based on the excellent compass, navigator (zoom in/out) and distance scale from the terriajs open source library (https://github.com/TerriaJS). The navigation UI from terriajs can not be used out of the box in Cesium because Cesium uses CommonJS modules with RequireJS, and the terriajs uses commonjs and Browserify, so you can't just copy the source files into Cesium and build. My work consisted on adapting the code to work within Cesium as a plugin as follows:
14 |
15 | - Extracted the minimum required modules from terriajs.
16 | - Converted all the modules from Browserify to requirejs.
17 | - Using nodejs and the requirejs optimizer as well as almond the whole plugin is built and bundled in a single file even the CSS style
18 | - This plugin can be used as a standalone script or via an AMD loader (tested with requirejs). Even in the special case where you use AMD but not for Cesium the plugin can be easily used.
19 |
20 | **How to use it?**
21 |
22 | *When to use which edition?*
23 |
24 | There are two editions, a standalone edition and an AMD compatible edition. If you want to load the mixin via requireJS then use the AMD compatible edition. Otherwise use the standalone edition which includes almond to resolve dependencies. Below some examples are given for better understanding.
25 |
26 | - If you are loading Cesium without requirejs (i.e. you have a global variable Cesium) then use the standalone edition. This edition is also suitable if you use requirejs but not for this mixin.
27 | ```HTML
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | ```
38 | and then extend a viewer:
39 |
40 | ```JavaScript
41 | // create a viewer assuming there is a DIV element with id 'cesiumContainer'
42 | var cesiumViewer = new Cesium.Viewer('cesiumContainer');
43 |
44 | // extend our view by the cesium navigaton mixin
45 | cesiumViewer.extend(Cesium.viewerCesiumNavigationMixin, {});
46 | ```
47 |
48 | or a widget:
49 |
50 | ```JavaScript
51 | // create a widget assuming there is a DIV element with id 'cesiumContainer'
52 | var cesiumWidget = new Cesium.CesiumWidget('cesiumContainer');
53 |
54 | // extend our view by the cesium navigaton mixin
55 | Cesium.viewerCesiumNavigationMixin.mixinWidget(cesiumWidget, {});
56 | ```
57 |
58 | You can access the newly created instance via
59 |
60 | ```
61 | // if using a viewer
62 | var cesiumNavigation = cesiumViewer.cesiumNavigation;
63 |
64 | // if using a widget
65 | var cesiumNavigation = cesiumWidget.cesiumNavigation;
66 | ```
67 |
68 | Another example if your are using requirejs except for Cesium:
69 | ```HTML
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
82 |
83 |
84 |
85 | ```
86 | and code
87 | ```JavaScript
88 | // IMPORTANT: be sure that Cesium.js has already been loaded, e.g. by loading requirejs AFTER Cesium
89 | require(['path/to/amd/viewerCesiumNavigationMixin'], function(viewerCesiumNavigationMixin) {
90 | // like above code but now one can directly access
91 | // viewerCesiumNavigationMixin
92 | // instead of
93 | // Cesium.viewerCesiumNavigationMixin
94 | }
95 | ```
96 |
97 | - If you are using requirejs for your entire project, including Cesium, then you have to use the AMD compatible edition.
98 |
99 | ```HTML
100 |
101 |
102 |
103 |
104 |
121 |
122 |
123 |
124 | ```
125 | and the code
126 | ```JavaScript
127 | require([
128 | 'Cesium/Cesium', // if Cesium points to Cesium directory
129 | 'Cesium', // if Cesium points to Cesium.js file
130 | 'path/to/amd/viewerCesiumNavigationMixin'
131 | ], function(
132 | Cesium,
133 | viewerCesiumNavigationMixin) {
134 |
135 | // like above but now you cannot access Cesium.viewerCesiumNavigationMixin
136 | // but use just viewerCesiumNavigationMixin
137 | });
138 | ```
139 | or if Cesium points to the Cesium directory
140 | ```JavaScript
141 | require([
142 | 'Cesium/Core/Viewer',
143 | 'path/to/amd/viewerCesiumNavigationMixin'
144 | ], function(
145 | CesiumViewer,
146 | viewerCesiumNavigationMixin) {
147 |
148 | // like above but now you cannot access Cesium.viewerCesiumNavigationMixin
149 | // but use just viewerCesiumNavigationMixin
150 | });
151 | ```
152 | *Available options of the plugin*
153 | ```
154 | defaultResetView --> option used to set a default view when resetting the map view with the reset navigation
155 | control. Values accepted are of type Cesium.Cartographic and Cesium.Rectangle.
156 |
157 | enableCompass --> option used to enable or disable the compass. Values accepted are true for enabling and false to disable. The default is true.
158 |
159 | enableZoomControls --> option used to enable or disable the zoom controls. Values accepted are true for enabling and false to disable. The default is true.
160 |
161 | enableDistanceLegend --> option used to enable or disable the distance legend. Values accepted are true for enabling and false to disable. The default is true.
162 |
163 | More options will be set in future releases of the plugin.
164 | ```
165 | Example of using the options when loading Cesium without requirejs:
166 | ```JavaScript
167 | var options = {};
168 | options.defaultResetView = Cesium.Rectangle.fromDegrees(71, 3, 90, 14);
169 | // Only the compass will show on the map
170 | options.enableCompass = true;
171 | options.enableZoomControls = false;
172 | options.enableDistanceLegend = false;
173 | cesiumViewer.extend(Cesium.viewerCesiumNavigationMixin, options);
174 | ```
175 |
176 | *Others*
177 |
178 | - To destroy the navigation object and release the resources later on use the following
179 | ```JavaScript
180 | viewer.cesiumNavigation.destroy();
181 | ```
182 |
183 | - if there are still open questions please checkout the examples
184 |
185 |
186 | **How to build it?**
187 |
188 | - run `npm install`
189 | - run `node build.js`
190 | - The build process also copies the files to the Example folder in order to always keep them sync with your build
191 |
192 |
193 | **Developers guide**
194 |
195 | For developing/debugging you should have a look at the "Source example". That example directly uses the source files and therefore it allows you to immediatley (only a page refresh is needed) see your changes without rebuilding anything. Furthermore due to working with the sources you can easily debug the project (e.g. via the developer console of the browser or via a debugger of your IDE like Webstorm)
196 |
197 |
198 | **Is there a demo using the plugin?**
199 |
200 | This is the demo:
201 |
202 | (http://larcius.github.io/cesium-navigation/)
203 |
204 | - The compass, navigator, and distance scale will appear on the right side of te map.
205 | - This plugin was successfully tested on Cesium version 1.15. It works great with Cesium in 3D mode. Recently Larcius (https://github.com/Larcius) made a lot of improvements and fixed some issues in Columbus and 2D modes.
206 |
207 | **What about the license?**
208 | - The plugin is 100% based on open source libraries. The same license that applies to Cesiumjs and terriajs applies also to this plugin. Feel free to use it, modify it, and improve it.
209 |
--------------------------------------------------------------------------------
/Source/CesiumNavigation.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Core/defineProperties',
5 | // 'Cesium/Core/defaultValue',
6 | 'Cesium/Core/Event',
7 | 'KnockoutES5',
8 | 'Core/registerKnockoutBindings',
9 | 'ViewModels/DistanceLegendViewModel',
10 | 'ViewModels/NavigationViewModel'
11 | ], function (
12 | defined,
13 | defineProperties,
14 | // defaultValue,
15 | CesiumEvent,
16 | Knockout,
17 | registerKnockoutBindings,
18 | DistanceLegendViewModel,
19 | NavigationViewModel)
20 | {
21 | 'use strict';
22 |
23 | /**
24 | * @alias CesiumNavigation
25 | * @constructor
26 | *
27 | * @param {Viewer|CesiumWidget} viewerCesiumWidget The Viewer or CesiumWidget instance
28 | */
29 | var CesiumNavigation = function (viewerCesiumWidget) {
30 | initialize.apply(this, arguments);
31 |
32 | this._onDestroyListeners = [];
33 | };
34 |
35 | CesiumNavigation.prototype.distanceLegendViewModel = undefined;
36 | CesiumNavigation.prototype.navigationViewModel = undefined;
37 | CesiumNavigation.prototype.navigationDiv = undefined;
38 | CesiumNavigation.prototype.distanceLegendDiv = undefined;
39 | CesiumNavigation.prototype.terria = undefined;
40 | CesiumNavigation.prototype.container = undefined;
41 | CesiumNavigation.prototype._onDestroyListeners = undefined;
42 |
43 | CesiumNavigation.prototype.destroy = function ()
44 | {
45 | if (defined(this.navigationViewModel))
46 | {
47 | this.navigationViewModel.destroy();
48 | }
49 | if (defined(this.distanceLegendViewModel))
50 | {
51 | this.distanceLegendViewModel.destroy();
52 | }
53 |
54 | if (defined(this.navigationDiv))
55 | {
56 | this.navigationDiv.parentNode.removeChild(this.navigationDiv);
57 | }
58 | delete this.navigationDiv;
59 |
60 | if (defined(this.distanceLegendDiv))
61 | {
62 | this.distanceLegendDiv.parentNode.removeChild(this.distanceLegendDiv);
63 | }
64 | delete this.distanceLegendDiv;
65 |
66 | if (defined(this.container))
67 | {
68 | this.container.parentNode.removeChild(this.container);
69 | }
70 | delete this.container;
71 |
72 | for (var i = 0; i < this._onDestroyListeners.length; i++)
73 | {
74 | this._onDestroyListeners[i]();
75 | }
76 | };
77 |
78 | CesiumNavigation.prototype.addOnDestroyListener = function (callback)
79 | {
80 | if (typeof callback === "function")
81 | {
82 | this._onDestroyListeners.push(callback);
83 | }
84 | };
85 |
86 | /**
87 | * @param {Viewer|CesiumWidget} viewerCesiumWidget The Viewer or CesiumWidget instance
88 | * @param options
89 | */
90 | function initialize(viewerCesiumWidget, options) {
91 | if (!defined(viewerCesiumWidget)) {
92 | throw new DeveloperError('CesiumWidget or Viewer is required.');
93 | }
94 |
95 | // options = defaultValue(options, defaultValue.EMPTY_OBJECT);
96 |
97 | var cesiumWidget = defined(viewerCesiumWidget.cesiumWidget) ? viewerCesiumWidget.cesiumWidget : viewerCesiumWidget;
98 |
99 | var container = document.createElement('div');
100 | container.className = 'cesium-widget-cesiumNavigationContainer';
101 | cesiumWidget.container.appendChild(container);
102 |
103 | this.terria = viewerCesiumWidget;
104 | this.terria.options = (defined(options))?options :{};
105 | this.terria.afterWidgetChanged = new CesiumEvent();
106 | this.terria.beforeWidgetChanged = new CesiumEvent();
107 | this.container = container;
108 |
109 | //this.navigationDiv.setAttribute("id", "navigationDiv");
110 |
111 |
112 | // Register custom Knockout.js bindings. If you're not using the TerriaJS user interface, you can remove this.
113 | registerKnockoutBindings();
114 |
115 | if (!defined(this.terria.options.enableDistanceLegend) || this.terria.options.enableDistanceLegend)
116 | {
117 | this.distanceLegendDiv = document.createElement('div');
118 | container.appendChild(this.distanceLegendDiv);
119 | this.distanceLegendDiv.setAttribute("id", "distanceLegendDiv");
120 | this.distanceLegendViewModel = DistanceLegendViewModel.create({
121 | container: this.distanceLegendDiv,
122 | terria: this.terria,
123 | mapElement: container,
124 | enableDistanceLegend: true
125 | });
126 |
127 | }
128 |
129 |
130 | if ((!defined(this.terria.options.enableZoomControls) || this.terria.options.enableZoomControls) && (!defined(this.terria.options.enableCompass) || this.terria.options.enableCompass))
131 | {
132 | this.navigationDiv = document.createElement('div');
133 | this.navigationDiv.setAttribute("id", "navigationDiv");
134 | container.appendChild(this.navigationDiv);
135 | // Create the navigation controls.
136 | this.navigationViewModel = NavigationViewModel.create({
137 | container: this.navigationDiv,
138 | terria: this.terria,
139 | enableZoomControls: true,
140 | enableCompass: true
141 | });
142 | }
143 | else if ((defined(this.terria.options.enableZoomControls) && !this.terria.options.enableZoomControls) && (!defined(this.terria.options.enableCompass) || this.terria.options.enableCompass))
144 | {
145 | this.navigationDiv = document.createElement('div');
146 | this.navigationDiv.setAttribute("id", "navigationDiv");
147 | container.appendChild(this.navigationDiv);
148 | // Create the navigation controls.
149 | this.navigationViewModel = NavigationViewModel.create({
150 | container: this.navigationDiv,
151 | terria: this.terria,
152 | enableZoomControls: false,
153 | enableCompass: true
154 | });
155 | }
156 | else if ((!defined(this.terria.options.enableZoomControls) || this.terria.options.enableZoomControls) && (defined(this.terria.options.enableCompass) && !this.terria.options.enableCompass))
157 | {
158 | this.navigationDiv = document.createElement('div');
159 | this.navigationDiv.setAttribute("id", "navigationDiv");
160 | container.appendChild(this.navigationDiv);
161 | // Create the navigation controls.
162 | this.navigationViewModel = NavigationViewModel.create({
163 | container: this.navigationDiv,
164 | terria: this.terria,
165 | enableZoomControls: true,
166 | enableCompass: false
167 | });
168 | }
169 | else if ((defined(this.terria.options.enableZoomControls) && !this.terria.options.enableZoomControls) && (defined(this.terria.options.enableCompass) && !this.terria.options.enableCompass))
170 | {
171 | //this.navigationDiv.setAttribute("id", "navigationDiv");
172 | // container.appendChild(this.navigationDiv);
173 | // Create the navigation controls.
174 | // this.navigationViewModel = NavigationViewModel.create({
175 | // container: this.navigationDiv,
176 | // terria: this.terria,
177 | // enableZoomControls: false,
178 | // enableCompass: false
179 | // });
180 | }
181 |
182 | }
183 |
184 | return CesiumNavigation;
185 | });
--------------------------------------------------------------------------------
/Source/Core/KnockoutHammerBinding.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'KnockoutES5',
4 | 'Hammer'
5 | ], function (Knockout, Hammer) {
6 | 'use strict';
7 |
8 | var KnockoutHammerBinding = {
9 | register: function (Knockout) {
10 | Knockout.bindingHandlers.swipeLeft = {
11 | init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
12 | var f = Knockout.unwrap(valueAccessor());
13 | new Hammer(element).on('swipeleft', function (e) {
14 | var viewModel = bindingContext.$data;
15 | f.apply(viewModel, arguments);
16 | });
17 | }
18 | };
19 |
20 | Knockout.bindingHandlers.swipeRight = {
21 | init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
22 | var f = Knockout.unwrap(valueAccessor());
23 | new Hammer(element).on('swiperight', function (e) {
24 | var viewModel = bindingContext.$data;
25 | f.apply(viewModel, arguments);
26 | });
27 | }
28 | };
29 | }
30 | };
31 |
32 | return KnockoutHammerBinding;
33 | });
34 |
--------------------------------------------------------------------------------
/Source/Core/KnockoutMarkdownBinding.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'markdown-it-sanitizer',
4 | 'markdown-it'
5 | ], function (
6 | MarkdownItSanitizer,
7 | MarkdownIt) {
8 | 'use strict';
9 |
10 | var htmlTagRegex = /(.|\s)*<\/html>/im;
11 |
12 | var md = new MarkdownIt({
13 | html: true,
14 | linkify: true
15 | });
16 |
17 | md.use(MarkdownItSanitizer, {
18 | imageClass: '',
19 | removeUnbalanced: false,
20 | removeUnknown: false
21 | });
22 |
23 | var KnockoutMarkdownBinding = {
24 | register: function (Knockout) {
25 | Knockout.bindingHandlers.markdown = {
26 | 'init': function () {
27 | // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
28 | return { 'controlsDescendantBindings': true };
29 | },
30 | 'update': function (element, valueAccessor) {
31 | // Remove existing children of this element.
32 | while (element.firstChild) {
33 | Knockout.removeNode(element.firstChild);
34 | }
35 |
36 | var rawText = Knockout.unwrap(valueAccessor());
37 |
38 | // If the text contains an tag, don't try to interpret it as Markdown because
39 | // we'll probably break it in the process.
40 | var html;
41 | if (htmlTagRegex.test(rawText)) {
42 | html = rawText;
43 | } else {
44 | html = md.render(rawText);
45 | }
46 |
47 | var nodes = Knockout.utils.parseHtmlFragment(html, element);
48 | element.className = element.className + ' markdown';
49 |
50 | for (var i = 0; i < nodes.length; ++i) {
51 | var node = nodes[i];
52 | setAnchorTargets(node);
53 | element.appendChild(node);
54 | }
55 | }
56 | };
57 | }
58 | };
59 |
60 | function setAnchorTargets(element) {
61 | if (element instanceof HTMLAnchorElement) {
62 | element.target = '_blank';
63 | }
64 |
65 | if (element.childNodes && element.childNodes.length > 0) {
66 | for (var i = 0; i < element.childNodes.length; ++i) {
67 | setAnchorTargets(element.childNodes[i]);
68 | }
69 | }
70 | }
71 |
72 | return KnockoutMarkdownBinding;
73 | });
74 |
75 |
--------------------------------------------------------------------------------
/Source/Core/Utils.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Core/Ray',
5 | 'Cesium/Core/Cartesian3',
6 | 'Cesium/Core/Cartographic',
7 | 'Cesium/Core/ReferenceFrame',
8 | 'Cesium/Scene/SceneMode'
9 | ], function (
10 | defined,
11 | Ray,
12 | Cartesian3,
13 | Cartographic,
14 | ReferenceFrame,
15 | SceneMode) {
16 | 'use strict';
17 |
18 | var Utils = {};
19 |
20 | var unprojectedScratch = new Cartographic();
21 | var rayScratch = new Ray();
22 |
23 | /**
24 | * gets the focus point of the camera
25 | * @param {Viewer|Widget} terria The terria
26 | * @param {boolean} inWorldCoordinates true to get the focus in world coordinates, otherwise get it in projection-specific map coordinates, in meters.
27 | * @param {Cartesian3} [result] The object in which the result will be stored.
28 | * @return {Cartesian3} The modified result parameter, a new instance if none was provided or undefined if there is no focus point.
29 | */
30 | Utils.getCameraFocus = function (terria, inWorldCoordinates, result) {
31 | var scene = terria.scene;
32 | var camera = scene.camera;
33 |
34 | if(scene.mode == SceneMode.MORPHING) {
35 | return undefined;
36 | }
37 |
38 | if(!defined(result)) {
39 | result = new Cartesian3();
40 | }
41 |
42 | // TODO bug when tracking: if entity moves the current position should be used and not only the one when starting orbiting/rotating
43 | // TODO bug when tracking: reset should reset to default view of tracked entity
44 |
45 | if(defined(terria.trackedEntity)) {
46 | result = terria.trackedEntity.position.getValue(terria.clock.currentTime, result);
47 | } else {
48 | rayScratch.origin = camera.positionWC;
49 | rayScratch.direction = camera.directionWC;
50 | result = scene.globe.pick(rayScratch, scene, result);
51 | }
52 |
53 | if (!defined(result)) {
54 | return undefined;
55 | }
56 |
57 | if(scene.mode == SceneMode.SCENE2D || scene.mode == SceneMode.COLUMBUS_VIEW) {
58 | result = camera.worldToCameraCoordinatesPoint(result, result);
59 |
60 | if(inWorldCoordinates) {
61 | result = scene.globe.ellipsoid.cartographicToCartesian(scene.mapProjection.unproject(result, unprojectedScratch), result);
62 | }
63 | } else {
64 | if(!inWorldCoordinates) {
65 | result = camera.worldToCameraCoordinatesPoint(result, result);
66 | }
67 | }
68 |
69 | return result;
70 | };
71 |
72 | return Utils;
73 | });
74 |
--------------------------------------------------------------------------------
/Source/Core/createFragmentFromTemplate.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | ], function () {
4 | 'use strict';
5 |
6 | var createFragmentFromTemplate = function (htmlString) {
7 | var holder = document.createElement('div');
8 | holder.innerHTML = htmlString;
9 |
10 | var fragment = document.createDocumentFragment();
11 | while (holder.firstChild) {
12 | fragment.appendChild(holder.firstChild);
13 | }
14 |
15 | return fragment;
16 | };
17 |
18 | return createFragmentFromTemplate;
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/Source/Core/loadView.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'Cesium/Widgets/getElement',
4 | 'KnockoutES5',
5 | 'Core/createFragmentFromTemplate'
6 | ], function (
7 | getElement,
8 | Knockout,
9 | createFragmentFromTemplate) {
10 | 'use strict';
11 |
12 | var loadView = function (htmlString, container, viewModel) {
13 | container = getElement(container);
14 |
15 | var fragment = createFragmentFromTemplate(htmlString);
16 |
17 | // Sadly, fragment.childNodes doesn't have a slice function.
18 | // This code could be replaced with Array.prototype.slice.call(fragment.childNodes)
19 | // but that seems slightly error prone.
20 | var nodes = [];
21 |
22 | var i;
23 | for (i = 0; i < fragment.childNodes.length; ++i) {
24 | nodes.push(fragment.childNodes[i]);
25 | }
26 |
27 | container.appendChild(fragment);
28 |
29 | for (i = 0; i < nodes.length; ++i) {
30 | var node = nodes[i];
31 | if (node.nodeType === 1 || node.nodeType === 8) {
32 | Knockout.applyBindings(viewModel, node);
33 | }
34 | }
35 |
36 | return nodes;
37 | };
38 |
39 | return loadView;
40 | });
--------------------------------------------------------------------------------
/Source/Core/registerKnockoutBindings.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'Cesium/Widgets/SvgPathBindingHandler',
4 | 'KnockoutES5',
5 | 'Core/KnockoutMarkdownBinding',
6 | 'Core/KnockoutHammerBinding'
7 | ], function (
8 | SvgPathBindingHandler,
9 | Knockout,
10 | KnockoutMarkdownBinding,
11 | KnockoutHammerBinding) {
12 | 'use strict';
13 |
14 | var registerKnockoutBindings = function () {
15 | SvgPathBindingHandler.register(Knockout);
16 | KnockoutMarkdownBinding.register(Knockout);
17 | KnockoutHammerBinding.register(Knockout);
18 |
19 | Knockout.bindingHandlers.embeddedComponent = {
20 | init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
21 | var component = Knockout.unwrap(valueAccessor());
22 | component.show(element);
23 | return { controlsDescendantBindings: true };
24 | },
25 | update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
26 | }
27 | };
28 | };
29 |
30 | return registerKnockoutBindings;
31 | });
32 |
33 |
--------------------------------------------------------------------------------
/Source/Styles/Core.less:
--------------------------------------------------------------------------------
1 | /*html {
2 | height: 100%;
3 | -webkit-font-smoothing: antialiased;
4 | }
5 |
6 | body {
7 | height: 100%;
8 | width: 100%;
9 | margin: 0;
10 | overflow: hidden;
11 | padding: 0;
12 | background: #000;
13 | font-size: 15px;
14 | font-family: @default-font;
15 | }*/
16 |
17 | .full-window {
18 | position: absolute;
19 | top: 0;
20 | left: 0;
21 | right: 0;
22 | bottom: 0;
23 | margin: 0;
24 | overflow: hidden;
25 | padding: 0;
26 |
27 | -webkit-transition: left @explorer-panel-close-animation-length ease-out;
28 | -moz-transition: left @explorer-panel-close-animation-length ease-out;
29 | -ms-transition: left @explorer-panel-close-animation-length ease-out;
30 | -o-transition: left @explorer-panel-close-animation-length ease-out;
31 | transition: left @explorer-panel-close-animation-length ease-out;
32 | }
33 |
34 | .transparent-to-input {
35 | pointer-events: none;
36 | }
37 |
38 | .opaque-to-input {
39 | pointer-events: auto;
40 | }
41 |
42 | .clickable {
43 | cursor: pointer;
44 | }
45 |
46 | /*a {
47 | text-decoration: none;
48 | color: @highlight-color;
49 | }*/
50 |
51 | a:hover {
52 | text-decoration: underline;
53 | }
54 |
55 | @modal-background-color: @panel-background-color;
56 | @modal-text-color: @panel-emphasized-text-color;
57 | @modal-header-background-color: rgba(0,0,0,0.2);
58 | @modal-header-text-color: @panel-emphasized-text-color;
59 |
60 | .modal-background {
61 | .opaque-to-input;
62 | position: fixed;
63 | left: 0;
64 | right: 0;
65 | top: 0;
66 | bottom: 0;
67 | background-color: rgba(0,0,0,0.5);
68 | z-index: 1000; /* required for IE9 */
69 | }
70 |
71 | .modal {
72 | position: absolute;
73 | margin: auto;
74 | background-color: @modal-background-color;
75 | top: 0;
76 | left: 0;
77 | bottom: 0;
78 | right: 0;
79 | max-height: 100%;
80 | max-width: 100%;
81 | font-family: @default-font;
82 | color: @modal-text-color;
83 | }
84 |
85 | .modal-header {
86 | background-color: @modal-header-background-color;
87 | border-bottom: @panel-element-border;
88 | font-size: 15px;
89 | line-height: 40px;
90 | margin: 0;
91 | }
92 |
93 | .modal-header h1 {
94 | font-size: 15px;
95 | color: @modal-header-text-color;
96 | margin-left: 15px;
97 | }
98 |
99 | .modal-content {
100 | margin-left: 15px;
101 | margin-right: 15px;
102 | margin-bottom: 15px;
103 | padding-top: 15px;
104 | overflow: auto;
105 | }
106 |
107 | .modal-close-button {
108 | position: absolute;
109 | right: 15px;
110 | cursor: pointer;
111 | font-size: 18px;
112 | color: @modal-header-text-color;
113 | }
114 |
115 |
116 | #ui {
117 | // This keeps the UI above the map in IE9.
118 | z-index: 2100;
119 | }
120 |
121 | @media print {
122 | .full-window {
123 | position: initial;
124 | }
125 | }
126 |
127 | // input fields
128 |
129 | /* input[type=text] {
130 | height: 38px;
131 | background-color: #eeeeee;
132 | color: @input-text-color;
133 | font-size: 14px;
134 | }
135 |
136 | ::-webkit-input-placeholder {
137 | color: fade(@input-text-color, 75%);
138 | font-style: italic;
139 | }
140 |
141 | :-moz-placeholder { /* Firefox 18-
142 | color: fade(@input-text-color, 75%);
143 | font-style: italic;
144 | }
145 |
146 | ::-moz-placeholder { /* Firefox 19+
147 | color: fade(@input-text-color, 75%);
148 | font-style: italic;
149 | }
150 |
151 | :-ms-input-placeholder {
152 | color: fade(@input-text-color, 75%);
153 | font-style: italic;
154 | }
155 |
156 | input:focus {
157 | outline-color: #FFFFFF;
158 | }
159 | */
160 |
161 | /*select {
162 | display: block;
163 | background-color: @panel-form-input-background-color;
164 | color: @panel-form-input-text-color;
165 | height: 40px;
166 | border: 0;
167 | margin-top: 10px;
168 | font-size: 14px;
169 | padding-left: 5px;
170 | }*/
171 |
172 | .markdown {
173 | img { max-width: 100% }
174 | svg { max-height: 100% }
175 |
176 | input,
177 | select,
178 | textarea,
179 | fieldset {
180 | font-family: inherit;
181 | font-size: 1rem;
182 | box-sizing: border-box;
183 | margin-top: 0;
184 | margin-bottom: 0;
185 | }
186 |
187 | label {
188 | vertical-align: middle;
189 | }
190 |
191 | h1, h2, h3, h4, h5, h6 {
192 | font-family: inherit;
193 | font-weight: bold;
194 | line-height: 1.25;
195 | margin-top: 1em;
196 | margin-bottom: .5em;
197 | }
198 |
199 | h1 { font-size: 2rem }
200 | h2 { font-size: 1.5rem }
201 | h3 { font-size: 1.25rem }
202 | h4 { font-size: 1rem }
203 | h5 { font-size: .875rem }
204 | h6 { font-size: .75rem }
205 |
206 | p {
207 | margin-top: 0;
208 | margin-bottom: 1rem;
209 | }
210 |
211 | strong { font-weight: bold }
212 | em { font-style: italic }
213 | small {font-size: 80%;}
214 | mark { color: #000; background: #ff0;}
215 | u {text-decoration: underline;}
216 | s {text-decoration: line-through;}
217 |
218 | dl, ol, ul {
219 | margin-top: 0;
220 | margin-bottom: 1rem;
221 | }
222 |
223 | ol{
224 | list-style: decimal inside;
225 | }
226 |
227 | ul{
228 | list-style: disc inside;
229 | }
230 |
231 | pre, code, samp {
232 | font-family: monospace;
233 | font-size: inherit;
234 | }
235 |
236 | pre {
237 | margin-top: 0;
238 | margin-bottom: 1rem;
239 | overflow-x: scroll;
240 | }
241 |
242 | a {
243 | color: #68ADFE;
244 | text-decoration: none;
245 | }
246 |
247 | a:hover {
248 | text-decoration: underline;
249 | }
250 |
251 | pre, code {
252 | background-color: transparent;
253 | border-radius: 3px;
254 | }
255 |
256 | hr {
257 | border: 0;
258 | border-bottom-style: solid;
259 | border-bottom-width: 1px;
260 | border-bottom-color: rgba(0,0,0,.125);
261 | }
262 |
263 | .left-align { text-align: left }
264 | .center { text-align: center }
265 | .right-align { text-align: right }
266 | .justify { text-align: justify }
267 |
268 | .truncate {
269 | max-width: 100%;
270 | overflow: hidden;
271 | text-overflow: ellipsis;
272 | white-space: nowrap;
273 | }
274 |
275 | ol.upper-roman {list-style-type: upper-roman;}
276 | ol.lower-alpha {list-style-type: lower-alpha;}
277 |
278 | ul.circle {list-style-type: circle;}
279 | ul.square {list-style-type: square;}
280 |
281 | .list-reset {
282 | list-style: none;
283 | padding-left: 0;
284 | }
285 | }
286 |
--------------------------------------------------------------------------------
/Source/Styles/DistanceLegend.less:
--------------------------------------------------------------------------------
1 | .distance-legend {
2 | .floating-horizontal;
3 | right: 25px;
4 | bottom: 30px;
5 | height: 30px;
6 | width: 125px;
7 | border: 1px solid rgba(255,255,255,0.1);
8 | box-sizing: content-box;
9 | }
10 |
11 | .distance-legend-label {
12 | display: inline-block;
13 | font-family: @default-font;
14 | font-size: 14px;
15 | font-weight: lighter;
16 | line-height: 30px;
17 | color: @floating-text-color;
18 | width: 125px;
19 | text-align: center;
20 | }
21 |
22 | .distance-legend-scale-bar {
23 | border-left: 1px solid @floating-text-color;
24 | border-right: 1px solid @floating-text-color;
25 | border-bottom: 1px solid @floating-text-color;
26 | position: absolute;
27 | height: 10px;
28 | top: 15px;
29 | }
30 |
31 | @media print {
32 | .distance-legend {
33 | display: none;
34 | }
35 | }
36 |
37 | // Don't display the distance legend on small screens like mobile phones.
38 | @media screen and (max-width: 700px), screen and (max-height: 420px) {
39 | .distance-legend {
40 | display: none;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Source/Styles/Floating.less:
--------------------------------------------------------------------------------
1 | .floating {
2 | .opaque-to-input;
3 | position: absolute;
4 | border-radius: 15px;
5 | background-color: @floating-background-color;
6 | }
7 |
8 | .floating-horizontal {
9 | .floating;
10 | padding-left: 5px;
11 | padding-right: 5px;
12 | }
13 |
14 | .floating-vertical {
15 | .floating;
16 | padding-top: 5px;
17 | padding-bottom: 5px;
18 | }
19 |
20 | @media print {
21 | .floating {
22 | display: none;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/Styles/Navigation.less:
--------------------------------------------------------------------------------
1 | .navigation-controls {
2 | //.floating-vertical;
3 | position: absolute;
4 | right: 30px;
5 | top: 210px;
6 | width: 30px;
7 | border: 1px solid rgba(255,255,255,0.1);
8 | font-weight: 300;
9 | // avoids selection of text with rapid zooming
10 | -webkit-touch-callout: none;
11 | -webkit-user-select: none;
12 | -khtml-user-select: none;
13 | -moz-user-select: none;
14 | -ms-user-select: none;
15 | user-select: none;
16 | }
17 |
18 | .navigation-control {
19 | .clickable;
20 | border-bottom: @floating-element-border;
21 | }
22 |
23 | .naviagation-control:active {
24 | color: #FFF;
25 | }
26 |
27 | .navigation-control-last {
28 | .navigation-control;
29 | border-bottom: 0;
30 | }
31 |
32 | .navigation-control-icon-zoom-in {
33 | position: relative;
34 | text-align: center;
35 | font-size: 20px;
36 | color: @floating-text-color;
37 | padding-bottom: 4px;
38 | }
39 |
40 | .navigation-control-icon-zoom-out {
41 | position: relative;
42 | text-align: center;
43 | font-size: 20px;
44 | color: @floating-text-color;
45 | }
46 |
47 | .navigation-control-icon-reset {
48 | position: relative;
49 | left: 10px;
50 | width: 10px;
51 | height: 10px;
52 | fill: fade(@floating-text-color, 80%);
53 | padding-top: 6px;
54 | padding-bottom: 6px;
55 | box-sizing: content-box;
56 | }
57 |
58 |
59 | @compass-diameter: 95px;
60 | @compass-ring-width: @compass-diameter * 20 / 145;
61 | @compass-gyro-diameter: @compass-diameter * 50 / 145;
62 |
63 | .compass {
64 | .opaque-to-input;
65 | position: absolute;
66 | right: 0px;
67 | top: 100px;
68 | width: @compass-diameter;
69 | height: @compass-diameter;
70 | overflow: hidden;
71 | }
72 |
73 | .compass-outer-ring {
74 | position: absolute;
75 | top: 0;
76 | width: @compass-diameter;
77 | height: @compass-diameter;
78 | fill: rgba(255,255,255,0.5);
79 | }
80 |
81 | .compass-outer-ring-background {
82 | position: absolute;
83 | top: 14px;
84 | left: 14px;
85 | width: 44px;
86 | height: 44px;
87 | border-radius: 44px;
88 | border: 12px solid @floating-background-color;
89 | box-sizing: content-box;
90 | }
91 |
92 | .compass-gyro {
93 | pointer-events: none;
94 | position: absolute;
95 | top: 0;
96 | width: @compass-diameter;
97 | height: @compass-diameter;
98 | fill: #CCC;
99 | }
100 |
101 | .compass-gyro-active {
102 | fill: @highlight-color;
103 | }
104 |
105 | .compass-gyro-background {
106 | position: absolute;
107 | top: 30px;
108 | left: 30px;
109 | width: 33px;
110 | height: 33px;
111 | border-radius: 33px;
112 | background-color: @floating-background-color;
113 | border: 1px solid rgba(255,255,255,0.2);
114 | box-sizing: content-box;
115 | }
116 |
117 | .compass-gyro-background:hover + .compass-gyro {
118 | fill: @highlight-color;
119 | }
120 |
121 | .compass-rotation-marker {
122 | position: absolute;
123 | top: 0;
124 | width: @compass-diameter;
125 | height: @compass-diameter;
126 | fill: @highlight-color;
127 | }
128 |
129 | // Don't display the nav controls on small screens like mobile phones.
130 | @media screen and (max-width: 700px), screen and (max-height: 420px) {
131 | .navigation-controls {
132 | display: none;
133 | }
134 | .compass {
135 | display: none;
136 | }
137 | }
138 |
139 | @media print {
140 | .navigation-controls {
141 | display: none;
142 | }
143 | .compass {
144 | display: none;
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/Source/Styles/cesium-navigation.less:
--------------------------------------------------------------------------------
1 | @import "Core";
2 | @import "Floating";
3 |
4 | @import "DistanceLegend";
5 | @import "Navigation";
6 |
7 | @default-font: 'Roboto', sans-serif;
8 | @highlight-color: #68ADFE;
9 | @left-side-panels-width: 350px;
10 |
11 | //Panels
12 | @panel-background-color: #2F353C;
13 | @panel-text-color: #CCCCCC;
14 | @panel-emphasized-text-color: #FFFFFF;
15 | @panel-selected-text-color: @highlight-color;
16 | @panel-box-shadow: 2px 2px 5px rgba(0,0,0,0.26);
17 | @panel-element-border: 1px solid rgba(100,100,100, 0.6);
18 | @panel-section-background-color: #282D32;
19 | @panel-form-input-background-color: #838689;
20 | @panel-form-input-text-color: #FFFFFF;
21 | @panel-form-button-background-color: #A1A3A6;
22 | @panel-form-button-text-color: #FFFFFF;
23 |
24 | // Explorer panel
25 | @explorer-panel-width: @left-side-panels-width;
26 | @explorer-panel-header-background-color: #757f88;
27 | @explorer-panel-inactive-tab-text-color: @panel-text-color;
28 | @explorer-panel-active-tab-text-color: @panel-emphasized-text-color;
29 |
30 | @explorer-panel-active-tab-underline-color: @highlight-color;
31 | @explorer-panel-close-animation-length: 0.25s;
32 | @explorer-panel-tab-switch-animation-length: 0.25s;
33 | @explorer-panel-badge-background-color: @highlight-color;
34 | @explorer-panel-badge-text-color: @panel-emphasized-text-color;
35 |
36 | //Floating elements
37 |
38 | @floating-background-color: rgba(47,53,60,80%);
39 | @floating-text-color: #FFFFFF;
40 | @floating-element-border: 1px solid #555555;
41 |
42 | // Input
43 | @input-background-color: #A1A3A6;
44 | @input-text-color: #666666;
--------------------------------------------------------------------------------
/Source/SvgPaths/svgCompassGyro.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | ], function () {
4 | 'use strict';
5 |
6 | return 'm 72.71875,54.375 c -0.476702,0 -0.908208,0.245402 -1.21875,0.5625 -0.310542,0.317098 -0.551189,0.701933 -0.78125,1.1875 -0.172018,0.363062 -0.319101,0.791709 -0.46875,1.25 -6.91615,1.075544 -12.313231,6.656514 -13,13.625 -0.327516,0.117495 -0.661877,0.244642 -0.9375,0.375 -0.485434,0.22959 -0.901634,0.471239 -1.21875,0.78125 -0.317116,0.310011 -0.5625,0.742111 -0.5625,1.21875 l 0.03125,0 c 0,0.476639 0.245384,0.877489 0.5625,1.1875 0.317116,0.310011 0.702066,0.58291 1.1875,0.8125 0.35554,0.168155 0.771616,0.32165 1.21875,0.46875 1.370803,6.10004 6.420817,10.834127 12.71875,11.8125 0.146999,0.447079 0.30025,0.863113 0.46875,1.21875 0.230061,0.485567 0.470708,0.870402 0.78125,1.1875 0.310542,0.317098 0.742048,0.5625 1.21875,0.5625 0.476702,0 0.876958,-0.245402 1.1875,-0.5625 0.310542,-0.317098 0.582439,-0.701933 0.8125,-1.1875 0.172018,-0.363062 0.319101,-0.791709 0.46875,-1.25 6.249045,-1.017063 11.256351,-5.7184 12.625,-11.78125 0.447134,-0.1471 0.86321,-0.300595 1.21875,-0.46875 0.485434,-0.22959 0.901633,-0.502489 1.21875,-0.8125 0.317117,-0.310011 0.5625,-0.710861 0.5625,-1.1875 l -0.03125,0 c 0,-0.476639 -0.245383,-0.908739 -0.5625,-1.21875 C 89.901633,71.846239 89.516684,71.60459 89.03125,71.375 88.755626,71.244642 88.456123,71.117495 88.125,71 87.439949,64.078341 82.072807,58.503735 75.21875,57.375 c -0.15044,-0.461669 -0.326927,-0.884711 -0.5,-1.25 -0.230061,-0.485567 -0.501958,-0.870402 -0.8125,-1.1875 -0.310542,-0.317098 -0.710798,-0.5625 -1.1875,-0.5625 z m -0.0625,1.40625 c 0.03595,-0.01283 0.05968,0 0.0625,0 0.0056,0 0.04321,-0.02233 0.1875,0.125 0.144288,0.147334 0.34336,0.447188 0.53125,0.84375 0.06385,0.134761 0.123901,0.309578 0.1875,0.46875 -0.320353,-0.01957 -0.643524,-0.0625 -0.96875,-0.0625 -0.289073,0 -0.558569,0.04702 -0.84375,0.0625 C 71.8761,57.059578 71.936151,56.884761 72,56.75 c 0.18789,-0.396562 0.355712,-0.696416 0.5,-0.84375 0.07214,-0.07367 0.120304,-0.112167 0.15625,-0.125 z m 0,2.40625 c 0.448007,0 0.906196,0.05436 1.34375,0.09375 0.177011,0.592256 0.347655,1.271044 0.5,2.03125 0.475097,2.370753 0.807525,5.463852 0.9375,8.9375 -0.906869,-0.02852 -1.834463,-0.0625 -2.78125,-0.0625 -0.92298,0 -1.802327,0.03537 -2.6875,0.0625 0.138529,-3.473648 0.493653,-6.566747 0.96875,-8.9375 0.154684,-0.771878 0.320019,-1.463985 0.5,-2.0625 0.405568,-0.03377 0.804291,-0.0625 1.21875,-0.0625 z m -2.71875,0.28125 c -0.129732,0.498888 -0.259782,0.987558 -0.375,1.5625 -0.498513,2.487595 -0.838088,5.693299 -0.96875,9.25 -3.21363,0.15162 -6.119596,0.480068 -8.40625,0.9375 -0.682394,0.136509 -1.275579,0.279657 -1.84375,0.4375 0.799068,-6.135482 5.504716,-11.036454 11.59375,-12.1875 z M 75.5,58.5 c 6.043169,1.18408 10.705093,6.052712 11.5,12.15625 -0.569435,-0.155806 -1.200273,-0.302525 -1.875,-0.4375 -2.262525,-0.452605 -5.108535,-0.783809 -8.28125,-0.9375 -0.130662,-3.556701 -0.470237,-6.762405 -0.96875,-9.25 C 75.761959,59.467174 75.626981,58.990925 75.5,58.5 z m -2.84375,12.09375 c 0.959338,0 1.895843,0.03282 2.8125,0.0625 C 75.48165,71.267751 75.5,71.871028 75.5,72.5 c 0,1.228616 -0.01449,2.438313 -0.0625,3.59375 -0.897358,0.0284 -1.811972,0.0625 -2.75,0.0625 -0.927373,0 -1.831062,-0.03473 -2.71875,-0.0625 -0.05109,-1.155437 -0.0625,-2.365134 -0.0625,-3.59375 0,-0.628972 0.01741,-1.232249 0.03125,-1.84375 0.895269,-0.02827 1.783025,-0.0625 2.71875,-0.0625 z M 68.5625,70.6875 c -0.01243,0.60601 -0.03125,1.189946 -0.03125,1.8125 0,1.22431 0.01541,2.407837 0.0625,3.5625 -3.125243,-0.150329 -5.92077,-0.471558 -8.09375,-0.90625 -0.784983,-0.157031 -1.511491,-0.316471 -2.125,-0.5 -0.107878,-0.704096 -0.1875,-1.422089 -0.1875,-2.15625 0,-0.115714 0.02849,-0.228688 0.03125,-0.34375 0.643106,-0.20284 1.389577,-0.390377 2.25,-0.5625 2.166953,-0.433487 4.97905,-0.75541 8.09375,-0.90625 z m 8.3125,0.03125 c 3.075121,0.15271 5.824455,0.446046 7.96875,0.875 0.857478,0.171534 1.630962,0.360416 2.28125,0.5625 0.0027,0.114659 0,0.228443 0,0.34375 0,0.735827 -0.07914,1.450633 -0.1875,2.15625 -0.598568,0.180148 -1.29077,0.34562 -2.0625,0.5 -2.158064,0.431708 -4.932088,0.754666 -8.03125,0.90625 0.04709,-1.154663 0.0625,-2.33819 0.0625,-3.5625 0,-0.611824 -0.01924,-1.185379 -0.03125,-1.78125 z M 57.15625,72.5625 c 0.0023,0.572772 0.06082,1.131112 0.125,1.6875 -0.125327,-0.05123 -0.266577,-0.10497 -0.375,-0.15625 -0.396499,-0.187528 -0.665288,-0.387337 -0.8125,-0.53125 -0.147212,-0.143913 -0.15625,-0.182756 -0.15625,-0.1875 0,-0.0047 -0.02221,-0.07484 0.125,-0.21875 0.147212,-0.143913 0.447251,-0.312472 0.84375,-0.5 0.07123,-0.03369 0.171867,-0.06006 0.25,-0.09375 z m 31.03125,0 c 0.08201,0.03503 0.175941,0.05872 0.25,0.09375 0.396499,0.187528 0.665288,0.356087 0.8125,0.5 0.14725,0.14391 0.15625,0.21405 0.15625,0.21875 0,0.0047 -0.009,0.04359 -0.15625,0.1875 -0.147212,0.143913 -0.416001,0.343722 -0.8125,0.53125 -0.09755,0.04613 -0.233314,0.07889 -0.34375,0.125 0.06214,-0.546289 0.09144,-1.094215 0.09375,-1.65625 z m -29.5,3.625 c 0.479308,0.123125 0.983064,0.234089 1.53125,0.34375 2.301781,0.460458 5.229421,0.787224 8.46875,0.9375 0.167006,2.84339 0.46081,5.433176 0.875,7.5 0.115218,0.574942 0.245268,1.063612 0.375,1.5625 -5.463677,-1.028179 -9.833074,-5.091831 -11.25,-10.34375 z m 27.96875,0 C 85.247546,81.408945 80.919274,85.442932 75.5,86.5 c 0.126981,-0.490925 0.261959,-0.967174 0.375,-1.53125 0.41419,-2.066824 0.707994,-4.65661 0.875,-7.5 3.204493,-0.15162 6.088346,-0.480068 8.375,-0.9375 0.548186,-0.109661 1.051942,-0.220625 1.53125,-0.34375 z M 70.0625,77.53125 c 0.865391,0.02589 1.723666,0.03125 2.625,0.03125 0.912062,0 1.782843,-0.0048 2.65625,-0.03125 -0.165173,2.736408 -0.453252,5.207651 -0.84375,7.15625 -0.152345,0.760206 -0.322989,1.438994 -0.5,2.03125 -0.437447,0.03919 -0.895856,0.0625 -1.34375,0.0625 -0.414943,0 -0.812719,-0.02881 -1.21875,-0.0625 -0.177011,-0.592256 -0.347655,-1.271044 -0.5,-2.03125 -0.390498,-1.948599 -0.700644,-4.419842 -0.875,-7.15625 z m 1.75,10.28125 c 0.284911,0.01545 0.554954,0.03125 0.84375,0.03125 0.325029,0 0.648588,-0.01171 0.96875,-0.03125 -0.05999,0.148763 -0.127309,0.31046 -0.1875,0.4375 -0.18789,0.396562 -0.386962,0.696416 -0.53125,0.84375 -0.144288,0.147334 -0.181857,0.125 -0.1875,0.125 -0.0056,0 -0.07446,0.02233 -0.21875,-0.125 C 72.355712,88.946416 72.18789,88.646562 72,88.25 71.939809,88.12296 71.872486,87.961263 71.8125,87.8125 z';
7 | });
--------------------------------------------------------------------------------
/Source/SvgPaths/svgCompassOuterRing.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | ], function () {
4 | 'use strict';
5 |
6 | return 'm 66.5625,0 0,15.15625 3.71875,0 0,-10.40625 5.5,10.40625 4.375,0 0,-15.15625 -3.71875,0 0,10.40625 L 70.9375,0 66.5625,0 z M 72.5,20.21875 c -28.867432,0 -52.28125,23.407738 -52.28125,52.28125 0,28.87351 23.413818,52.3125 52.28125,52.3125 28.86743,0 52.28125,-23.43899 52.28125,-52.3125 0,-28.873512 -23.41382,-52.28125 -52.28125,-52.28125 z m 0,1.75 c 13.842515,0 26.368948,5.558092 35.5,14.5625 l -11.03125,11 0.625,0.625 11.03125,-11 c 8.9199,9.108762 14.4375,21.579143 14.4375,35.34375 0,13.764606 -5.5176,26.22729 -14.4375,35.34375 l -11.03125,-11 -0.625,0.625 11.03125,11 c -9.130866,9.01087 -21.658601,14.59375 -35.5,14.59375 -13.801622,0 -26.321058,-5.53481 -35.4375,-14.5 l 11.125,-11.09375 c 6.277989,6.12179 14.857796,9.90625 24.3125,9.90625 19.241896,0 34.875,-15.629154 34.875,-34.875 0,-19.245847 -15.633104,-34.84375 -34.875,-34.84375 -9.454704,0 -18.034511,3.760884 -24.3125,9.875 L 37.0625,36.4375 C 46.179178,27.478444 58.696991,21.96875 72.5,21.96875 z m -0.875,0.84375 0,13.9375 1.75,0 0,-13.9375 -1.75,0 z M 36.46875,37.0625 47.5625,48.15625 C 41.429794,54.436565 37.65625,63.027539 37.65625,72.5 c 0,9.472461 3.773544,18.055746 9.90625,24.34375 L 36.46875,107.9375 c -8.96721,-9.1247 -14.5,-21.624886 -14.5,-35.4375 0,-13.812615 5.53279,-26.320526 14.5,-35.4375 z M 72.5,39.40625 c 18.297686,0 33.125,14.791695 33.125,33.09375 0,18.302054 -14.827314,33.125 -33.125,33.125 -18.297687,0 -33.09375,-14.822946 -33.09375,-33.125 0,-18.302056 14.796063,-33.09375 33.09375,-33.09375 z M 22.84375,71.625 l 0,1.75 13.96875,0 0,-1.75 -13.96875,0 z m 85.5625,0 0,1.75 14,0 0,-1.75 -14,0 z M 71.75,108.25 l 0,13.9375 1.71875,0 0,-13.9375 -1.71875,0 z';
7 | });
--------------------------------------------------------------------------------
/Source/SvgPaths/svgCompassRotationMarker.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | ], function () {
4 | 'use strict';
5 |
6 | return 'M 72.46875,22.03125 C 59.505873,22.050338 46.521615,27.004287 36.6875,36.875 L 47.84375,47.96875 C 61.521556,34.240041 83.442603,34.227389 97.125,47.90625 l 11.125,-11.125 C 98.401629,26.935424 85.431627,22.012162 72.46875,22.03125 z';
7 | });
--------------------------------------------------------------------------------
/Source/SvgPaths/svgReset.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | ], function () {
4 | 'use strict';
5 |
6 | return 'M 7.5,0 C 3.375,0 0,3.375 0,7.5 0,11.625 3.375,15 7.5,15 c 3.46875,0 6.375,-2.4375 7.21875,-5.625 l -1.96875,0 C 12,11.53125 9.9375,13.125 7.5,13.125 4.40625,13.125 1.875,10.59375 1.875,7.5 1.875,4.40625 4.40625,1.875 7.5,1.875 c 1.59375,0 2.90625,0.65625 3.9375,1.6875 l -3,3 6.5625,0 L 15,0 12.75,2.25 C 11.4375,0.84375 9.5625,0 7.5,0 z';
7 | });
--------------------------------------------------------------------------------
/Source/ViewModels/DistanceLegendViewModel.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Core/DeveloperError',
5 | 'Cesium/Core/EllipsoidGeodesic',
6 | 'Cesium/Core/Cartesian2',
7 | 'Cesium/Core/getTimestamp',
8 | 'Cesium/Core/EventHelper',
9 | 'KnockoutES5',
10 | 'Core/loadView',
11 | 'leaflet'
12 | ], function (
13 | defined,
14 | DeveloperError,
15 | EllipsoidGeodesic,
16 | Cartesian2,
17 | getTimestamp,
18 | EventHelper,
19 | Knockout,
20 | loadView,
21 | leaflet) {
22 | 'use strict';
23 |
24 | var DistanceLegendViewModel = function (options) {
25 | if (!defined(options) || !defined(options.terria)) {
26 | throw new DeveloperError('options.terria is required.');
27 | }
28 |
29 | this.terria = options.terria;
30 | this._removeSubscription = undefined;
31 | this._lastLegendUpdate = undefined;
32 | this.eventHelper = new EventHelper();
33 |
34 | this.distanceLabel = undefined;
35 | this.barWidth = undefined;
36 |
37 | this.enableDistanceLegend = (defined(options.enableDistanceLegend))?options.enableDistanceLegend:true;
38 |
39 | Knockout.track(this, ['distanceLabel', 'barWidth']);
40 |
41 | this.eventHelper.add(this.terria.afterWidgetChanged, function () {
42 | if (defined(this._removeSubscription)) {
43 | this._removeSubscription();
44 | this._removeSubscription = undefined;
45 | }
46 | }, this);
47 | // this.terria.beforeWidgetChanged.addEventListener(function () {
48 | // if (defined(this._removeSubscription)) {
49 | // this._removeSubscription();
50 | // this._removeSubscription = undefined;
51 | // }
52 | // }, this);
53 |
54 | var that = this;
55 |
56 | function addUpdateSubscription() {
57 | if (defined(that.terria)) {
58 | var scene = that.terria.scene;
59 | that._removeSubscription = scene.postRender.addEventListener(function () {
60 | updateDistanceLegendCesium(this, scene);
61 | }, that);
62 | } else if (defined(that.terria.leaflet)) {
63 | var map = that.terria.leaflet.map;
64 |
65 | var potentialChangeCallback = function potentialChangeCallback() {
66 | updateDistanceLegendLeaflet(that, map);
67 | };
68 |
69 | that._removeSubscription = function () {
70 | map.off('zoomend', potentialChangeCallback);
71 | map.off('moveend', potentialChangeCallback);
72 | };
73 |
74 | map.on('zoomend', potentialChangeCallback);
75 | map.on('moveend', potentialChangeCallback);
76 |
77 | updateDistanceLegendLeaflet(that, map);
78 | }
79 | }
80 |
81 | addUpdateSubscription();
82 | this.eventHelper.add(this.terria.afterWidgetChanged, function () {
83 | addUpdateSubscription();
84 | }, this);
85 | //this.terria.afterWidgetChanged.addEventListener(function() {
86 | // addUpdateSubscription();
87 | // }, this);
88 | };
89 |
90 |
91 | DistanceLegendViewModel.prototype.destroy = function () {
92 |
93 | this.eventHelper.removeAll();
94 | };
95 |
96 | DistanceLegendViewModel.prototype.show = function (container) {
97 | var testing ;
98 | if ( this.enableDistanceLegend)
99 | {
100 | testing = '' +
101 | '
' +
102 | '
' +
103 | '
';
104 | }
105 | else
106 | {
107 | testing = '' +
108 | '
' +
109 | '
' +
110 | '
';
111 | }
112 | loadView(testing, container, this);
113 | // loadView(distanceLegendTemplate, container, this);
114 | //loadView(require('fs').readFileSync(__dirname + '/../Views/DistanceLegend.html', 'utf8'), container, this);
115 | };
116 |
117 | DistanceLegendViewModel.create = function (options) {
118 | var result = new DistanceLegendViewModel(options);
119 | result.show(options.container);
120 | return result;
121 | };
122 |
123 | var geodesic = new EllipsoidGeodesic();
124 |
125 | var distances = [
126 | 1, 2, 3, 5,
127 | 10, 20, 30, 50,
128 | 100, 200, 300, 500,
129 | 1000, 2000, 3000, 5000,
130 | 10000, 20000, 30000, 50000,
131 | 100000, 200000, 300000, 500000,
132 | 1000000, 2000000, 3000000, 5000000,
133 | 10000000, 20000000, 30000000, 50000000];
134 |
135 | function updateDistanceLegendCesium(viewModel, scene) {
136 | if (!viewModel.enableDistanceLegend)
137 | {
138 | viewModel.barWidth = undefined;
139 | viewModel.distanceLabel = undefined;
140 | return;
141 | }
142 | var now = getTimestamp();
143 | if (now < viewModel._lastLegendUpdate + 250) {
144 | return;
145 | }
146 |
147 | viewModel._lastLegendUpdate = now;
148 |
149 | // Find the distance between two pixels at the bottom center of the screen.
150 | var width = scene.canvas.clientWidth;
151 | var height = scene.canvas.clientHeight;
152 |
153 | var left = scene.camera.getPickRay(new Cartesian2((width / 2) | 0, height - 1));
154 | var right = scene.camera.getPickRay(new Cartesian2(1 + (width / 2) | 0, height - 1));
155 |
156 | var globe = scene.globe;
157 | var leftPosition = globe.pick(left, scene);
158 | var rightPosition = globe.pick(right, scene);
159 |
160 | if (!defined(leftPosition) || !defined(rightPosition)) {
161 | viewModel.barWidth = undefined;
162 | viewModel.distanceLabel = undefined;
163 | return;
164 | }
165 |
166 | var leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition);
167 | var rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition);
168 |
169 | geodesic.setEndPoints(leftCartographic, rightCartographic);
170 | var pixelDistance = geodesic.surfaceDistance;
171 |
172 | // Find the first distance that makes the scale bar less than 100 pixels.
173 | var maxBarWidth = 100;
174 | var distance;
175 | for (var i = distances.length - 1; !defined(distance) && i >= 0; --i) {
176 | if (distances[i] / pixelDistance < maxBarWidth) {
177 | distance = distances[i];
178 | }
179 | }
180 |
181 | if (defined(distance)) {
182 | var label;
183 | if (distance >= 1000) {
184 | label = (distance / 1000).toString() + ' km';
185 | } else {
186 | label = distance.toString() + ' m';
187 | }
188 |
189 | viewModel.barWidth = (distance / pixelDistance) | 0;
190 | viewModel.distanceLabel = label;
191 | } else {
192 | viewModel.barWidth = undefined;
193 | viewModel.distanceLabel = undefined;
194 | }
195 | }
196 |
197 | function updateDistanceLegendLeaflet(viewModel, map) {
198 | var halfHeight = map.getSize().y / 2;
199 | var maxPixelWidth = 100;
200 | var maxMeters = map.containerPointToLatLng([0, halfHeight]).distanceTo(
201 | map.containerPointToLatLng([maxPixelWidth, halfHeight]));
202 |
203 | var meters = leaflet.control.scale()._getRoundNum(maxMeters);
204 | var label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
205 |
206 | viewModel.barWidth = (meters / maxMeters) * maxPixelWidth;
207 | viewModel.distanceLabel = label;
208 | }
209 |
210 | return DistanceLegendViewModel;
211 | });
212 |
--------------------------------------------------------------------------------
/Source/ViewModels/NavigationControl.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'ViewModels/UserInterfaceControl'
4 | ], function (
5 | UserInterfaceControl) {
6 | 'use strict';
7 |
8 | /**
9 | * The view-model for a control in the navigation control tool bar
10 | *
11 | * @alias NavigationControl
12 | * @constructor
13 | * @abstract
14 | *
15 | * @param {Terria} terria The Terria instance.
16 | */
17 | var NavigationControl = function (terria) {
18 | UserInterfaceControl.apply(this, arguments);
19 | };
20 |
21 | NavigationControl.prototype = Object.create(UserInterfaceControl.prototype);
22 |
23 | return NavigationControl;
24 | });
25 |
--------------------------------------------------------------------------------
/Source/ViewModels/NavigationViewModel.js:
--------------------------------------------------------------------------------
1 | /*global define*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Core/Math',
5 | 'Cesium/Core/getTimestamp',
6 | 'Cesium/Core/EventHelper',
7 | 'Cesium/Core/Transforms',
8 | 'Cesium/Scene/SceneMode',
9 | 'Cesium/Core/Cartesian2',
10 | 'Cesium/Core/Cartesian3',
11 | 'Cesium/Core/Matrix4',
12 | 'Cesium/Core/BoundingSphere',
13 | 'Cesium/Core/HeadingPitchRange',
14 | 'KnockoutES5',
15 | 'Core/loadView',
16 | 'ViewModels/ResetViewNavigationControl',
17 | 'ViewModels/ZoomNavigationControl',
18 | 'SvgPaths/svgCompassOuterRing',
19 | 'SvgPaths/svgCompassGyro',
20 | 'SvgPaths/svgCompassRotationMarker',
21 | 'Core/Utils'
22 | ], function (
23 | defined,
24 | CesiumMath,
25 | getTimestamp,
26 | EventHelper,
27 | Transforms,
28 | SceneMode,
29 | Cartesian2,
30 | Cartesian3,
31 | Matrix4,
32 | BoundingSphere,
33 | HeadingPitchRange,
34 | Knockout,
35 | loadView,
36 | ResetViewNavigationControl,
37 | ZoomNavigationControl,
38 | svgCompassOuterRing,
39 | svgCompassGyro,
40 | svgCompassRotationMarker,
41 | Utils)
42 | {
43 | 'use strict';
44 |
45 | var NavigationViewModel = function (options)
46 | {
47 |
48 | this.terria = options.terria;
49 | this.eventHelper = new EventHelper();
50 | this.enableZoomControls = (defined(options.enableZoomControls))?options.enableZoomControls:true;
51 | this.enableCompass = (defined(options.enableCompass))?options.enableCompass:true;
52 |
53 | // if (this.showZoomControls)
54 | // {
55 | this.controls = options.controls;
56 | if (!defined(this.controls))
57 | {
58 | this.controls = [
59 | new ZoomNavigationControl(this.terria, true),
60 | new ResetViewNavigationControl(this.terria),
61 | new ZoomNavigationControl(this.terria, false)
62 | ];
63 | }
64 | //}
65 |
66 | this.svgCompassOuterRing = svgCompassOuterRing;
67 | this.svgCompassGyro = svgCompassGyro;
68 | this.svgCompassRotationMarker = svgCompassRotationMarker;
69 |
70 | this.showCompass = defined(this.terria) && this.enableCompass;
71 | this.heading = this.showCompass ? this.terria.scene.camera.heading : 0.0;
72 |
73 | this.isOrbiting = false;
74 | this.orbitCursorAngle = 0;
75 | this.orbitCursorOpacity = 0.0;
76 | this.orbitLastTimestamp = 0;
77 | this.orbitFrame = undefined;
78 | this.orbitIsLook = false;
79 | this.orbitMouseMoveFunction = undefined;
80 | this.orbitMouseUpFunction = undefined;
81 |
82 | this.isRotating = false;
83 | this.rotateInitialCursorAngle = undefined;
84 | this.rotateFrame = undefined;
85 | this.rotateIsLook = false;
86 | this.rotateMouseMoveFunction = undefined;
87 | this.rotateMouseUpFunction = undefined;
88 |
89 | this._unsubcribeFromPostRender = undefined;
90 |
91 | Knockout.track(this, ['controls', 'showCompass', 'heading', 'isOrbiting', 'orbitCursorAngle', 'isRotating']);
92 |
93 | var that = this;
94 |
95 | function widgetChange()
96 | {
97 | if (defined(that.terria))
98 | {
99 | if (that._unsubcribeFromPostRender)
100 | {
101 | that._unsubcribeFromPostRender();
102 | that._unsubcribeFromPostRender = undefined;
103 | }
104 |
105 | that.showCompass = true && that.enableCompass;
106 |
107 | that._unsubcribeFromPostRender = that.terria.scene.postRender.addEventListener(function ()
108 | {
109 | that.heading = that.terria.scene.camera.heading;
110 | });
111 | }
112 | else
113 | {
114 | if (that._unsubcribeFromPostRender)
115 | {
116 | that._unsubcribeFromPostRender();
117 | that._unsubcribeFromPostRender = undefined;
118 | }
119 | that.showCompass = false;
120 | }
121 | }
122 |
123 | this.eventHelper.add(this.terria.afterWidgetChanged, widgetChange, this);
124 | //this.terria.afterWidgetChanged.addEventListener(widgetChange);
125 |
126 | widgetChange();
127 | };
128 |
129 |
130 | NavigationViewModel.prototype.destroy = function ()
131 | {
132 |
133 | this.eventHelper.removeAll();
134 |
135 | //loadView(require('fs').readFileSync(baseURLEmpCesium + 'js-lib/terrajs/lib/Views/Navigation.html', 'utf8'), container, this);
136 |
137 | };
138 |
139 | NavigationViewModel.prototype.show = function (container)
140 | {
141 | var testing;
142 | if (this.enableZoomControls && this.enableCompass)
143 | {
144 | testing = '' +
148 | '
' +
149 | '
' +
150 | '
' +
151 | '
' +
152 | '
' +
153 | '
' +
154 | '' +
155 | '' +
156 | '
' +
157 | ' ' +
158 | '
' +
159 | ' ' +
160 | ' ' +
161 | '
' +
162 | ' ' +
163 | '
' +
164 | ' ' +
165 | '
';
166 | }
167 | else if (!this.enableZoomControls && this.enableCompass)
168 | {
169 | testing = '' +
173 | '
' +
174 | '
' +
175 | '
' +
176 | '
' +
177 | '
' +
178 | '
' +
179 | '' +
180 | '' +
181 | '
' +
182 | ' ' +
183 | '
' +
184 | ' ' +
185 | ' ' +
186 | '
' +
187 | ' ' +
188 | '
' +
189 | ' ' +
190 | '
';
191 | }
192 | else if (this.enableZoomControls && !this.enableCompass)
193 | {
194 | testing = '' +
198 | '
' +
199 | '
' +
200 | '
' +
201 | '
' +
202 | '
' +
203 | '
' +
204 | '' +
205 | '' +
206 | '
' +
207 | ' ' +
208 | '
' +
209 | ' ' +
210 | ' ' +
211 | '
' +
212 | ' ' +
213 | '
' +
214 | ' ' +
215 | '
';
216 | }
217 | else if (!this.enableZoomControls && !this.enableCompass)
218 | {
219 | testing = '' +
223 | '
' +
224 | '
' +
225 | '
' +
226 | '
' +
227 | '
' +
228 | '
' +
229 | '' +
230 | '' +
231 | '
' +
232 | ' ' +
233 | '
' +
234 | ' ' +
235 | ' ' +
236 | '
' +
237 | ' ' +
238 | '
' +
239 | ' ' +
240 | '
';
241 | }
242 | loadView(testing, container, this);
243 | // loadView(navigatorTemplate, container, this);
244 | //loadView(require('fs').readFileSync(baseURLEmpCesium + 'js-lib/terrajs/lib/Views/Navigation.html', 'utf8'), container, this);
245 |
246 | };
247 |
248 | /**
249 | * Adds a control to this toolbar.
250 | * @param {NavControl} control The control to add.
251 | */
252 | NavigationViewModel.prototype.add = function (control)
253 | {
254 | this.controls.push(control);
255 | };
256 |
257 | /**
258 | * Removes a control from this toolbar.
259 | * @param {NavControl} control The control to remove.
260 | */
261 | NavigationViewModel.prototype.remove = function (control)
262 | {
263 | this.controls.remove(control);
264 | };
265 |
266 | /**
267 | * Checks if the control given is the last control in the control array.
268 | * @param {NavControl} control The control to remove.
269 | */
270 | NavigationViewModel.prototype.isLastControl = function (control)
271 | {
272 | return (control === this.controls[this.controls.length - 1]);
273 | };
274 |
275 | var vectorScratch = new Cartesian2();
276 |
277 | NavigationViewModel.prototype.handleMouseDown = function (viewModel, e)
278 | {
279 | var scene = this.terria.scene;
280 | if (scene.mode === SceneMode.MORPHING)
281 | {
282 | return true;
283 | }
284 |
285 | var compassElement = e.currentTarget;
286 | var compassRectangle = e.currentTarget.getBoundingClientRect();
287 | var maxDistance = compassRectangle.width / 2.0;
288 | var center = new Cartesian2((compassRectangle.right - compassRectangle.left) / 2.0, (compassRectangle.bottom - compassRectangle.top) / 2.0);
289 | var clickLocation = new Cartesian2(e.clientX - compassRectangle.left, e.clientY - compassRectangle.top);
290 | var vector = Cartesian2.subtract(clickLocation, center, vectorScratch);
291 | var distanceFromCenter = Cartesian2.magnitude(vector);
292 |
293 | var distanceFraction = distanceFromCenter / maxDistance;
294 |
295 | var nominalTotalRadius = 145;
296 | var norminalGyroRadius = 50;
297 |
298 | if (distanceFraction < norminalGyroRadius / nominalTotalRadius)
299 | {
300 | orbit(this, compassElement, vector);
301 | // return false;
302 | }
303 | else if (distanceFraction < 1.0)
304 | {
305 | rotate(this, compassElement, vector);
306 | // return false;
307 | }
308 | else
309 | {
310 | return true;
311 | }
312 | };
313 |
314 | var oldTransformScratch = new Matrix4();
315 | var newTransformScratch = new Matrix4();
316 | var centerScratch = new Cartesian3();
317 |
318 | NavigationViewModel.prototype.handleDoubleClick = function (viewModel, e)
319 | {
320 | var scene = viewModel.terria.scene;
321 | var camera = scene.camera;
322 |
323 | var sscc = scene.screenSpaceCameraController;
324 |
325 | if (scene.mode == SceneMode.MORPHING || !sscc.enableInputs) {
326 | return true;
327 | }
328 | if (scene.mode == SceneMode.COLUMBUS_VIEW && !sscc.enableTranslate) {
329 | return;
330 | }
331 | if(scene.mode == SceneMode.SCENE3D || scene.mode == SceneMode.COLUMBUS_VIEW) {
332 | if (!sscc.enableLook) {
333 | return;
334 | }
335 |
336 | if(scene.mode == SceneMode.SCENE3D) {
337 | if(!sscc.enableRotate) {
338 | return
339 | }
340 | }
341 | }
342 |
343 | var center = Utils.getCameraFocus(viewModel.terria, true, centerScratch);
344 |
345 | if (!defined(center))
346 | {
347 | // Globe is barely visible, so reset to home view.
348 |
349 | this.controls[1].resetView();
350 | return;
351 | }
352 |
353 | var cameraPosition = scene.globe.ellipsoid.cartographicToCartesian(camera.positionCartographic, new Cartesian3());
354 |
355 | var surfaceNormal = scene.globe.ellipsoid.geodeticSurfaceNormal(center);
356 |
357 | var focusBoundingSphere = new BoundingSphere(center, 0);
358 |
359 | camera.flyToBoundingSphere(focusBoundingSphere, {
360 | offset: new HeadingPitchRange(0,
361 | // do not use camera.pitch since the pitch at the center/target is required
362 | CesiumMath.PI_OVER_TWO - Cartesian3.angleBetween(
363 | surfaceNormal,
364 | camera.directionWC
365 | ),
366 | // distanceToBoundingSphere returns wrong values when in 2D or Columbus view so do not use
367 | // camera.distanceToBoundingSphere(focusBoundingSphere)
368 | // instead calculate distance manually
369 | Cartesian3.distance(cameraPosition, center)
370 | ),
371 | duration: 1.5
372 | });
373 | };
374 |
375 | NavigationViewModel.create = function (options)
376 | {
377 | //options.enableZoomControls = this.enableZoomControls;
378 | //options.enableCompass = this.enableCompass;
379 | var result = new NavigationViewModel(options);
380 | result.show(options.container);
381 | return result;
382 | };
383 |
384 | function orbit(viewModel, compassElement, cursorVector){
385 | var scene = viewModel.terria.scene;
386 |
387 |
388 | var sscc = scene.screenSpaceCameraController;
389 |
390 | // do not orbit if it is disabled
391 | if(scene.mode == SceneMode.MORPHING || !sscc.enableInputs) {
392 | return;
393 | }
394 |
395 | switch(scene.mode) {
396 | case SceneMode.COLUMBUS_VIEW:
397 | if(sscc.enableLook) {
398 | break;
399 | }
400 |
401 | if (!sscc.enableTranslate || !sscc.enableTilt) {
402 | return;
403 | }
404 | break;
405 | case SceneMode.SCENE3D:
406 | if(sscc.enableLook) {
407 | break;
408 | }
409 |
410 | if (!sscc.enableTilt || !sscc.enableRotate) {
411 | return;
412 | }
413 | break;
414 | case SceneMode.SCENE2D:
415 | if (!sscc.enableTranslate) {
416 | return;
417 | }
418 | break;
419 | }
420 |
421 | // Remove existing event handlers, if any.
422 | document.removeEventListener('mousemove', viewModel.orbitMouseMoveFunction, false);
423 | document.removeEventListener('mouseup', viewModel.orbitMouseUpFunction, false);
424 |
425 | if (defined(viewModel.orbitTickFunction))
426 | {
427 | viewModel.terria.clock.onTick.removeEventListener(viewModel.orbitTickFunction);
428 | }
429 |
430 | viewModel.orbitMouseMoveFunction = undefined;
431 | viewModel.orbitMouseUpFunction = undefined;
432 | viewModel.orbitTickFunction = undefined;
433 |
434 | viewModel.isOrbiting = true;
435 | viewModel.orbitLastTimestamp = getTimestamp();
436 |
437 | var camera = scene.camera;
438 |
439 | if (defined(viewModel.terria.trackedEntity)) {
440 | // when tracking an entity simply use that reference frame
441 | viewModel.orbitFrame = undefined;
442 | viewModel.orbitIsLook = false;
443 | } else {
444 | var center = Utils.getCameraFocus(viewModel.terria, true, centerScratch);
445 |
446 | if (!defined(center))
447 | {
448 | viewModel.orbitFrame = Transforms.eastNorthUpToFixedFrame(camera.positionWC, scene.globe.ellipsoid, newTransformScratch);
449 | viewModel.orbitIsLook = true;
450 | }
451 | else
452 | {
453 | viewModel.orbitFrame = Transforms.eastNorthUpToFixedFrame(center, scene.globe.ellipsoid, newTransformScratch);
454 | viewModel.orbitIsLook = false;
455 | }
456 | }
457 |
458 | viewModel.orbitTickFunction = function (e)
459 | {
460 | var timestamp = getTimestamp();
461 | var deltaT = timestamp - viewModel.orbitLastTimestamp;
462 | var rate = (viewModel.orbitCursorOpacity - 0.5) * 2.5 / 1000;
463 | var distance = deltaT * rate;
464 |
465 | var angle = viewModel.orbitCursorAngle + CesiumMath.PI_OVER_TWO;
466 | var x = Math.cos(angle) * distance;
467 | var y = Math.sin(angle) * distance;
468 |
469 | var oldTransform;
470 |
471 | if (defined(viewModel.orbitFrame)) {
472 | oldTransform = Matrix4.clone(camera.transform, oldTransformScratch);
473 |
474 | camera.lookAtTransform(viewModel.orbitFrame);
475 | }
476 |
477 | // do not look up/down or rotate in 2D mode
478 | if (scene.mode == SceneMode.SCENE2D)
479 | {
480 | camera.move(new Cartesian3(x, y, 0), Math.max(scene.canvas.clientWidth, scene.canvas.clientHeight) / 100 * camera.positionCartographic.height * distance);
481 | }
482 | else
483 | {
484 | if (viewModel.orbitIsLook)
485 | {
486 | camera.look(Cartesian3.UNIT_Z, -x);
487 | camera.look(camera.right, -y);
488 | }
489 | else
490 | {
491 | camera.rotateLeft(x);
492 | camera.rotateUp(y);
493 | }
494 | }
495 |
496 | if (defined(viewModel.orbitFrame)) {
497 | camera.lookAtTransform(oldTransform);
498 | }
499 |
500 | // viewModel.terria.cesium.notifyRepaintRequired();
501 |
502 | viewModel.orbitLastTimestamp = timestamp;
503 | };
504 |
505 | function updateAngleAndOpacity(vector, compassWidth)
506 | {
507 | var angle = Math.atan2(-vector.y, vector.x);
508 | viewModel.orbitCursorAngle = CesiumMath.zeroToTwoPi(angle - CesiumMath.PI_OVER_TWO);
509 |
510 | var distance = Cartesian2.magnitude(vector);
511 | var maxDistance = compassWidth / 2.0;
512 | var distanceFraction = Math.min(distance / maxDistance, 1.0);
513 | var easedOpacity = 0.5 * distanceFraction * distanceFraction + 0.5;
514 | viewModel.orbitCursorOpacity = easedOpacity;
515 |
516 | //viewModel.terria.cesium.notifyRepaintRequired();
517 | }
518 |
519 | viewModel.orbitMouseMoveFunction = function (e)
520 | {
521 | var compassRectangle = compassElement.getBoundingClientRect();
522 | var center = new Cartesian2((compassRectangle.right - compassRectangle.left) / 2.0, (compassRectangle.bottom - compassRectangle.top) / 2.0);
523 | var clickLocation = new Cartesian2(e.clientX - compassRectangle.left, e.clientY - compassRectangle.top);
524 | var vector = Cartesian2.subtract(clickLocation, center, vectorScratch);
525 | updateAngleAndOpacity(vector, compassRectangle.width);
526 | };
527 |
528 | viewModel.orbitMouseUpFunction = function (e)
529 | {
530 | // TODO: if mouse didn't move, reset view to looking down, north is up?
531 |
532 | viewModel.isOrbiting = false;
533 | document.removeEventListener('mousemove', viewModel.orbitMouseMoveFunction, false);
534 | document.removeEventListener('mouseup', viewModel.orbitMouseUpFunction, false);
535 |
536 | if (defined(viewModel.orbitTickFunction))
537 | {
538 | viewModel.terria.clock.onTick.removeEventListener(viewModel.orbitTickFunction);
539 | }
540 |
541 | viewModel.orbitMouseMoveFunction = undefined;
542 | viewModel.orbitMouseUpFunction = undefined;
543 | viewModel.orbitTickFunction = undefined;
544 | };
545 |
546 | document.addEventListener('mousemove', viewModel.orbitMouseMoveFunction, false);
547 | document.addEventListener('mouseup', viewModel.orbitMouseUpFunction, false);
548 | viewModel.terria.clock.onTick.addEventListener(viewModel.orbitTickFunction);
549 |
550 | updateAngleAndOpacity(cursorVector, compassElement.getBoundingClientRect().width);
551 | }
552 |
553 | function rotate(viewModel, compassElement, cursorVector)
554 | {
555 | var scene = viewModel.terria.scene;
556 | var camera = scene.camera;
557 |
558 | var sscc = scene.screenSpaceCameraController;
559 | // do not rotate in 2D mode or if rotating is disabled
560 | if (scene.mode == SceneMode.MORPHING || scene.mode == SceneMode.SCENE2D || !sscc.enableInputs) {
561 | return;
562 | }
563 | if(!sscc.enableLook && (scene.mode == SceneMode.COLUMBUS_VIEW || (scene.mode == SceneMode.SCENE3D && !sscc.enableRotate))) {
564 | return;
565 | }
566 |
567 | // Remove existing event handlers, if any.
568 | document.removeEventListener('mousemove', viewModel.rotateMouseMoveFunction, false);
569 | document.removeEventListener('mouseup', viewModel.rotateMouseUpFunction, false);
570 |
571 | viewModel.rotateMouseMoveFunction = undefined;
572 | viewModel.rotateMouseUpFunction = undefined;
573 |
574 | viewModel.isRotating = true;
575 | viewModel.rotateInitialCursorAngle = Math.atan2(-cursorVector.y, cursorVector.x);
576 |
577 | if(defined(viewModel.terria.trackedEntity)) {
578 | // when tracking an entity simply use that reference frame
579 | viewModel.rotateFrame = undefined;
580 | viewModel.rotateIsLook = false;
581 | } else {
582 | var viewCenter = Utils.getCameraFocus(viewModel.terria, true, centerScratch);
583 |
584 | if (!defined(viewCenter) || (scene.mode == SceneMode.COLUMBUS_VIEW && !sscc.enableLook && !sscc.enableTranslate))
585 | {
586 | viewModel.rotateFrame = Transforms.eastNorthUpToFixedFrame(camera.positionWC, scene.globe.ellipsoid, newTransformScratch);
587 | viewModel.rotateIsLook = true;
588 | }
589 | else
590 | {
591 | viewModel.rotateFrame = Transforms.eastNorthUpToFixedFrame(viewCenter, scene.globe.ellipsoid, newTransformScratch);
592 | viewModel.rotateIsLook = false;
593 | }
594 | }
595 |
596 | var oldTransform;
597 | if(defined(viewModel.rotateFrame)) {
598 | oldTransform = Matrix4.clone(camera.transform, oldTransformScratch);
599 | camera.lookAtTransform(viewModel.rotateFrame);
600 | }
601 |
602 | viewModel.rotateInitialCameraAngle = -camera.heading;
603 |
604 | if(defined(viewModel.rotateFrame)) {
605 | camera.lookAtTransform(oldTransform);
606 | }
607 |
608 | viewModel.rotateMouseMoveFunction = function (e)
609 | {
610 | var compassRectangle = compassElement.getBoundingClientRect();
611 | var center = new Cartesian2((compassRectangle.right - compassRectangle.left) / 2.0, (compassRectangle.bottom - compassRectangle.top) / 2.0);
612 | var clickLocation = new Cartesian2(e.clientX - compassRectangle.left, e.clientY - compassRectangle.top);
613 | var vector = Cartesian2.subtract(clickLocation, center, vectorScratch);
614 | var angle = Math.atan2(-vector.y, vector.x);
615 |
616 | var angleDifference = angle - viewModel.rotateInitialCursorAngle;
617 | var newCameraAngle = CesiumMath.zeroToTwoPi(viewModel.rotateInitialCameraAngle - angleDifference);
618 |
619 | var camera = viewModel.terria.scene.camera;
620 |
621 | var oldTransform;
622 | if(defined(viewModel.rotateFrame)) {
623 | oldTransform = Matrix4.clone(camera.transform, oldTransformScratch);
624 | camera.lookAtTransform(viewModel.rotateFrame);
625 | }
626 |
627 | var currentCameraAngle = -camera.heading;
628 | camera.rotateRight(newCameraAngle - currentCameraAngle);
629 |
630 | if(defined(viewModel.rotateFrame)) {
631 | camera.lookAtTransform(oldTransform);
632 | }
633 |
634 | // viewModel.terria.cesium.notifyRepaintRequired();
635 | };
636 |
637 | viewModel.rotateMouseUpFunction = function (e)
638 | {
639 | viewModel.isRotating = false;
640 | document.removeEventListener('mousemove', viewModel.rotateMouseMoveFunction, false);
641 | document.removeEventListener('mouseup', viewModel.rotateMouseUpFunction, false);
642 |
643 | viewModel.rotateMouseMoveFunction = undefined;
644 | viewModel.rotateMouseUpFunction = undefined;
645 | };
646 |
647 | document.addEventListener('mousemove', viewModel.rotateMouseMoveFunction, false);
648 | document.addEventListener('mouseup', viewModel.rotateMouseUpFunction, false);
649 | }
650 |
651 | return NavigationViewModel;
652 | });
653 |
--------------------------------------------------------------------------------
/Source/ViewModels/ResetViewNavigationControl.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Scene/Camera',
5 | 'Cesium/Core/Rectangle',
6 | 'Cesium/Core/Cartographic',
7 | 'ViewModels/NavigationControl',
8 | 'SvgPaths/svgReset'
9 | ], function (
10 | defined,
11 | Camera,
12 | Rectangle,
13 | Cartographic,
14 | NavigationControl,
15 | svgReset) {
16 | 'use strict';
17 |
18 | /**
19 | * The model for a zoom in control in the navigation control tool bar
20 | *
21 | * @alias ResetViewNavigationControl
22 | * @constructor
23 | * @abstract
24 | *
25 | * @param {Terria} terria The Terria instance.
26 | */
27 | var ResetViewNavigationControl = function (terria) {
28 | NavigationControl.apply(this, arguments);
29 |
30 | /**
31 | * Gets or sets the name of the control which is set as the control's title.
32 | * This property is observable.
33 | * @type {String}
34 | */
35 | this.name = 'Reset View';
36 |
37 | /**
38 | * Gets or sets the svg icon of the control. This property is observable.
39 | * @type {Object}
40 | */
41 | this.svgIcon = svgReset;
42 |
43 | /**
44 | * Gets or sets the height of the svg icon. This property is observable.
45 | * @type {Integer}
46 | */
47 | this.svgHeight = 15;
48 |
49 | /**
50 | * Gets or sets the width of the svg icon. This property is observable.
51 | * @type {Integer}
52 | */
53 | this.svgWidth = 15;
54 |
55 | /**
56 | * Gets or sets the CSS class of the control. This property is observable.
57 | * @type {String}
58 | */
59 | this.cssClass = "navigation-control-icon-reset";
60 |
61 | };
62 |
63 | ResetViewNavigationControl.prototype = Object.create(NavigationControl.prototype);
64 |
65 | ResetViewNavigationControl.prototype.resetView = function () {
66 | //this.terria.analytics.logEvent('navigation', 'click', 'reset');
67 |
68 | var scene = this.terria.scene;
69 |
70 | var sscc = scene.screenSpaceCameraController;
71 | if (!sscc.enableInputs) {
72 | return;
73 | }
74 |
75 | this.isActive = true;
76 |
77 | var camera = scene.camera;
78 |
79 | if (defined(this.terria.trackedEntity)) {
80 | // when tracking do not reset to default view but to default view of tracked entity
81 | var trackedEntity = this.terria.trackedEntity;
82 | this.terria.trackedEntity = undefined;
83 | this.terria.trackedEntity = trackedEntity;
84 | } else {
85 | // reset to a default position or view defined in the options
86 | if (this.terria.options.defaultResetView) {
87 | if (this.terria.options.defaultResetView && this.terria.options.defaultResetView instanceof Cartographic) {
88 | camera.flyTo({
89 | destination: scene.globe.ellipsoid.cartographicToCartesian(this.terria.options.defaultResetView)
90 | });
91 | } else if (this.terria.options.defaultResetView && this.terria.options.defaultResetView instanceof Rectangle) {
92 | try {
93 | Rectangle.validate(this.terria.options.defaultResetView);
94 | camera.flyTo({
95 | destination: this.terria.options.defaultResetView
96 | });
97 | } catch (e) {
98 | console.log("Cesium-navigation/ResetViewNavigationControl: options.defaultResetView Cesium rectangle is invalid!");
99 | }
100 | }
101 | }
102 | else if (typeof camera.flyHome === "function") {
103 | camera.flyHome(1);
104 | } else {
105 | camera.flyTo({'destination': Camera.DEFAULT_VIEW_RECTANGLE, 'duration': 1});
106 | }
107 | }
108 | this.isActive = false;
109 | };
110 |
111 | /**
112 | * When implemented in a derived class, performs an action when the user clicks
113 | * on this control
114 | * @abstract
115 | * @protected
116 | */
117 | ResetViewNavigationControl.prototype.activate = function () {
118 | this.resetView();
119 | };
120 |
121 | return ResetViewNavigationControl;
122 | });
123 |
--------------------------------------------------------------------------------
/Source/ViewModels/UserInterfaceControl.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Core/defineProperties',
5 | 'Cesium/Core/DeveloperError',
6 | 'KnockoutES5'
7 | ], function (
8 | defined,
9 | defineProperties,
10 | DeveloperError,
11 | Knockout) {
12 | 'use strict';
13 |
14 | /**
15 | * The view-model for a control in the user interface
16 | *
17 | * @alias UserInterfaceControl
18 | * @constructor
19 | * @abstract
20 | *
21 | * @param {Terria} terria The Terria instance.
22 | */
23 | var UserInterfaceControl = function (terria) {
24 |
25 | if (!defined(terria)) {
26 | throw new DeveloperError('terria is required');
27 | }
28 |
29 | this._terria = terria;
30 |
31 | /**
32 | * Gets or sets the name of the control which is set as the controls title.
33 | * This property is observable.
34 | * @type {String}
35 | */
36 | this.name = 'Unnamed Control';
37 |
38 | /**
39 | * Gets or sets the text to be displayed in the UI control.
40 | * This property is observable.
41 | * @type {String}
42 | */
43 | this.text = undefined;
44 |
45 | /**
46 | * Gets or sets the svg icon of the control. This property is observable.
47 | * @type {Object}
48 | */
49 | this.svgIcon = undefined;
50 |
51 | /**
52 | * Gets or sets the height of the svg icon. This property is observable.
53 | * @type {Integer}
54 | */
55 | this.svgHeight = undefined;
56 |
57 | /**
58 | * Gets or sets the width of the svg icon. This property is observable.
59 | * @type {Integer}
60 | */
61 | this.svgWidth = undefined;
62 |
63 | /**
64 | * Gets or sets the CSS class of the control. This property is observable.
65 | * @type {String}
66 | */
67 | this.cssClass = undefined;
68 |
69 | /**
70 | * Gets or sets the property describing whether or not the control is in the active state.
71 | * This property is observable.
72 | * @type {Boolean}
73 | */
74 | this.isActive = false;
75 |
76 | Knockout.track(this, ['name', 'svgIcon', 'svgHeight', 'svgWidth', 'cssClass', 'isActive']);
77 | };
78 |
79 | defineProperties(UserInterfaceControl.prototype, {
80 | /**
81 | * Gets the Terria instance.
82 | * @memberOf UserInterfaceControl.prototype
83 | * @type {Terria}
84 | */
85 | terria: {
86 | get: function () {
87 | return this._terria;
88 | }
89 | },
90 | /**
91 | * Gets a value indicating whether this button has text associated with it.
92 | * @type {Object}
93 | */
94 | hasText: {
95 | get: function () {
96 | return defined(this.text) && typeof this.text === 'string';
97 | }
98 | }
99 |
100 | });
101 |
102 | /**
103 | * When implemented in a derived class, performs an action when the user clicks
104 | * on this control.
105 | * @abstract
106 | * @protected
107 | */
108 | UserInterfaceControl.prototype.activate = function () {
109 | throw new DeveloperError('activate must be implemented in the derived class.');
110 | };
111 |
112 | return UserInterfaceControl;
113 | });
114 |
--------------------------------------------------------------------------------
/Source/ViewModels/ZoomNavigationControl.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | define([
3 | 'Cesium/Core/defined',
4 | 'Cesium/Core/Ray',
5 | 'Cesium/Core/IntersectionTests',
6 | 'Cesium/Core/Cartesian3',
7 | 'Cesium/Scene/SceneMode',
8 | 'ViewModels/NavigationControl',
9 | 'Core/Utils'
10 | ], function (
11 | defined,
12 | Ray,
13 | IntersectionTests,
14 | Cartesian3,
15 | SceneMode,
16 | NavigationControl,
17 | Utils) {
18 | 'use strict';
19 |
20 | /**
21 | * The model for a zoom in control in the navigation control tool bar
22 | *
23 | * @alias ZoomOutNavigationControl
24 | * @constructor
25 | * @abstract
26 | *
27 | * @param {Terria} terria The Terria instance.
28 | * @param {boolean} zoomIn is used for zooming in (true) or out (false)
29 | */
30 | var ZoomNavigationControl = function (terria, zoomIn) {
31 | NavigationControl.apply(this, arguments);
32 |
33 | /**
34 | * Gets or sets the name of the control which is set as the control's title.
35 | * This property is observable.
36 | * @type {String}
37 | */
38 | this.name = 'Zoom ' + (zoomIn ? 'In' : 'Out');
39 |
40 | /**
41 | * Gets or sets the text to be displayed in the nav control. Controls that
42 | * have text do not display the svgIcon.
43 | * This property is observable.
44 | * @type {String}
45 | */
46 | this.text = zoomIn ? '+' : '-';
47 |
48 | /**
49 | * Gets or sets the CSS class of the control. This property is observable.
50 | * @type {String}
51 | */
52 | this.cssClass = 'navigation-control-icon-zoom-' + (zoomIn ? 'in' : 'out');
53 |
54 | this.relativeAmount = 2;
55 |
56 | if (zoomIn) {
57 | // this ensures that zooming in is the inverse of zooming out and vice versa
58 | // e.g. the camera position remains when zooming in and out
59 | this.relativeAmount = 1 / this.relativeAmount;
60 | }
61 | };
62 |
63 | ZoomNavigationControl.prototype.relativeAmount = 1;
64 |
65 | ZoomNavigationControl.prototype = Object.create(NavigationControl.prototype);
66 |
67 | /**
68 | * When implemented in a derived class, performs an action when the user clicks
69 | * on this control
70 | * @abstract
71 | * @protected
72 | */
73 | ZoomNavigationControl.prototype.activate = function () {
74 | this.zoom(this.relativeAmount);
75 | };
76 |
77 | var cartesian3Scratch = new Cartesian3();
78 |
79 | ZoomNavigationControl.prototype.zoom = function (relativeAmount) {
80 | // this.terria.analytics.logEvent('navigation', 'click', 'zoomIn');
81 |
82 | this.isActive = true;
83 |
84 | if (defined(this.terria)) {
85 | var scene = this.terria.scene;
86 |
87 | var sscc = scene.screenSpaceCameraController;
88 | // do not zoom if it is disabled
89 | if (!sscc.enableInputs || !sscc.enableZoom) {
90 | return;
91 | }
92 | // TODO
93 | // if(scene.mode == SceneMode.COLUMBUS_VIEW && !sscc.enableTranslate) {
94 | // return;
95 | // }
96 |
97 | var camera = scene.camera;
98 | var orientation;
99 |
100 | switch (scene.mode) {
101 | case SceneMode.MORPHING:
102 | break;
103 | case SceneMode.SCENE2D:
104 | camera.zoomIn(camera.positionCartographic.height * (1 - this.relativeAmount));
105 | break;
106 | default:
107 | var focus;
108 |
109 | if(defined(this.terria.trackedEntity)) {
110 | focus = new Cartesian3();
111 | } else {
112 | focus = Utils.getCameraFocus(this.terria, false);
113 | }
114 |
115 | if (!defined(focus)) {
116 | // Camera direction is not pointing at the globe, so use the ellipsoid horizon point as
117 | // the focal point.
118 | var ray = new Ray(camera.worldToCameraCoordinatesPoint(scene.globe.ellipsoid.cartographicToCartesian(camera.positionCartographic)), camera.directionWC);
119 | focus = IntersectionTests.grazingAltitudeLocation(ray, scene.globe.ellipsoid);
120 |
121 | orientation = {
122 | heading: camera.heading,
123 | pitch: camera.pitch,
124 | roll: camera.roll
125 | };
126 | } else {
127 | orientation = {
128 | direction: camera.direction,
129 | up: camera.up
130 | };
131 | }
132 |
133 | var direction = Cartesian3.subtract(camera.position, focus, cartesian3Scratch);
134 | var movementVector = Cartesian3.multiplyByScalar(direction, relativeAmount, direction);
135 | var endPosition = Cartesian3.add(focus, movementVector, focus);
136 |
137 | if (defined(this.terria.trackedEntity) || scene.mode == SceneMode.COLUMBUS_VIEW) {
138 | // sometimes flyTo does not work (jumps to wrong position) so just set the position without any animation
139 | // do not use flyTo when tracking an entity because during animatiuon the position of the entity may change
140 | camera.position = endPosition;
141 | } else {
142 | camera.flyTo({
143 | destination: endPosition,
144 | orientation: orientation,
145 | duration: 0.5,
146 | convert: false
147 | });
148 | }
149 | }
150 | }
151 |
152 | // this.terria.notifyRepaintRequired();
153 | this.isActive = false;
154 | };
155 |
156 | return ZoomNavigationControl;
157 | });
158 |
--------------------------------------------------------------------------------
/Source/copyrightHeader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Cesium Navigation - https://github.com/alberto-acevedo/cesium-navigation
3 | *
4 | * The plugin is 100% based on open source libraries. The same license that applies to Cesiumjs and terriajs applies also to this plugin. Feel free to use it, modify it, and improve it.
5 | */
--------------------------------------------------------------------------------
/Source/viewerCesiumNavigationMixin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Larcius on 18.02.16.
3 | */
4 | /*global define*/
5 | define([
6 | 'Cesium/Core/defined',
7 | 'Cesium/Core/defineProperties',
8 | 'Cesium/Core/DeveloperError',
9 | 'CesiumNavigation',
10 | 'require-less/less!Styles/cesium-navigation'
11 | ], function(
12 | defined,
13 | defineProperties,
14 | DeveloperError,
15 | CesiumNavigation) {
16 | 'use strict';
17 |
18 | /**
19 | * A mixin which adds the Compass/Navigation widget to the Viewer widget.
20 | * Rather than being called directly, this function is normally passed as
21 | * a parameter to {@link Viewer#extend}, as shown in the example below.
22 | * @exports viewerCesiumNavigationMixin
23 | *
24 | * @param {Viewer} viewer The viewer instance.
25 | * @param {{}} options The options.
26 | *
27 | * @exception {DeveloperError} viewer is required.
28 | *
29 | * @demo {@link http://localhost:8080/index.html|run local server with examples}
30 | *
31 | * @example
32 | * var viewer = new Cesium.Viewer('cesiumContainer');
33 | * viewer.extend(viewerCesiumNavigationMixin);
34 | */
35 | function viewerCesiumNavigationMixin(viewer, options) {
36 | if (!defined(viewer)) {
37 | throw new DeveloperError('viewer is required.');
38 | }
39 |
40 | var cesiumNavigation = init(viewer, options);
41 |
42 | cesiumNavigation.addOnDestroyListener((function (viewer) {
43 | return function () {
44 | delete viewer.cesiumNavigation;
45 | };
46 | })(viewer));
47 |
48 | defineProperties(viewer, {
49 | cesiumNavigation: {
50 | configurable: true,
51 | get: function () {
52 | return viewer.cesiumWidget.cesiumNavigation;
53 | }
54 | }
55 | });
56 | }
57 |
58 | /**
59 | *
60 | * @param {CesiumWidget} cesiumWidget The cesium widget instance.
61 | * @param {{}} options The options.
62 | */
63 | viewerCesiumNavigationMixin.mixinWidget = function (cesiumWidget, options) {
64 | return init.apply(undefined, arguments);
65 | };
66 |
67 | /**
68 | * @param {Viewer|CesiumWidget} viewerCesiumWidget The Viewer or CesiumWidget instance
69 | * @param {{}} options the options
70 | */
71 | var init = function (viewerCesiumWidget, options) {
72 | var cesiumNavigation = new CesiumNavigation(viewerCesiumWidget, options);
73 |
74 | var cesiumWidget = defined(viewerCesiumWidget.cesiumWidget) ? viewerCesiumWidget.cesiumWidget : viewerCesiumWidget;
75 |
76 | defineProperties(cesiumWidget, {
77 | cesiumNavigation: {
78 | configurable: true,
79 | get: function () {
80 | return cesiumNavigation;
81 | }
82 | }
83 | });
84 |
85 | cesiumNavigation.addOnDestroyListener((function (cesiumWidget) {
86 | return function () {
87 | delete cesiumWidget.cesiumNavigation;
88 | };
89 | })(cesiumWidget));
90 |
91 | return cesiumNavigation;
92 | };
93 |
94 | return viewerCesiumNavigationMixin;
95 | });
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cesium-navigation",
3 | "dependencies": {
4 | "almond": "^0.3.2",
5 | "hammerjs": "^2.0.8",
6 | "knockout": "^3.4.0",
7 | "knockout-es5": "^0.4.4",
8 | "leaflet": "^0.7.7",
9 | "markdown-it-sanitizer": "^0.4.1",
10 | "markdown-it": "^7.0.0",
11 | "require-css": "^0.1.8",
12 | "require-less": "^0.1.5"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | "use strict";
3 | /*jshint node:true*/
4 |
5 | var sourceDir = 'Source';
6 | var buildDir = 'dist',
7 | standaloneSubDir = 'standalone',
8 | amdSubDir = 'amd',
9 | buildName = 'viewerCesiumNavigationMixin';
10 | var examplesDir = 'Examples';
11 |
12 | var requirejs = require('requirejs');
13 |
14 | var path = require('path');
15 | var fs = require('fs-extra');
16 |
17 | var nodeMinify = require('node-minify');
18 |
19 | var minify = function (fileIn, callback) {
20 | var fileOut = path.join(path.dirname(fileIn), path.basename(fileIn, path.extname(fileIn)) + '.min' + path.extname(fileIn));
21 |
22 | new nodeMinify.minify({
23 | type: 'uglifyjs',
24 | fileIn: fileIn,
25 | fileOut: fileOut,
26 | callback: function (err) {
27 | if (err) {
28 | console.log(err);
29 | return;
30 | }
31 |
32 | callback(fileOut);
33 | }
34 | });
35 | };
36 |
37 | var shimsGlobal = {},
38 | shimsBuild = {};
39 | var licenseComments = [];
40 |
41 | var findAllCesiumReferences = function (absPath) {
42 | if (fs.lstatSync(absPath).isDirectory()) {
43 | var files = fs.readdirSync(absPath);
44 |
45 | files.forEach(function (subpath) {
46 | findAllCesiumReferences(path.join(absPath, subpath));
47 | });
48 | return;
49 | } else if (!fs.lstatSync(absPath).isFile()) {
50 | return;
51 | }
52 |
53 | var contents = fs.readFileSync(absPath).toString();
54 |
55 | if (/\.js$/.test(absPath)) {
56 | // Search for Cesium modules and add shim
57 | // modules that pull from the Cesium global
58 |
59 | var cesiumRequireRegex = /['"](Cesium\/\w*\/(\w*))['"]/g;
60 | var match;
61 | while ((match = cesiumRequireRegex.exec(contents)) !== null) {
62 | if (!(match[1] in shimsGlobal)) {
63 | shimsGlobal[match[1]] = 'define(\'' + match[1] + '\', function() { return Cesium[\'' + match[2] + '\']; });';
64 | }
65 | if (!(match[1] in shimsBuild)) {
66 | shimsBuild[match[1]] = 'define(\'' + match[1] + '\', [\'Cesium\'], function(Cesium) { return Cesium[\'' + match[2] + '\']; });';
67 | }
68 | }
69 | } else if (/\.glsl$/.test(absPath)) {
70 | var newContents = [];
71 |
72 | contents = contents.replace(/\r\n/gm, '\n');
73 |
74 | var licenseComments = contents.match(/\/\*\*(?:[^*\/]|\*(?!\/)|\n)*?@license(?:.|\n)*?\*\//gm);
75 | if (licenseComments !== null) {
76 | licenseComments = licenseComments.concat(licenseComments);
77 | }
78 |
79 | // Remove comments. Code ported from
80 | // https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/filters/StripJavaComments.java
81 | for (var i = 0; i < contents.length; ++i) {
82 | var c = contents.charAt(i);
83 | if (c === '/') {
84 | c = contents.charAt(++i);
85 | if (c === '/') {
86 | while (c !== '\r' && c !== '\n' && i < contents.length) {
87 | c = contents.charAt(++i);
88 | }
89 | } else if (c === '*') {
90 | while (i < contents.length) {
91 | c = contents.charAt(++i);
92 | if (c === '*') {
93 | c = contents.charAt(++i);
94 | while (c === '*') {
95 | c = contents.charAt(++i);
96 | }
97 | if (c === '/') {
98 | c = contents.charAt(++i);
99 | break;
100 | }
101 | }
102 | }
103 | } else {
104 | --i;
105 | c = '/';
106 | }
107 | }
108 | newContents.push(c);
109 | }
110 |
111 | newContents = newContents.join('');
112 | newContents = newContents.replace(/\s+$/gm, '').replace(/^\s+/gm, '').replace(/\n+/gm, '\n');
113 | }
114 | };
115 |
116 | findAllCesiumReferences(sourceDir);
117 |
118 | shimsGlobal = Object.keys(shimsGlobal).map(function (key) {
119 | return shimsGlobal[key];
120 | }).join('\n');
121 | shimsBuild = Object.keys(shimsBuild).map(function (key) {
122 | return shimsBuild[key];
123 | }).join('\n');
124 |
125 | var copyrightHeader = fs.readFileSync(sourceDir + '/copyrightHeader.js').toString();
126 |
127 |
128 | // <-- build standalone edition
129 | var rjsBasicConfig = {
130 | mainConfigFile: 'mainConfig.js',
131 | wrap: {
132 | start: copyrightHeader + '\n' +
133 | "(function (root, factory) {\n" +
134 | " 'use strict';\n" +
135 | " /*jshint sub:true*/\n\n" +
136 | " if (typeof define === 'function' && define.amd) {\n" +
137 | " if(require.specified('Cesium/Cesium')) {\n" +
138 | " define(['Cesium/Cesium'], factory);\n" +
139 | " } else if(require.specified('Cesium')) {\n" +
140 | " define(['Cesium'], factory);\n" +
141 | " } else {\n" +
142 | " define([], factory);\n" +
143 | " }\n" +
144 | " } else {\n" +
145 | " factory();\n" +
146 | " }\n" +
147 | "}(typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : this, function (C) {\n\n" +
148 | " if (typeof C === 'object' && C !== null) {\n" +
149 | " Cesium = C;\n" +
150 | " }\n\n" +
151 | "// <-- actual code\n\n\n",
152 | end: "\n\n" +
153 | "// actual code -->\n\n" +
154 | " /*global define,require,self,Cesium*/\n" +
155 | " " + licenseComments.join('\n ') + "\n" +
156 | shimsGlobal + "\n" +
157 | " \n" +
158 | " var mixin = require('viewerCesiumNavigationMixin');\n" +
159 | " if (typeof Cesium === 'object' && Cesium !== null) {\n" +
160 | " Cesium['" + buildName + "'] = mixin;\n" +
161 | " }\n\n" +
162 | " return mixin;" +
163 | "}));"
164 | },
165 | name: 'almond',
166 | include: ['viewerCesiumNavigationMixin'],
167 | logLevel: 0
168 | };
169 |
170 | var rjsConfig = JSON.parse(JSON.stringify(rjsBasicConfig));
171 | rjsConfig.optimize = 'none';
172 | rjsConfig.out = path.join(buildDir, standaloneSubDir, buildName + '.js');
173 |
174 | requirejs.optimize(rjsConfig, function (buildResponse) {
175 | console.log('Built standalone edition ' + rjsConfig.out + ' successfully.');
176 |
177 | minify(rjsConfig.out, function (minFile) {
178 | console.log('Generated minified ' + minFile);
179 | });
180 | });
181 | // -->
182 |
183 |
184 | // <-- build amd compatible edition
185 | var rjsAMDBasicConfig = {
186 | mainConfigFile: 'mainConfig.js',
187 | name: 'viewerCesiumNavigationMixin',
188 | wrap: {
189 | start: copyrightHeader + '\n\n',
190 | end: '\n\n\n'+
191 | "/*global define,require*/\n" +
192 | "if(!require.specified('Cesium/Cesium')) {\n" +
193 | " if(typeof Cesium === 'object' && Cesium !== null) {\n" +
194 | shimsGlobal + "\n"+
195 | " } else {\n" +
196 | shimsBuild + "\n"+
197 | " }\n" +
198 | "}\n\n" +
199 | 'define([\'viewerCesiumNavigationMixin\'], function(viewerCesiumNavigationMixin) {\n' +
200 | ' return viewerCesiumNavigationMixin;\n' +
201 | '});'
202 | },
203 | logLevel: 0
204 | };
205 |
206 | var rjsAMDConfig = JSON.parse(JSON.stringify(rjsAMDBasicConfig));
207 | rjsAMDConfig.optimize = 'none';
208 | rjsAMDConfig.out = path.join(buildDir, amdSubDir, buildName + '.js');
209 | requirejs.optimize(rjsAMDConfig, function (buildResponse) {
210 | console.log('Built AMD compatible edition ' + rjsAMDConfig.out + ' successfully.');
211 |
212 | minify(rjsAMDConfig.out, function (minFile) {
213 | console.log('Generated minified ' + minFile);
214 | });
215 | });
216 | // -->
217 | })();
--------------------------------------------------------------------------------
/mainConfig.js:
--------------------------------------------------------------------------------
1 | requirejs.config({
2 | useStrict: true,
3 | inlineText: true,
4 | // stubModules : ['text'],
5 | baseUrl: 'Source',
6 | skipModuleInsertion: false,
7 | paths: {
8 | 'require-less': '../bower_components/require-less',
9 |
10 | 'almond': '../bower_components/almond/almond',
11 |
12 | 'KnockoutES5': '../bower_components/knockout-es5/dist/knockout-es5.min',
13 | 'knockout': '../bower_components/knockout/dist/knockout',
14 | 'Hammer': '../bower_components/hammerjs/hammer.min',
15 | 'leaflet': '../bower_components/leaflet/dist/leaflet',
16 | 'markdown-it': '../bower_components/markdown-it/dist/markdown-it.min',
17 | 'markdown-it-sanitizer': '../bower_components/markdown-it-sanitizer/dist/markdown-it-sanitizer.min',
18 |
19 | 'Cesium': 'empty:'
20 | // 'text' : 'ThirdParty/requirejs-2.1.22/text'
21 | },
22 | onBuildWrite: function (moduleName, path, contents) {
23 | // replace all require-less calls to dummy ones because they are only needed for the optimization
24 | return contents.replace(/('|")require-less\/less.*?\1/g, '$1dummy/require-less/less/dummy$1');
25 | },
26 | // those are only needed during optimization where an css is generated, so no need to pack them but only the wrapped output
27 | excludeShallow: ['require-less/less', 'require-less/normalize', 'require-less/lessc', 'require-less/less-builder', 'require-less/lessc-server']
28 | });
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cesium-navigation",
3 | "version": "1.1.3",
4 | "description": "Cesium plugin that adds a compass, navigator, and distance scale to the map",
5 | "main": "viewerCesiumNavigationMixin",
6 | "dependencies": {
7 | "bower": "*"
8 | },
9 | "devDependencies": {
10 | "fs-extra": "^0.26.5",
11 | "csso": "^1.5.4",
12 | "less": "^1.7.5",
13 | "node-minify": "^1.3.7",
14 | "express": "~4.9.x",
15 | "compression": "1.0.8",
16 | "yargs": "1.2.6",
17 | "requirejs": "^2.1.22",
18 | "cesium": "^1.20.0"
19 | },
20 | "scripts": {
21 | "test": "echo \"Error: no test specified\" && exit 1",
22 | "postinstall": "bower install"
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/alberto-acevedo/cesium-navigation.git"
27 | },
28 | "keywords": [
29 | "cesium",
30 | "navigation",
31 | "compass",
32 | "navigator",
33 | "distance",
34 | "scale"
35 | ],
36 | "author": "alberto acevedo",
37 | "license": "Apache-2.0",
38 | "bugs": {
39 | "url": "https://github.com/alberto-acevedo/cesium-navigation/issues"
40 | },
41 | "homepage": "https://github.com/alberto-acevedo/cesium-navigation#readme"
42 | }
43 |
--------------------------------------------------------------------------------