@openglobus/og 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -68
- package/css/og.css +308 -45
- package/lib/@openglobus/og.css +1 -1
- package/lib/@openglobus/og.esm.js +1 -1
- package/lib/@openglobus/og.esm.js.map +1 -1
- package/lib/@openglobus/og.umd.js +1 -1
- package/lib/@openglobus/og.umd.js.map +1 -1
- package/lib/js/Globe.d.ts +2 -0
- package/lib/js/Globe.js +3 -1
- package/lib/js/camera/PlanetCamera.d.ts +2 -2
- package/lib/js/camera/PlanetCamera.js +3 -2
- package/lib/js/control/DebugInfo.js +5 -0
- package/lib/js/control/EarthCoordinates.js +2 -2
- package/lib/js/control/LayerSwitcher.d.ts +18 -3
- package/lib/js/control/LayerSwitcher.js +111 -11
- package/lib/js/control/MouseNavigation.d.ts +2 -0
- package/lib/js/control/MouseNavigation.js +15 -15
- package/lib/js/control/elevationProfile/ElevationProfile.d.ts +41 -25
- package/lib/js/control/elevationProfile/ElevationProfile.js +106 -75
- package/lib/js/control/elevationProfile/ElevationProfileButtonsView.d.ts +14 -0
- package/lib/js/control/elevationProfile/ElevationProfileButtonsView.js +61 -0
- package/lib/js/control/elevationProfile/ElevationProfileControl.d.ts +33 -0
- package/lib/js/control/elevationProfile/ElevationProfileControl.js +153 -0
- package/lib/js/control/elevationProfile/ElevationProfileLegend.d.ts +20 -0
- package/lib/js/control/elevationProfile/ElevationProfileLegend.js +82 -0
- package/lib/js/control/elevationProfile/ElevationProfileScene.d.ts +80 -0
- package/lib/js/control/elevationProfile/ElevationProfileScene.js +539 -0
- package/lib/js/control/elevationProfile/ElevationProfileView.d.ts +63 -0
- package/lib/js/control/elevationProfile/ElevationProfileView.js +504 -0
- package/lib/js/control/elevationProfile/PointListDialog.d.ts +12 -0
- package/lib/js/control/elevationProfile/PointListDialog.js +57 -0
- package/lib/js/control/heightRuler/HeightRulerScene.js +1 -1
- package/lib/js/control/index.d.ts +2 -1
- package/lib/js/control/index.js +2 -1
- package/lib/js/control/ruler/RulerScene.js +3 -3
- package/lib/js/control/selection/SelectionScene.js +2 -2
- package/lib/js/entity/Entity.js +5 -1
- package/lib/js/entity/Polyline.js +1 -1
- package/lib/js/layer/GeoImage.js +3 -0
- package/lib/js/layer/Layer.d.ts +18 -4
- package/lib/js/layer/Layer.js +25 -4
- package/lib/js/layer/XYZ.d.ts +0 -1
- package/lib/js/quadTree/Node.d.ts +21 -3
- package/lib/js/quadTree/Node.js +173 -62
- package/lib/js/renderer/Renderer.d.ts +0 -1
- package/lib/js/renderer/Renderer.js +22 -44
- package/lib/js/renderer/RendererEvents.d.ts +1 -0
- package/lib/js/renderer/RendererEvents.js +5 -7
- package/lib/js/scene/Planet.d.ts +33 -4
- package/lib/js/scene/Planet.js +206 -84
- package/lib/js/segment/Segment.d.ts +7 -1
- package/lib/js/segment/Segment.js +40 -12
- package/lib/js/shaders/drawnode.js +21 -2
- package/lib/js/shaders/geoObject.js +26 -18
- package/lib/js/terrain/GlobusTerrain.d.ts +3 -0
- package/lib/js/terrain/GlobusTerrain.js +15 -3
- package/lib/js/terrain/MapboxTerrain.js +29 -29
- package/lib/js/ui/Dialog.js +1 -1
- package/lib/js/utils/TerrainWorker.js +1 -1
- package/lib/js/utils/shared.d.ts +3 -1
- package/lib/js/utils/shared.js +22 -3
- package/package.json +2 -2
- package/lib/js/shaders/pickingMask.d.ts +0 -2
- package/lib/js/shaders/pickingMask.js +0 -22
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Deferred } from '../../Deferred';
|
|
2
2
|
import { createEvents } from '../../Events';
|
|
3
3
|
import { Vec3 } from "../../math/Vec3";
|
|
4
|
-
const
|
|
4
|
+
const DEFAULT_WARNING_HEIGHT_LEVEL = 5;
|
|
5
|
+
const ELEVATIONPROFILE_EVENTS = ["startcollecting", "profilecollected", "clear"];
|
|
5
6
|
/**
|
|
6
7
|
* Point types
|
|
7
8
|
*/
|
|
8
|
-
const SAFE = 0;
|
|
9
|
-
const WARNING = 1;
|
|
10
|
-
const COLLISION = 2;
|
|
9
|
+
export const SAFE = 0;
|
|
10
|
+
export const WARNING = 1;
|
|
11
|
+
export const COLLISION = 2;
|
|
11
12
|
/**
|
|
12
13
|
* drawData index names
|
|
13
14
|
*/
|
|
@@ -16,51 +17,75 @@ const GROUND = 1;
|
|
|
16
17
|
const SEGMMENT_LENGTH = 1.0; // Distance between query points on the ground
|
|
17
18
|
const GROUND_OFFSET = 1.0; // Ground level offset
|
|
18
19
|
const BOTTOM_PADDING = 0.1; // Range minY padding in percentage from the bottom
|
|
19
|
-
const TOP_PADDING = 0.
|
|
20
|
+
const TOP_PADDING = 0.2; // Range maxY padding in percentage from the top
|
|
20
21
|
const HEIGHT_EPS = 0.1; // Warning height level error
|
|
21
|
-
class ElevationProfile {
|
|
22
|
-
constructor(options) {
|
|
22
|
+
export class ElevationProfile {
|
|
23
|
+
constructor(options = {}) {
|
|
23
24
|
this.events = createEvents(ELEVATIONPROFILE_EVENTS);
|
|
24
|
-
this.planet = options.planet;
|
|
25
|
-
this._warningHeightLevel =
|
|
25
|
+
this.planet = options.planet || null;
|
|
26
|
+
this._warningHeightLevel = DEFAULT_WARNING_HEIGHT_LEVEL;
|
|
26
27
|
this._pointsReady = false;
|
|
27
28
|
this._isWarning = false;
|
|
28
29
|
this._minX = 0;
|
|
29
|
-
this._maxX = 1000;
|
|
30
|
+
this._planeDistance = this._maxX = 1000;
|
|
30
31
|
this._minY = 0;
|
|
31
32
|
this._maxY = 200;
|
|
32
|
-
this._drawData = [][
|
|
33
|
+
this._drawData = [[], []];
|
|
33
34
|
this._promiseArr = [];
|
|
34
35
|
this._promiseCounter = 0;
|
|
35
36
|
this._pMaxY = 0;
|
|
36
37
|
this._pMinY = 0;
|
|
37
38
|
this._pDist = 0;
|
|
38
|
-
this._pTrackCoords = [
|
|
39
|
-
this._pGroundCoords = [
|
|
39
|
+
this._pTrackCoords = [];
|
|
40
|
+
this._pGroundCoords = [];
|
|
40
41
|
this._pIndex = 0;
|
|
41
42
|
}
|
|
43
|
+
bindPlanet(planet) {
|
|
44
|
+
this.planet = planet;
|
|
45
|
+
}
|
|
42
46
|
setWarningHeightLevel(warningHeight = 0) {
|
|
43
47
|
this._warningHeightLevel = warningHeight;
|
|
44
48
|
}
|
|
45
49
|
setRange(minX, maxX, minY, maxY) {
|
|
46
50
|
this._minX = minX;
|
|
47
51
|
this._maxX = maxX;
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
if (minY) {
|
|
53
|
+
this._minY = minY;
|
|
54
|
+
}
|
|
55
|
+
if (maxY) {
|
|
56
|
+
this._maxY = maxY;
|
|
57
|
+
}
|
|
50
58
|
}
|
|
51
|
-
_getHeightAsync(ll, pIndex) {
|
|
59
|
+
_getHeightAsync(ll, pIndex, promiseCounter) {
|
|
52
60
|
let def = new Deferred();
|
|
53
|
-
this.planet
|
|
54
|
-
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
if (this.planet) {
|
|
62
|
+
let msl = this.planet.terrain.geoid.getHeightLonLat(ll);
|
|
63
|
+
this.planet.terrain.getHeightAsync(ll, (elv) => {
|
|
64
|
+
if (this.planet && promiseCounter === this._promiseCounter) {
|
|
65
|
+
elv += msl;
|
|
66
|
+
this._pGroundCoords[pIndex][1] = elv;
|
|
67
|
+
this._pGroundCoords[pIndex][2] = SAFE;
|
|
68
|
+
this._pGroundCoords[pIndex][3] = ll.height;
|
|
69
|
+
if (elv > this._pMaxY)
|
|
70
|
+
this._pMaxY = elv;
|
|
71
|
+
if (elv < this._pMinY)
|
|
72
|
+
this._pMinY = elv;
|
|
73
|
+
this._updatePointType(pIndex);
|
|
74
|
+
def.resolve(elv);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
def.reject();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
def.reject();
|
|
83
|
+
}
|
|
61
84
|
return def.promise;
|
|
62
85
|
}
|
|
63
|
-
_collectCoordsBetweenTwoTrackPoints(internalPoints, scaleFactor, p0, trackDir) {
|
|
86
|
+
_collectCoordsBetweenTwoTrackPoints(index, internalPoints, scaleFactor, p0, trackDir, promiseCounter) {
|
|
87
|
+
if (!this.planet)
|
|
88
|
+
return;
|
|
64
89
|
for (let j = 1; j <= internalPoints; j++) {
|
|
65
90
|
this._pDist += SEGMMENT_LENGTH;
|
|
66
91
|
this._pIndex++;
|
|
@@ -68,19 +93,17 @@ class ElevationProfile {
|
|
|
68
93
|
let dirSegLen = j * scaleFactor;
|
|
69
94
|
let pjd = p0.add(trackDir.scaleTo(dirSegLen));
|
|
70
95
|
let llx = this.planet.ellipsoid.cartesianToLonLat(pjd);
|
|
71
|
-
this._pGroundCoords[this._pIndex] = [this._pDist, 0, SAFE];
|
|
96
|
+
this._pGroundCoords[this._pIndex] = [this._pDist, 0, SAFE, 0, index];
|
|
72
97
|
((lonlat, index) => {
|
|
73
|
-
this._promiseArr.push(this._getHeightAsync(lonlat, index)
|
|
74
|
-
.then((elv) => {
|
|
75
|
-
if (elv > this._pMaxY)
|
|
76
|
-
this._pMaxY = elv;
|
|
77
|
-
if (elv < this._pMinY)
|
|
78
|
-
this._pMinY = elv;
|
|
79
|
-
}));
|
|
98
|
+
this._promiseArr.push(this._getHeightAsync(lonlat, index, promiseCounter));
|
|
80
99
|
})(llx, this._pIndex);
|
|
81
100
|
}
|
|
82
101
|
}
|
|
83
|
-
_collectAllPoints(pointsLonLat) {
|
|
102
|
+
_collectAllPoints(pointsLonLat, promiseCounter) {
|
|
103
|
+
if (!this.planet)
|
|
104
|
+
return;
|
|
105
|
+
if (promiseCounter !== this._promiseCounter)
|
|
106
|
+
return;
|
|
84
107
|
let p0 = new Vec3(), p1 = new Vec3();
|
|
85
108
|
for (let i = 1, len = pointsLonLat.length; i < len; i++) {
|
|
86
109
|
let lonlat0 = pointsLonLat[i - 1], lonlat1 = pointsLonLat[i];
|
|
@@ -93,11 +116,11 @@ class ElevationProfile {
|
|
|
93
116
|
let projLen = proj.length();
|
|
94
117
|
let internalPoints = Math.floor(projLen / SEGMMENT_LENGTH);
|
|
95
118
|
let scaleFactor = SEGMMENT_LENGTH * dirLength / projLen;
|
|
96
|
-
this._getGroundElevation(lonlat0);
|
|
119
|
+
this._getGroundElevation(lonlat0, i - 1, promiseCounter);
|
|
97
120
|
proj.normalize();
|
|
98
121
|
trackDir.normalize();
|
|
99
122
|
// Getting internal point elevations and looking for the collisions
|
|
100
|
-
this._collectCoordsBetweenTwoTrackPoints(internalPoints, scaleFactor, p0, trackDir);
|
|
123
|
+
this._collectCoordsBetweenTwoTrackPoints(i - 1, internalPoints, scaleFactor, p0, trackDir, promiseCounter);
|
|
101
124
|
this._pDist += projLen - internalPoints * SEGMMENT_LENGTH;
|
|
102
125
|
this._pIndex++;
|
|
103
126
|
let elv = lonlat1.height;
|
|
@@ -105,49 +128,41 @@ class ElevationProfile {
|
|
|
105
128
|
this._pMaxY = elv;
|
|
106
129
|
if (elv < this._pMinY)
|
|
107
130
|
this._pMinY = elv;
|
|
108
|
-
this._pTrackCoords[i] = [this._pDist, elv];
|
|
131
|
+
this._pTrackCoords[i] = [this._pDist, elv, this._pIndex];
|
|
109
132
|
}
|
|
110
133
|
}
|
|
111
|
-
_getGroundElevation(lonLat) {
|
|
112
|
-
this._pGroundCoords[this._pIndex] = [this._pDist, 0, SAFE];
|
|
113
|
-
this._promiseArr.push(this._getHeightAsync(lonLat, this._pIndex)
|
|
114
|
-
.then((elv) => {
|
|
115
|
-
if (typeof elv === 'number') {
|
|
116
|
-
if ((elv > this._pMaxY) && (elv))
|
|
117
|
-
this._pMaxY = elv;
|
|
118
|
-
if ((elv < this._pMinY) && (elv))
|
|
119
|
-
this._pMinY = elv;
|
|
120
|
-
}
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
|
-
_collectPromise(resolve) {
|
|
124
|
-
Promise.all(this._promiseArr).then(() => {
|
|
125
|
-
resolve({
|
|
126
|
-
dist: this._pDist,
|
|
127
|
-
minY: this._pMinY,
|
|
128
|
-
maxY: this._pMaxY,
|
|
129
|
-
trackCoords: this._pTrackCoords,
|
|
130
|
-
groundCoords: this._pGroundCoords
|
|
131
|
-
});
|
|
132
|
-
});
|
|
134
|
+
_getGroundElevation(lonLat, index, promiseCounter) {
|
|
135
|
+
this._pGroundCoords[this._pIndex] = [this._pDist, 0, SAFE, 0, index];
|
|
136
|
+
this._promiseArr.push(this._getHeightAsync(lonLat, this._pIndex, promiseCounter));
|
|
133
137
|
}
|
|
134
|
-
_calcPointsAsync(pointsLonLat) {
|
|
138
|
+
_calcPointsAsync(pointsLonLat, promiseCounter) {
|
|
135
139
|
return new Promise((resolve, reject) => {
|
|
136
|
-
this._pTrackCoords = [[0, pointsLonLat[0].height]];
|
|
140
|
+
this._pTrackCoords = [[0, pointsLonLat[0].height, 0]];
|
|
137
141
|
this._pMaxY = pointsLonLat[0].height;
|
|
138
142
|
this._pMinY = this._pMaxY;
|
|
139
143
|
this._pDist = 0;
|
|
140
|
-
this._pGroundCoords = [
|
|
144
|
+
this._pGroundCoords = [];
|
|
141
145
|
this._pIndex = 0;
|
|
142
146
|
this._promiseArr = [];
|
|
143
|
-
this._collectAllPoints(pointsLonLat);
|
|
144
|
-
this._getGroundElevation(pointsLonLat[pointsLonLat.length - 1]);
|
|
145
|
-
this.
|
|
147
|
+
this._collectAllPoints(pointsLonLat, promiseCounter);
|
|
148
|
+
this._getGroundElevation(pointsLonLat[pointsLonLat.length - 1], pointsLonLat.length - 1, promiseCounter);
|
|
149
|
+
Promise.all(this._promiseArr).then(() => {
|
|
150
|
+
resolve({
|
|
151
|
+
dist: this._pDist,
|
|
152
|
+
minY: this._pMinY,
|
|
153
|
+
maxY: this._pMaxY,
|
|
154
|
+
trackCoords: this._pTrackCoords,
|
|
155
|
+
groundCoords: this._pGroundCoords
|
|
156
|
+
});
|
|
157
|
+
});
|
|
146
158
|
});
|
|
147
159
|
}
|
|
148
160
|
get minX() {
|
|
149
161
|
return this._minX;
|
|
150
162
|
}
|
|
163
|
+
get planeDistance() {
|
|
164
|
+
return this._planeDistance;
|
|
165
|
+
}
|
|
151
166
|
get maxX() {
|
|
152
167
|
return this._maxX;
|
|
153
168
|
}
|
|
@@ -163,24 +178,36 @@ class ElevationProfile {
|
|
|
163
178
|
get isWarningOrCollision() {
|
|
164
179
|
return this._isWarning;
|
|
165
180
|
}
|
|
181
|
+
get drawData() {
|
|
182
|
+
return this._drawData;
|
|
183
|
+
}
|
|
166
184
|
collectProfile(pointsLonLat) {
|
|
185
|
+
let def = new Deferred();
|
|
186
|
+
if (!this.planet)
|
|
187
|
+
def.reject();
|
|
167
188
|
this._pointsReady = false;
|
|
168
189
|
this._isWarning = false;
|
|
169
|
-
if (!pointsLonLat || !pointsLonLat.length)
|
|
170
|
-
|
|
190
|
+
if (!pointsLonLat || !pointsLonLat.length) {
|
|
191
|
+
def.reject();
|
|
192
|
+
return def.promise;
|
|
193
|
+
}
|
|
194
|
+
this.events.dispatch(this.events.startcollecting, this);
|
|
171
195
|
this._promiseCounter++;
|
|
172
196
|
((counter) => {
|
|
173
|
-
this._calcPointsAsync(pointsLonLat).then((p) => {
|
|
197
|
+
this._calcPointsAsync(pointsLonLat, counter).then((p) => {
|
|
174
198
|
if (counter === this._promiseCounter) {
|
|
199
|
+
this._planeDistance = p.dist;
|
|
175
200
|
this.setRange(0, p.dist, p.minY - BOTTOM_PADDING * Math.abs(p.minY), p.maxY + Math.abs(p.maxY) * TOP_PADDING);
|
|
176
201
|
this._pointsReady = true;
|
|
177
202
|
this._drawData = [p.trackCoords, p.groundCoords];
|
|
178
203
|
this.events.dispatch(this.events.profilecollected, this._drawData, this);
|
|
204
|
+
def.resolve(this._drawData);
|
|
179
205
|
}
|
|
180
206
|
});
|
|
181
207
|
})(this._promiseCounter);
|
|
208
|
+
return def.promise;
|
|
182
209
|
}
|
|
183
|
-
|
|
210
|
+
_updatePointType(pIndex) {
|
|
184
211
|
if ((this._pGroundCoords[pIndex][3] >= this._pGroundCoords[pIndex][1]) &&
|
|
185
212
|
(this._pGroundCoords[pIndex][3] < this._pGroundCoords[pIndex][1] + this._warningHeightLevel - HEIGHT_EPS)) {
|
|
186
213
|
this._pGroundCoords[pIndex][2] = WARNING;
|
|
@@ -188,30 +215,34 @@ class ElevationProfile {
|
|
|
188
215
|
if (this._pGroundCoords[pIndex][3] <= this._pGroundCoords[pIndex][1] + GROUND_OFFSET) {
|
|
189
216
|
this._pGroundCoords[pIndex][2] = COLLISION;
|
|
190
217
|
}
|
|
191
|
-
if (this._pGroundCoords[pIndex][2]
|
|
218
|
+
if (this._pGroundCoords[pIndex][2] === WARNING || this._pGroundCoords[pIndex][2] === COLLISION) {
|
|
192
219
|
this._isWarning = true;
|
|
193
220
|
}
|
|
194
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* @deprecated
|
|
224
|
+
*/
|
|
195
225
|
_setPointsType() {
|
|
196
226
|
this._isWarning = false;
|
|
197
227
|
this._pTrackCoords = this._drawData[TRACK];
|
|
198
228
|
this._pGroundCoords = this._drawData[GROUND];
|
|
199
229
|
for (let i = 0; i < this._pGroundCoords.length; i++) {
|
|
200
|
-
this.
|
|
230
|
+
this._updatePointType(i);
|
|
201
231
|
}
|
|
202
232
|
this._drawData[GROUND] = this._pGroundCoords;
|
|
203
233
|
this.events.dispatch(this.events.profilecollected, this._drawData, this);
|
|
204
234
|
}
|
|
205
235
|
clear() {
|
|
236
|
+
this._promiseCounter = 0;
|
|
206
237
|
this._pointsReady = false;
|
|
207
238
|
this._isWarning = false;
|
|
208
|
-
this._drawData = [][
|
|
239
|
+
this._drawData = [[], []];
|
|
209
240
|
this._pMaxY = 0;
|
|
210
241
|
this._pMinY = 0;
|
|
211
242
|
this._pDist = 0;
|
|
212
|
-
this._pTrackCoords = [
|
|
213
|
-
this._pGroundCoords = [
|
|
243
|
+
this._pTrackCoords = [];
|
|
244
|
+
this._pGroundCoords = [];
|
|
214
245
|
this._pIndex = 0;
|
|
246
|
+
this.events.dispatch(this.events.clear, this._drawData, this);
|
|
215
247
|
}
|
|
216
248
|
}
|
|
217
|
-
export { COLLISION, SAFE, WARNING, ElevationProfile, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { View, IViewParams, ViewEventsList } from "../../ui/View";
|
|
2
|
+
import { ToggleButton } from "../../ui/ToggleButton";
|
|
3
|
+
import { EventsHandler } from "../../Events";
|
|
4
|
+
import { ElevationProfile } from "./ElevationProfile";
|
|
5
|
+
interface IElevationProfileButtonsViewParams extends IViewParams {
|
|
6
|
+
}
|
|
7
|
+
type ElevationProfileButtonsViewEventsList = ["reset", "list", "location"];
|
|
8
|
+
export declare class ElevationProfileButtonsView extends View<ElevationProfile> {
|
|
9
|
+
events: EventsHandler<ElevationProfileButtonsViewEventsList> & EventsHandler<ViewEventsList>;
|
|
10
|
+
pointListBtn: ToggleButton;
|
|
11
|
+
constructor(params?: IElevationProfileButtonsViewParams);
|
|
12
|
+
render(params: any): this;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { View } from "../../ui/View";
|
|
2
|
+
import { Button } from "../../ui/Button";
|
|
3
|
+
import { ToggleButton } from "../../ui/ToggleButton";
|
|
4
|
+
const TEMPLATE = '<div class="og-elevationprofile-buttons"></div>';
|
|
5
|
+
const RESET_SVG_ICON = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
6
|
+
<svg width="30" height="30" viewBox="0 0 30 30" version="1.1">
|
|
7
|
+
<g transform="translate(0,-289.0625)">
|
|
8
|
+
<path d="M 15 6 C 10.041282 6 6 10.04128 6 15 C 6 19.95872 10.041282 24 15 24 C 16.586491 24 18.07668 23.58246 19.373047 22.857422 L 17.888672 21.375 C 17.00816 21.772814 16.032235 22 15 22 C 11.122162 22 8 18.87784 8 15 C 8 11.12216 11.122162 8 15 8 C 18.877838 8 22 11.12216 22 15 L 19 15 L 23 20 L 27 15 L 24 15 C 24 10.04128 19.958718 6 15 6 z " transform="translate(0,289.0625)" />
|
|
9
|
+
</g>
|
|
10
|
+
</svg>`;
|
|
11
|
+
const LIST_SVG_ICON = `<?xml version="1.0" encoding="utf-8"?><svg width="800px" height="800px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:none;}</style></defs><title>list</title><rect x="10" y="6" width="18" height="2"/><rect x="10" y="24" width="18" height="2"/><rect x="10" y="15" width="18" height="2"/><rect x="4" y="15" width="2" height="2"/><rect x="4" y="6" width="2" height="2"/><rect x="4" y="24" width="2" height="2"/></svg>`;
|
|
12
|
+
const LOCATION_SVG_ICON = `<?xml version="1.0" encoding="utf-8"?>
|
|
13
|
+
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
|
|
14
|
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
15
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 256 256" enable-background="new 0 0 256 256" xml:space="preserve">
|
|
16
|
+
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
|
|
17
|
+
<g><g><path fill="#000000" d="M127,169.4c23.7,0,42.8-18.3,42.8-41s-19.2-41-42.8-41c-23.7,0-42.8,18.4-42.8,41S103.4,169.4,127,169.4z"/><path fill="#000000" d="M221.7,120.2c-3.8-44-40.9-78.9-87-82V15h-16.3v23.6c-44.8,4-80.3,38.5-84.1,81.7H10v15.6h24.3c3.8,43.1,39.3,77.4,84.1,81.7V241h16.3v-23.2c46-3.1,83.2-37.9,87-82H246v-15.6H221.7L221.7,120.2L221.7,120.2z M128,201.6c-42.5,0-76.7-33-76.7-73.4c0-40.4,34.5-73.4,76.7-73.4c42.5,0,76.7,33,76.7,73.4C204.7,168.5,170.5,201.6,128,201.6L128,201.6z"/></g></g>
|
|
18
|
+
</svg>`;
|
|
19
|
+
const ELEVATIONPROFILEBUTTONSVIEW_EVENTS = ["reset", "list", "location"];
|
|
20
|
+
export class ElevationProfileButtonsView extends View {
|
|
21
|
+
constructor(params = {}) {
|
|
22
|
+
super({
|
|
23
|
+
...params,
|
|
24
|
+
template: TEMPLATE
|
|
25
|
+
});
|
|
26
|
+
//@ts-ignore
|
|
27
|
+
this.events = this.events.registerNames(ELEVATIONPROFILEBUTTONSVIEW_EVENTS);
|
|
28
|
+
this.pointListBtn = new ToggleButton({
|
|
29
|
+
classList: ["og-elevationprofile-button"],
|
|
30
|
+
icon: LIST_SVG_ICON,
|
|
31
|
+
title: "Point List"
|
|
32
|
+
});
|
|
33
|
+
this.pointListBtn.events.on("change", (isActive) => {
|
|
34
|
+
this.events.dispatch(this.events.list, isActive);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
render(params) {
|
|
38
|
+
super.render(params);
|
|
39
|
+
let resetBtn = new Button({
|
|
40
|
+
classList: ["og-elevationprofile-button"],
|
|
41
|
+
icon: RESET_SVG_ICON,
|
|
42
|
+
title: "Reset"
|
|
43
|
+
});
|
|
44
|
+
resetBtn.appendTo(this.el);
|
|
45
|
+
resetBtn.events.on("click", () => {
|
|
46
|
+
this.model.clear();
|
|
47
|
+
this.events.dispatch(this.events.reset, this);
|
|
48
|
+
});
|
|
49
|
+
this.pointListBtn.appendTo(this.el);
|
|
50
|
+
let locationBtn = new Button({
|
|
51
|
+
classList: ["og-elevationprofile-button", "og-elevationprofile-button__location"],
|
|
52
|
+
icon: LOCATION_SVG_ICON,
|
|
53
|
+
title: "View bounds"
|
|
54
|
+
});
|
|
55
|
+
locationBtn.appendTo(this.el);
|
|
56
|
+
locationBtn.events.on("click", () => {
|
|
57
|
+
this.events.dispatch(this.events.location, this);
|
|
58
|
+
});
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Control, IControlParams } from "../Control";
|
|
2
|
+
import { Dialog } from "../../ui/Dialog";
|
|
3
|
+
import { View } from "../../ui/View";
|
|
4
|
+
import { ToggleButton } from "../../ui/ToggleButton";
|
|
5
|
+
import { ElevationProfileView } from "./ElevationProfileView";
|
|
6
|
+
import { ElevationProfileScene } from "./ElevationProfileScene";
|
|
7
|
+
import { ElevationProfileButtonsView } from "./ElevationProfileButtonsView";
|
|
8
|
+
import { PointListDialog } from "./PointListDialog";
|
|
9
|
+
import { GroundItem, TrackItem } from "./ElevationProfile";
|
|
10
|
+
import { ElevationProfileLegend } from "./ElevationProfileLegend";
|
|
11
|
+
interface IElevationProfileGraphParams extends IControlParams {
|
|
12
|
+
}
|
|
13
|
+
export declare class ElevationProfileControl extends Control {
|
|
14
|
+
protected _toggleBtn: ToggleButton;
|
|
15
|
+
protected _dialog: Dialog<null>;
|
|
16
|
+
protected _graphView: View<null>;
|
|
17
|
+
protected _poiListDialog: PointListDialog;
|
|
18
|
+
protected _elevationProfileView: ElevationProfileView;
|
|
19
|
+
protected _elevationProfileScene: ElevationProfileScene;
|
|
20
|
+
protected _elevationProfileButtonsView: ElevationProfileButtonsView;
|
|
21
|
+
protected _elevationProfileLegend: ElevationProfileLegend;
|
|
22
|
+
protected _collectProfileThrottled: () => void;
|
|
23
|
+
constructor(options?: IElevationProfileGraphParams);
|
|
24
|
+
oninit(): void;
|
|
25
|
+
protected _onSceneChange: () => void;
|
|
26
|
+
onactivate(): void;
|
|
27
|
+
ondeactivate(): void;
|
|
28
|
+
protected _onElevationProfilePointer: (pointerDistance: number, tp0: TrackItem, tp1: TrackItem, gp0: GroundItem, gp1: GroundItem, trackPoiIndex: number, groundPoiIndex: number, elevation: number) => void;
|
|
29
|
+
protected _onElevationProfileDblClick: (pointerDistance: number, tp0: TrackItem, tp1: TrackItem, gp0: GroundItem, gp1: GroundItem, trackPoiIndex: number, groundPoiIndex: number, elevation: number) => void;
|
|
30
|
+
protected _onElevationProfileMouseEnter: () => void;
|
|
31
|
+
protected _onElevationProfileMouseLeave: () => void;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Control } from "../Control";
|
|
2
|
+
import { Dialog } from "../../ui/Dialog";
|
|
3
|
+
import { View } from "../../ui/View";
|
|
4
|
+
import { ToggleButton } from "../../ui/ToggleButton";
|
|
5
|
+
import { ElevationProfileView } from "./ElevationProfileView";
|
|
6
|
+
import { ElevationProfileScene } from "./ElevationProfileScene";
|
|
7
|
+
import { throttle } from "../../utils/shared";
|
|
8
|
+
import { ElevationProfileButtonsView } from "./ElevationProfileButtonsView";
|
|
9
|
+
import { PointListDialog } from "./PointListDialog";
|
|
10
|
+
import { ElevationProfileLegend } from "./ElevationProfileLegend";
|
|
11
|
+
const TEMPLATE = `<div class="og-elevationprofile__container">
|
|
12
|
+
<div class="og-elevationprofile__menu"></div>
|
|
13
|
+
<div class="og-elevationprofile__graph"></div>
|
|
14
|
+
</div>`;
|
|
15
|
+
const ICON_BUTTON_SVG = `<svg style="width: 2em; height: 2em;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M128 896v-158.293333l331.946667-191.573334 160.853333 93.866667L896 480V896H128M896 381.44l-275.2 159.146667-160.853333-92.586667L128 640v-94.293333l331.946667-191.573334 160.853333 93.866667L896 288v93.44z" fill="" /></svg>`;
|
|
16
|
+
export class ElevationProfileControl extends Control {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
super({
|
|
19
|
+
name: "ElevationProfileControl",
|
|
20
|
+
...options
|
|
21
|
+
});
|
|
22
|
+
this._onSceneChange = () => {
|
|
23
|
+
this._collectProfileThrottled();
|
|
24
|
+
};
|
|
25
|
+
this._onElevationProfilePointer = (pointerDistance, tp0, tp1, gp0, gp1, trackPoiIndex, groundPoiIndex, elevation) => {
|
|
26
|
+
let lonLat0 = this._elevationProfileScene.getPointLonLat(trackPoiIndex);
|
|
27
|
+
let lonLat1 = this._elevationProfileScene.getPointLonLat(trackPoiIndex + 1);
|
|
28
|
+
let cart0 = this.planet.ellipsoid.lonLatToCartesian(lonLat0), cart1 = this.planet.ellipsoid.lonLatToCartesian(lonLat1);
|
|
29
|
+
let d = (pointerDistance - tp0[0]) / (tp1[0] - tp0[0]);
|
|
30
|
+
let dir = cart1.sub(cart0);
|
|
31
|
+
this._elevationProfileScene.setPointerCartesian3v(cart0.add(dir.scale(d)), elevation);
|
|
32
|
+
};
|
|
33
|
+
this._onElevationProfileDblClick = (pointerDistance, tp0, tp1, gp0, gp1, trackPoiIndex, groundPoiIndex, elevation) => {
|
|
34
|
+
let lonLat0 = this._elevationProfileScene.getPointLonLat(trackPoiIndex);
|
|
35
|
+
let lonLat1 = this._elevationProfileScene.getPointLonLat(trackPoiIndex + 1);
|
|
36
|
+
let cart0 = this.planet.ellipsoid.lonLatToCartesian(lonLat0), cart1 = this.planet.ellipsoid.lonLatToCartesian(lonLat1);
|
|
37
|
+
let d = (pointerDistance - tp0[0]) / (tp1[0] - tp0[0]);
|
|
38
|
+
let dir = cart1.sub(cart0);
|
|
39
|
+
let poi = cart0.add(dir.scale(d));
|
|
40
|
+
this.planet.camera.flyDistance(poi, this.planet.camera.eye.distance(poi));
|
|
41
|
+
};
|
|
42
|
+
this._onElevationProfileMouseEnter = () => {
|
|
43
|
+
if (this._elevationProfileView.model.pointsReady) {
|
|
44
|
+
this._elevationProfileScene.setPointerVisibility(true);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
this._onElevationProfileMouseLeave = () => {
|
|
48
|
+
};
|
|
49
|
+
this._elevationProfileScene = new ElevationProfileScene();
|
|
50
|
+
this._elevationProfileView = new ElevationProfileView();
|
|
51
|
+
this._elevationProfileLegend = new ElevationProfileLegend();
|
|
52
|
+
this._elevationProfileButtonsView = new ElevationProfileButtonsView({
|
|
53
|
+
model: this._elevationProfileView.model
|
|
54
|
+
});
|
|
55
|
+
this._elevationProfileView.events.on("pointer", this._onElevationProfilePointer);
|
|
56
|
+
this._elevationProfileView.events.on("dblclick", this._onElevationProfileDblClick);
|
|
57
|
+
this._elevationProfileView.events.on("mouseenter", this._onElevationProfileMouseEnter);
|
|
58
|
+
this._elevationProfileView.events.on("mouseleave", this._onElevationProfileMouseLeave);
|
|
59
|
+
this._dialog = new Dialog({
|
|
60
|
+
title: "Elevation Profile",
|
|
61
|
+
visible: false,
|
|
62
|
+
resizable: true,
|
|
63
|
+
useHide: true,
|
|
64
|
+
top: 175,
|
|
65
|
+
left: 65,
|
|
66
|
+
width: 400,
|
|
67
|
+
height: 200,
|
|
68
|
+
minHeight: 100,
|
|
69
|
+
minWidth: 100
|
|
70
|
+
});
|
|
71
|
+
this._graphView = new View({
|
|
72
|
+
template: TEMPLATE
|
|
73
|
+
});
|
|
74
|
+
this._poiListDialog = new PointListDialog({
|
|
75
|
+
model: this._elevationProfileScene
|
|
76
|
+
});
|
|
77
|
+
this._toggleBtn = new ToggleButton({
|
|
78
|
+
classList: ["og-map-button", "og-elevationprofile_button"],
|
|
79
|
+
icon: ICON_BUTTON_SVG
|
|
80
|
+
});
|
|
81
|
+
this._collectProfileThrottled = throttle(() => {
|
|
82
|
+
let points = this._elevationProfileScene.getPointsLonLat();
|
|
83
|
+
this._elevationProfileView.model.collectProfile(points);
|
|
84
|
+
}, 250);
|
|
85
|
+
}
|
|
86
|
+
oninit() {
|
|
87
|
+
this._dialog.appendTo(this.planet.renderer.div);
|
|
88
|
+
this._graphView.appendTo(this._dialog.container);
|
|
89
|
+
this._toggleBtn.appendTo(this.renderer.div);
|
|
90
|
+
this._dialog.events.on("visibility", (v) => {
|
|
91
|
+
this._toggleBtn.setActive(v);
|
|
92
|
+
if (v) {
|
|
93
|
+
this.activate();
|
|
94
|
+
this._elevationProfileView.resize();
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.deactivate();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
this._toggleBtn.events.on("change", (isActive) => {
|
|
101
|
+
this._dialog.setVisibility(isActive);
|
|
102
|
+
});
|
|
103
|
+
this._elevationProfileView.appendTo(this._graphView.select(".og-elevationprofile__graph"));
|
|
104
|
+
this._elevationProfileView.model.bindPlanet(this.planet);
|
|
105
|
+
this._elevationProfileView.model.events.on("clear", () => {
|
|
106
|
+
this._elevationProfileScene.clear();
|
|
107
|
+
this._elevationProfileLegend.clear();
|
|
108
|
+
});
|
|
109
|
+
this._elevationProfileView.model.events.on("startcollecting", () => {
|
|
110
|
+
this._elevationProfileScene.setPointerVisibility(false);
|
|
111
|
+
});
|
|
112
|
+
this._elevationProfileView.events.on("tracklength", (length) => {
|
|
113
|
+
this._elevationProfileLegend.setTrackLength(length);
|
|
114
|
+
});
|
|
115
|
+
this._elevationProfileView.events.on("groundlength", (length) => {
|
|
116
|
+
this._elevationProfileLegend.setGroundLength(length);
|
|
117
|
+
});
|
|
118
|
+
this._elevationProfileView.events.on("warninglength", (length) => {
|
|
119
|
+
this._elevationProfileLegend.setWarningLength(length);
|
|
120
|
+
});
|
|
121
|
+
this._elevationProfileView.events.on("collisionlength", (length) => {
|
|
122
|
+
this._elevationProfileLegend.setCollisionLength(length);
|
|
123
|
+
});
|
|
124
|
+
this._poiListDialog.appendTo(this.planet.renderer.div);
|
|
125
|
+
this._poiListDialog.events.on("visibility", (isVisible) => {
|
|
126
|
+
this._elevationProfileButtonsView.pointListBtn.setActive(isVisible, true);
|
|
127
|
+
});
|
|
128
|
+
this._elevationProfileLegend.appendTo(this._graphView.select(".og-elevationprofile__menu"));
|
|
129
|
+
this._elevationProfileButtonsView.appendTo(this._graphView.select(".og-elevationprofile__menu"));
|
|
130
|
+
this._elevationProfileButtonsView.events.on("list", (isActive) => {
|
|
131
|
+
this._poiListDialog.setVisibility(isActive);
|
|
132
|
+
});
|
|
133
|
+
this._elevationProfileButtonsView.events.on("location", (isActive) => {
|
|
134
|
+
this._elevationProfileScene.flyExtent();
|
|
135
|
+
});
|
|
136
|
+
this._elevationProfileButtonsView.events.on("reset", (isActive) => {
|
|
137
|
+
this._elevationProfileScene.setPointerVisibility(false);
|
|
138
|
+
});
|
|
139
|
+
this._elevationProfileScene.events.on("change", this._onSceneChange);
|
|
140
|
+
}
|
|
141
|
+
onactivate() {
|
|
142
|
+
this.renderer.controls.mouseNavigation.deactivateDoubleClickZoom();
|
|
143
|
+
this.planet && this._elevationProfileScene.bindPlanet(this.planet);
|
|
144
|
+
this.renderer && this.renderer.addNode(this._elevationProfileScene);
|
|
145
|
+
}
|
|
146
|
+
ondeactivate() {
|
|
147
|
+
this._poiListDialog.setVisibility(false);
|
|
148
|
+
this._elevationProfileView.model.clear();
|
|
149
|
+
this.renderer.controls.mouseNavigation.activateDoubleClickZoom();
|
|
150
|
+
this.renderer && this.renderer.removeNode(this._elevationProfileScene);
|
|
151
|
+
this._dialog.hide();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IViewParams, View } from '../../ui/View';
|
|
2
|
+
export interface IElevationProfileLegendParams extends IViewParams {
|
|
3
|
+
}
|
|
4
|
+
export declare class ElevationProfileLegend extends View<null> {
|
|
5
|
+
$groundValue: HTMLElement | null;
|
|
6
|
+
$trackValue: HTMLElement | null;
|
|
7
|
+
$warningValue: HTMLElement | null;
|
|
8
|
+
$collisionValue: HTMLElement | null;
|
|
9
|
+
$trackUnits: HTMLElement | null;
|
|
10
|
+
$groundUnits: HTMLElement | null;
|
|
11
|
+
$warningUnits: HTMLElement | null;
|
|
12
|
+
$collisionUnits: HTMLElement | null;
|
|
13
|
+
constructor(params?: IElevationProfileLegendParams);
|
|
14
|
+
render(params: any): this;
|
|
15
|
+
clear(): void;
|
|
16
|
+
setTrackLength(trackLength: number): void;
|
|
17
|
+
setGroundLength(groundLength: number): void;
|
|
18
|
+
setWarningLength(warningLength: number): void;
|
|
19
|
+
setCollisionLength(collisionLength: number): void;
|
|
20
|
+
}
|