@openglobus/og 0.18.3 → 0.18.5

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.
Files changed (44) hide show
  1. package/README.md +8 -5
  2. package/css/og.css +251 -3
  3. package/lib/@openglobus/og.css +1 -1
  4. package/lib/@openglobus/og.esm.js +1 -1
  5. package/lib/@openglobus/og.esm.js.map +1 -1
  6. package/lib/@openglobus/og.umd.js +1 -1
  7. package/lib/@openglobus/og.umd.js.map +1 -1
  8. package/lib/js/camera/PlanetCamera.d.ts +2 -2
  9. package/lib/js/camera/PlanetCamera.js +3 -2
  10. package/lib/js/control/Atmosphere.js +7 -10
  11. package/lib/js/control/EarthCoordinates.js +2 -2
  12. package/lib/js/control/elevationProfile/ElevationProfile.d.ts +41 -25
  13. package/lib/js/control/elevationProfile/ElevationProfile.js +103 -74
  14. package/lib/js/control/elevationProfile/ElevationProfileButtonsView.d.ts +14 -0
  15. package/lib/js/control/elevationProfile/ElevationProfileButtonsView.js +61 -0
  16. package/lib/js/control/elevationProfile/ElevationProfileControl.d.ts +33 -0
  17. package/lib/js/control/elevationProfile/ElevationProfileControl.js +153 -0
  18. package/lib/js/control/elevationProfile/ElevationProfileLegend.d.ts +20 -0
  19. package/lib/js/control/elevationProfile/ElevationProfileLegend.js +82 -0
  20. package/lib/js/control/elevationProfile/ElevationProfileScene.d.ts +80 -0
  21. package/lib/js/control/elevationProfile/ElevationProfileScene.js +539 -0
  22. package/lib/js/control/elevationProfile/ElevationProfileView.d.ts +63 -0
  23. package/lib/js/control/elevationProfile/ElevationProfileView.js +504 -0
  24. package/lib/js/control/elevationProfile/PointListDialog.d.ts +12 -0
  25. package/lib/js/control/elevationProfile/PointListDialog.js +57 -0
  26. package/lib/js/control/index.d.ts +2 -1
  27. package/lib/js/control/index.js +2 -1
  28. package/lib/js/entity/Polyline.js +1 -1
  29. package/lib/js/layer/GeoImage.js +3 -0
  30. package/lib/js/renderer/Renderer.d.ts +0 -1
  31. package/lib/js/renderer/Renderer.js +3 -28
  32. package/lib/js/renderer/RendererEvents.js +0 -7
  33. package/lib/js/scene/Planet.d.ts +4 -0
  34. package/lib/js/scene/Planet.js +9 -1
  35. package/lib/js/terrain/GlobusTerrain.d.ts +3 -0
  36. package/lib/js/terrain/GlobusTerrain.js +14 -2
  37. package/lib/js/terrain/MapboxTerrain.js +29 -29
  38. package/lib/js/ui/Dialog.js +1 -1
  39. package/lib/js/utils/TerrainWorker.js +1 -1
  40. package/lib/js/utils/shared.d.ts +2 -1
  41. package/lib/js/utils/shared.js +21 -3
  42. package/package.json +1 -1
  43. package/lib/js/shaders/pickingMask.d.ts +0 -2
  44. package/lib/js/shaders/pickingMask.js +0 -22
@@ -0,0 +1,504 @@
1
+ import { View } from '../../ui/View';
2
+ import { SAFE, WARNING, COLLISION, ElevationProfile } from './ElevationProfile';
3
+ import { distanceFormatExt, binarySearch } from "../../utils/shared";
4
+ const FILL_COLOR = "rgb(63, 63, 63)";
5
+ const TRACK_COLOR = "rgb(0, 255, 50)";
6
+ const TERRAIN_COLOR = "rgb(198, 198, 198)";
7
+ const TERRAIN_FILL_COLOR = "rgb(64, 68, 82)";
8
+ const WARNING_COLOR = "rgb(255, 255, 0)";
9
+ const COLLISION_COLOR = "rgb(255, 0, 0)";
10
+ const LINE_COLORS = [TERRAIN_COLOR, WARNING_COLOR, COLLISION_COLOR];
11
+ const TERRAIN_ALPHA = 0.5;
12
+ const LINE_WIDTH = 5;
13
+ const ELEVATIONPROFILEVIEW_EVENTS = ["startdrag", "stopdrag", "pointer", "mouseenter", "mouseleave", "dblclick", "tracklength", "groundlength", "warninglength", "collisionlength"];
14
+ const TEMPLATE = `<div class="og-elevationprofile">
15
+ <div class="og-elevationprofile-loading" style="display: none;">
16
+ <div class="loadingio-spinner-bars-r354qqyl5v">
17
+ <div class="ldio-p0v5a1f6oz">
18
+ <div></div>
19
+ <div></div>
20
+ <div></div>
21
+ <div></div>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>`;
26
+ class ElevationProfileView extends View {
27
+ constructor(options = {}) {
28
+ super({
29
+ template: TEMPLATE,
30
+ model: new ElevationProfile()
31
+ });
32
+ this._onMouseDblClick = (e) => {
33
+ //
34
+ // @todo: The same code as in the pointer mouse move
35
+ //
36
+ let rect = this.$canvas.getBoundingClientRect();
37
+ let x = e.clientX - rect.left;
38
+ let pointerDistance = this._leftDistance + (this._rightDistance - this._leftDistance) * x / this.clientWidth;
39
+ let groundData = this.model.drawData[1];
40
+ let trackData = this.model.drawData[0];
41
+ let groundPoiIndex;
42
+ if (pointerDistance < 0) {
43
+ groundPoiIndex = 1;
44
+ pointerDistance = 0;
45
+ x = (0 - this._leftDistance) * this.clientWidth / (this._rightDistance - this._leftDistance);
46
+ }
47
+ else if (pointerDistance > this.model.planeDistance) {
48
+ groundPoiIndex = groundData.length - 1;
49
+ pointerDistance = this.model.planeDistance;
50
+ x = (pointerDistance - this._leftDistance) * this.clientWidth / (this._rightDistance - this._leftDistance);
51
+ }
52
+ else {
53
+ groundPoiIndex = -1 - binarySearch(groundData, pointerDistance, (a, b) => {
54
+ return a - b[0];
55
+ });
56
+ }
57
+ // Ground point
58
+ let gp0 = groundData[groundPoiIndex - 1], gp1 = groundData[groundPoiIndex];
59
+ let d = (pointerDistance - gp0[0]) / (gp1[0] - gp0[0]);
60
+ let groundElv = gp0[1] + d * (gp1[1] - gp0[1]);
61
+ // track point
62
+ let trackPoiIndex = gp0[4];
63
+ let tp0 = trackData[trackPoiIndex], tp1 = trackData[trackPoiIndex + 1];
64
+ d = (pointerDistance - tp0[0]) / (tp1[0] - tp0[0]);
65
+ let trackElv = tp0[1] + d * (tp1[1] - tp0[1]);
66
+ this.events.dispatch(this.events.dblclick, pointerDistance, tp0, tp1, gp0, gp1, trackPoiIndex, groundPoiIndex - 1, trackElv - groundElv);
67
+ };
68
+ this._onMouseEnter = (e) => {
69
+ this._isMouseOver = true;
70
+ this.events.dispatch(this.events.mouseenter, e);
71
+ };
72
+ this._onMouseOut = (e) => {
73
+ this._isMouseOver = false;
74
+ this.events.dispatch(this.events.mouseleave, e);
75
+ };
76
+ this._onMouseDown = (e) => {
77
+ if (this._isMouseOver) {
78
+ this._isDragging = true;
79
+ document.body.classList.add("og-timeline-unselectable");
80
+ this._clickPosX = e.clientX;
81
+ if (!this._customFrame) {
82
+ this._leftDistance = this.model.minX;
83
+ this._rightDistance = this.model.maxX;
84
+ }
85
+ this._clickLeftDistance = this._leftDistance;
86
+ this._clickRightDistance = this._rightDistance;
87
+ this.events.dispatch(this.events.startdrag, e);
88
+ }
89
+ };
90
+ this._onMouseUp = (e) => {
91
+ if (this._isDragging) {
92
+ this._isDragging = false;
93
+ document.body.classList.remove("og-timeline-unselectable");
94
+ this.events.dispatch(this.events.stopdrag, e);
95
+ }
96
+ };
97
+ this._onCanvasMouseMove = (e) => {
98
+ if (this.model.pointsReady) {
99
+ if (!this._isDragging) {
100
+ if (!this._customFrame) {
101
+ this._leftDistance = this.model.minX;
102
+ this._rightDistance = this.model.maxX;
103
+ }
104
+ let rect = this.$pointerCanvas.getBoundingClientRect();
105
+ let x = e.clientX - rect.left;
106
+ this.redrawPointerCanvas(x);
107
+ }
108
+ else {
109
+ this.clearPointerCanvas();
110
+ }
111
+ }
112
+ };
113
+ this._onMouseMove = (e) => {
114
+ if (this._isDragging && this.model.pointsReady) {
115
+ let offset = (this._clickPosX - e.clientX);
116
+ let distanceOffset = offset * this._canvasScale / this._pixelsInMeter_x;
117
+ this.setFrame(this._clickLeftDistance + distanceOffset, this._clickRightDistance + distanceOffset);
118
+ }
119
+ };
120
+ this._onMouseWheelFF = (e) => {
121
+ this._onMouseWheel(e);
122
+ };
123
+ this._onMouseWheel = (e) => {
124
+ if (this._isMouseOver && this.model.pointsReady) {
125
+ if (!this._customFrame) {
126
+ this._leftDistance = this.model.minX;
127
+ this._rightDistance = this.model.maxX;
128
+ }
129
+ this._customFrame = true;
130
+ let padDist = Math.sign(e.wheelDelta) * (this._rightDistance - this._leftDistance) / 20;
131
+ let rect = this.$canvas.getBoundingClientRect();
132
+ let pointerPosX = e.clientX - rect.left, pointerCenterOffsetX = pointerPosX - this.$canvas.clientWidth * 0.5;
133
+ let distanceCenterOffsetX = pointerCenterOffsetX * this._canvasScale / this._pixelsInMeter_x;
134
+ // Move distance under pointer to a screen center
135
+ let leftDistance = distanceCenterOffsetX + this._leftDistance + padDist;
136
+ let rightDistance = distanceCenterOffsetX + this._rightDistance - padDist;
137
+ // move center back to the mouse pointer
138
+ distanceCenterOffsetX = -pointerCenterOffsetX * (rightDistance - leftDistance) / this.clientWidth;
139
+ this.setFrame(leftDistance + distanceCenterOffsetX, rightDistance + distanceCenterOffsetX);
140
+ this.redrawPointerCanvas(pointerPosX);
141
+ }
142
+ };
143
+ //@ts-ignore
144
+ this.events = this.events.registerNames(ELEVATIONPROFILEVIEW_EVENTS);
145
+ this.fillStyle = options.fillStyle || FILL_COLOR;
146
+ this._customFrame = false;
147
+ this._leftDistance = 0;
148
+ this._rightDistance = 0;
149
+ this._pixelsInMeter_x = 0;
150
+ this._pixelsInMeter_y = 0;
151
+ this._canvasScale = 2;
152
+ this.$canvas = document.createElement("canvas");
153
+ this.$canvas.style.position = "absolute";
154
+ this._ctx = this.$canvas.getContext('2d');
155
+ this.$pointerCanvas = document.createElement("canvas");
156
+ this.$pointerCanvas.style.pointerEvents = "none";
157
+ this.$pointerCanvas.style.position = "absolute";
158
+ this._pointerCtx = this.$pointerCanvas.getContext('2d');
159
+ this.$loading = null;
160
+ this._isMouseOver = false;
161
+ this._isDragging = false;
162
+ this._clickPosX = 0;
163
+ this._clickLeftDistance = 0;
164
+ this._clickRightDistance = 0;
165
+ this._timeStartHandler = 0;
166
+ this._onResizeObserver_ = this._onResizeObserver.bind(this);
167
+ this._resizeObserver = new ResizeObserver(this._onResizeObserver_);
168
+ }
169
+ _onResizeObserver() {
170
+ this.resize();
171
+ }
172
+ get canvasScale() {
173
+ return this._canvasScale;
174
+ }
175
+ set canvasScale(scale) {
176
+ if (scale !== this._canvasScale) {
177
+ this._canvasScale = scale;
178
+ this.resize();
179
+ }
180
+ }
181
+ resize() {
182
+ this._resize();
183
+ this.draw();
184
+ }
185
+ render() {
186
+ super.render();
187
+ this._resizeObserver.observe(this.el);
188
+ this.el.appendChild(this.$canvas);
189
+ this.el.appendChild(this.$pointerCanvas);
190
+ this.model.events.on("profilecollected", (data) => {
191
+ this._hideLoading();
192
+ this.clearPointerCanvas();
193
+ this.draw();
194
+ });
195
+ this.model.events.on("startcollecting", () => {
196
+ clearTimeout(this._timeStartHandler);
197
+ //@ts-ignore
198
+ this._timeStartHandler = setTimeout(() => {
199
+ this._showLoading();
200
+ }, 450);
201
+ });
202
+ this.model.events.on("clear", () => {
203
+ this._customFrame = false;
204
+ this._leftDistance = 0;
205
+ this.clearCanvas();
206
+ this.clearPointerCanvas();
207
+ });
208
+ this.$loading = this.select(".og-elevationprofile-loading");
209
+ this.$canvas.addEventListener("mouseenter", this._onMouseEnter);
210
+ this.$canvas.addEventListener("mouseout", this._onMouseOut);
211
+ this.$canvas.addEventListener("dblclick", this._onMouseDblClick);
212
+ this.$canvas.addEventListener("mousemove", this._onCanvasMouseMove);
213
+ document.body.addEventListener("mousemove", this._onMouseMove);
214
+ document.body.addEventListener("mousedown", this._onMouseDown);
215
+ document.body.addEventListener("mouseup", this._onMouseUp);
216
+ document.body.addEventListener("wheel", this._onMouseWheelFF);
217
+ return this;
218
+ }
219
+ _hideLoading() {
220
+ clearTimeout(this._timeStartHandler);
221
+ this.$loading.style.display = "none";
222
+ }
223
+ _showLoading() {
224
+ this.$loading.style.display = "flex";
225
+ }
226
+ redrawPointerCanvas(x) {
227
+ this.clearPointerCanvas();
228
+ let pointerDistance = this._leftDistance + (this._rightDistance - this._leftDistance) * x / this.clientWidth;
229
+ let groundData = this.model.drawData[1];
230
+ let trackData = this.model.drawData[0];
231
+ let groundPoiIndex;
232
+ if (pointerDistance < 0) {
233
+ groundPoiIndex = 1;
234
+ pointerDistance = 0;
235
+ x = (0 - this._leftDistance) * this.clientWidth / (this._rightDistance - this._leftDistance);
236
+ }
237
+ else if (pointerDistance > this.model.planeDistance) {
238
+ groundPoiIndex = groundData.length - 1;
239
+ pointerDistance = this.model.planeDistance;
240
+ x = (pointerDistance - this._leftDistance) * this.clientWidth / (this._rightDistance - this._leftDistance);
241
+ }
242
+ else {
243
+ groundPoiIndex = -1 - binarySearch(groundData, pointerDistance, (a, b) => {
244
+ return a - b[0];
245
+ });
246
+ }
247
+ // Ground point
248
+ let gp0 = groundData[groundPoiIndex - 1], gp1 = groundData[groundPoiIndex];
249
+ let d = (pointerDistance - gp0[0]) / (gp1[0] - gp0[0]);
250
+ let groundElv = gp0[1] + d * (gp1[1] - gp0[1]);
251
+ // track point
252
+ let trackPoiIndex = gp0[4];
253
+ let tp0 = trackData[trackPoiIndex], tp1 = trackData[trackPoiIndex + 1];
254
+ d = (pointerDistance - tp0[0]) / (tp1[0] - tp0[0]);
255
+ let trackElv = tp0[1] + d * (tp1[1] - tp0[1]);
256
+ let trackY = (this.model.maxY - trackElv) * this._pixelsInMeter_y;
257
+ let groundY = (this.model.maxY - groundElv) * this._pixelsInMeter_y;
258
+ this.events.dispatch(this.events.pointer, pointerDistance, tp0, tp1, gp0, gp1, trackPoiIndex, groundPoiIndex - 1, trackElv - groundElv);
259
+ let ctx = this._pointerCtx;
260
+ // Vertical grey line
261
+ ctx.lineWidth = 3;
262
+ ctx.strokeStyle = "rgba(64,64,64,0.6)";
263
+ ctx.beginPath();
264
+ ctx.moveTo(x * this._canvasScale, 0);
265
+ ctx.lineTo(x * this._canvasScale, this.clientHeight * this._canvasScale);
266
+ ctx.stroke();
267
+ // Ground point
268
+ ctx.beginPath();
269
+ ctx.arc(x * this._canvasScale, groundY, 4, 0, 2 * Math.PI, false);
270
+ ctx.fillStyle = '#FFB277';
271
+ ctx.fill();
272
+ ctx.lineWidth = 4;
273
+ ctx.strokeStyle = '#FFB277';
274
+ ctx.stroke();
275
+ // Track point
276
+ ctx.beginPath();
277
+ ctx.arc(x * this._canvasScale, trackY, 4, 0, 2 * Math.PI, false);
278
+ ctx.fillStyle = '#FFB277';
279
+ ctx.fill();
280
+ ctx.lineWidth = 4;
281
+ ctx.strokeStyle = '#FFB277';
282
+ ctx.stroke();
283
+ // Vertical white line
284
+ ctx.lineWidth = 3;
285
+ ctx.strokeStyle = "#FFB277";
286
+ ctx.beginPath();
287
+ ctx.moveTo(x * this._canvasScale, groundY);
288
+ ctx.lineTo(x * this._canvasScale, trackY);
289
+ ctx.stroke();
290
+ // Altitude label
291
+ ctx.fillStyle = "white";
292
+ ctx.font = `${28 / devicePixelRatio}px Arial`;
293
+ ctx.textBaseline = "middle";
294
+ ctx.textAlign = "left";
295
+ ctx.fillText(`${Math.round(trackElv - groundElv).toString()} m`, (x + 5) * this._canvasScale, groundY + (trackY - groundY) * 0.5);
296
+ // distance from the begining label
297
+ ctx.fillStyle = "white";
298
+ ctx.font = `${28 / devicePixelRatio}px Arial`;
299
+ ctx.textAlign = "right";
300
+ let distStr = distanceFormatExt(pointerDistance);
301
+ ctx.fillText(`${distStr[0]} ${distStr[1]}`, (x - 5) * this._canvasScale, (this.clientHeight - 7) * this._canvasScale);
302
+ }
303
+ get clientWidth() {
304
+ return this.$canvas ? this.$canvas.width / this._canvasScale : 0;
305
+ }
306
+ get clientHeight() {
307
+ return this.$canvas ? this.$canvas.height / this._canvasScale : 0;
308
+ }
309
+ _resize() {
310
+ if (this.el) {
311
+ this.$canvas.width = this.el.clientWidth * this._canvasScale;
312
+ this.$canvas.height = this.el.clientHeight * this._canvasScale;
313
+ this.$canvas.style.width = `${this.el.clientWidth}px`;
314
+ this.$canvas.style.height = `${this.el.clientHeight}px`;
315
+ this.$pointerCanvas.width = this.el.clientWidth * this._canvasScale;
316
+ this.$pointerCanvas.height = this.el.clientHeight * this._canvasScale;
317
+ this.$pointerCanvas.style.width = `${this.el.clientWidth}px`;
318
+ this.$pointerCanvas.style.height = `${this.el.clientHeight}px`;
319
+ if (this._customFrame) {
320
+ this._pixelsInMeter_x = this._canvasScale * this.clientWidth / (this._rightDistance - this._leftDistance);
321
+ }
322
+ }
323
+ }
324
+ clearPointerCanvas() {
325
+ this._pointerCtx.fillStyle = "rgba(0,0,0,0)";
326
+ this._pointerCtx.clearRect(0, 0, this.clientWidth * this._canvasScale, this.clientHeight * this._canvasScale);
327
+ }
328
+ clearCanvas() {
329
+ const grd = this._ctx.createLinearGradient(0, 0, 0, this.clientHeight * this._canvasScale);
330
+ grd.addColorStop(0, "black");
331
+ grd.addColorStop(1, this.fillStyle);
332
+ this._ctx.fillStyle = grd;
333
+ this._ctx.fillRect(0, 0, this.clientWidth * this._canvasScale, this.clientHeight * this._canvasScale);
334
+ }
335
+ setFrame(leftDistance, rightDistance) {
336
+ this._leftDistance = leftDistance;
337
+ this._rightDistance = rightDistance;
338
+ this._customFrame = true;
339
+ this._pixelsInMeter_x = this._canvasScale * this.clientWidth / (this._rightDistance - this._leftDistance);
340
+ this.model.setRange(leftDistance, rightDistance);
341
+ this.draw();
342
+ }
343
+ _updateUnits() {
344
+ if (!this._customFrame) {
345
+ this._pixelsInMeter_x = this._canvasScale * this.clientWidth / (this.model.maxX - this.model.minX);
346
+ }
347
+ this._pixelsInMeter_y = this._canvasScale * this.clientHeight / (this.model.maxY - this.model.minY);
348
+ }
349
+ clear() {
350
+ this.model.clear();
351
+ this.clearCanvas();
352
+ }
353
+ draw() {
354
+ let trackCoords = this.model.drawData[0];
355
+ if (trackCoords.length > 1) {
356
+ this._updateUnits();
357
+ this.clearCanvas();
358
+ let groundCoords = this.model.drawData[1];
359
+ this._drawTrack(trackCoords, groundCoords);
360
+ this._drawTerrain(groundCoords);
361
+ this._drawWarningAndCollision(groundCoords);
362
+ this._drawLabels(trackCoords, groundCoords);
363
+ }
364
+ else {
365
+ this.clearCanvas();
366
+ }
367
+ }
368
+ _drawLabels(coords, groundCoords) {
369
+ let ctx = this._ctx;
370
+ if (ctx) {
371
+ let p0 = coords[0];
372
+ const maxY = this.model.maxY;
373
+ let x = (-this._leftDistance + p0[0]) * this._pixelsInMeter_x, yt = (maxY - p0[1]) * this._pixelsInMeter_y, yg = (maxY - groundCoords[p0[2]][1]) * this._pixelsInMeter_y;
374
+ // Track points
375
+ ctx.beginPath();
376
+ ctx.fillStyle = '#F7F718';
377
+ ctx.fillRect(x - 4, yt - 4, 8, 8);
378
+ ctx.stroke();
379
+ // Alt label
380
+ ctx.fillStyle = "white";
381
+ ctx.font = `${26 / devicePixelRatio}px Arial`;
382
+ ctx.textBaseline = "bottom";
383
+ ctx.textAlign = "left";
384
+ ctx.fillText(`${Math.round(p0[1] - groundCoords[p0[2]][1]).toString()} m`, x + 1, yt - 10);
385
+ ctx.stroke();
386
+ for (let i = 1, len = coords.length; i < len; i++) {
387
+ let pi = coords[i];
388
+ x = (-this._leftDistance + pi[0]) * this._pixelsInMeter_x;
389
+ yt = (maxY - pi[1]) * this._pixelsInMeter_y;
390
+ yg = (maxY - groundCoords[pi[2]][1]) * this._pixelsInMeter_y;
391
+ // Track points
392
+ ctx.beginPath();
393
+ ctx.fillStyle = '#F7F718';
394
+ ctx.fillRect(x - 4, yt - 4, 8, 8);
395
+ ctx.stroke();
396
+ // Alt label
397
+ ctx.fillStyle = "white";
398
+ ctx.fillText(`${Math.round(pi[1] - groundCoords[pi[2]][1]).toString()} m`, x + 1, yt - 10);
399
+ ctx.stroke();
400
+ }
401
+ }
402
+ }
403
+ _drawTrack(coords, groundCoords) {
404
+ let p0 = coords[0];
405
+ let ctx = this._ctx;
406
+ if (ctx) {
407
+ const maxY = this.model.maxY;
408
+ ctx.lineWidth = LINE_WIDTH;
409
+ ctx.strokeStyle = TRACK_COLOR;
410
+ ctx.beginPath();
411
+ ctx.moveTo((-this._leftDistance + p0[0]) * this._pixelsInMeter_x, (maxY - p0[1]) * this._pixelsInMeter_y);
412
+ let trackLength = 0;
413
+ for (let i = 1, len = coords.length; i < len; i++) {
414
+ let pi = coords[i];
415
+ ctx.lineTo((-this._leftDistance + pi[0]) * this._pixelsInMeter_x, (maxY - pi[1]) * this._pixelsInMeter_y);
416
+ let prevP = coords[i - 1];
417
+ let a = pi[0] - prevP[0], b = pi[1] - prevP[1], aa = a * a, bb = b * b;
418
+ trackLength += Math.sqrt(aa + bb);
419
+ }
420
+ ctx.stroke();
421
+ // Track points lines
422
+ ctx.lineWidth = 2;
423
+ ctx.strokeStyle = "rgba(255,255,255,0.7)";
424
+ ctx.beginPath();
425
+ let x = (-this._leftDistance + p0[0]) * this._pixelsInMeter_x, yt = (maxY - p0[1]) * this._pixelsInMeter_y, yg = (maxY - groundCoords[p0[2]][1]) * this._pixelsInMeter_y;
426
+ ctx.moveTo(x, yt);
427
+ ctx.lineTo(x, yg);
428
+ for (let i = 1, len = coords.length; i < len; i++) {
429
+ let pi = coords[i];
430
+ x = (-this._leftDistance + pi[0]) * this._pixelsInMeter_x;
431
+ yt = (maxY - pi[1]) * this._pixelsInMeter_y;
432
+ yg = (maxY - groundCoords[pi[2]][1]) * this._pixelsInMeter_y;
433
+ ctx.strokeStyle = "rgba(255,255,255,0.7)";
434
+ ctx.moveTo(x, yt);
435
+ ctx.lineTo(x, yg);
436
+ }
437
+ ctx.stroke();
438
+ this.events.dispatch(this.events.tracklength, trackLength);
439
+ }
440
+ }
441
+ _drawTerrain(coords) {
442
+ let p0 = coords[0];
443
+ let ctx = this._ctx;
444
+ if (ctx) {
445
+ const maxY = this.model.maxY;
446
+ ctx.lineWidth = LINE_WIDTH;
447
+ ctx.strokeStyle = TERRAIN_COLOR;
448
+ ctx.beginPath();
449
+ ctx.moveTo((-this._leftDistance + p0[0]) * this._pixelsInMeter_x, this.$canvas.height);
450
+ ctx.lineTo((-this._leftDistance + p0[0]) * this._pixelsInMeter_x, (maxY - p0[1]) * this._pixelsInMeter_y);
451
+ let groundLength = 0;
452
+ for (let i = 1, len = coords.length; i < len; i++) {
453
+ let pi = coords[i];
454
+ ctx.lineTo((-this._leftDistance + pi[0]) * this._pixelsInMeter_x, (maxY - pi[1]) * this._pixelsInMeter_y);
455
+ let prevP = coords[i - 1];
456
+ let a = pi[0] - prevP[0], b = pi[1] - prevP[1], aa = a * a, bb = b * b;
457
+ groundLength += Math.sqrt(aa + bb);
458
+ }
459
+ ctx.lineTo((-this._leftDistance + coords[coords.length - 1][0]) * this._pixelsInMeter_x, this.$canvas.height);
460
+ ctx.closePath();
461
+ ctx.stroke();
462
+ ctx.save();
463
+ ctx.fillStyle = TERRAIN_FILL_COLOR;
464
+ ctx.globalAlpha = TERRAIN_ALPHA;
465
+ ctx.fill();
466
+ ctx.restore();
467
+ ctx.globalAlpha = 1;
468
+ this.events.dispatch(this.events.groundlength, groundLength);
469
+ }
470
+ }
471
+ _drawWarningAndCollision(coords) {
472
+ let ctx = this._ctx;
473
+ if (ctx && coords.length > 1) {
474
+ let maxY = this.model.maxY;
475
+ ctx.lineWidth = LINE_WIDTH;
476
+ ctx.beginPath();
477
+ let warningLength = 0, collisionLength = 0;
478
+ for (let i = 0, len = coords.length - 1; i < len; i++) {
479
+ let pi0 = coords[i], pi1 = coords[i + 1];
480
+ if (pi0[2] !== SAFE && pi1[2] !== SAFE) {
481
+ let a = pi1[0] - pi0[0], b = pi1[1] - pi0[1], aa = a * a, bb = b * b;
482
+ if (pi0[2] === COLLISION) {
483
+ ctx.stroke();
484
+ ctx.beginPath();
485
+ ctx.strokeStyle = LINE_COLORS[COLLISION];
486
+ collisionLength += Math.sqrt(aa + bb);
487
+ }
488
+ else if (pi0[2] === WARNING) {
489
+ ctx.stroke();
490
+ ctx.beginPath();
491
+ ctx.strokeStyle = LINE_COLORS[WARNING];
492
+ warningLength += Math.sqrt(aa + bb);
493
+ }
494
+ ctx.moveTo((-this._leftDistance + pi0[0]) * this._pixelsInMeter_x, (maxY - pi0[1]) * this._pixelsInMeter_y);
495
+ ctx.lineTo((-this._leftDistance + pi1[0]) * this._pixelsInMeter_x, (maxY - pi1[1]) * this._pixelsInMeter_y);
496
+ }
497
+ }
498
+ ctx.stroke();
499
+ this.events.dispatch(this.events.warninglength, warningLength);
500
+ this.events.dispatch(this.events.collisionlength, collisionLength);
501
+ }
502
+ }
503
+ }
504
+ export { ElevationProfileView };
@@ -0,0 +1,12 @@
1
+ import { IDialogParams, Dialog } from "../../ui/Dialog";
2
+ import { ElevationProfileScene } from "./ElevationProfileScene";
3
+ interface IPointListDialog extends IDialogParams {
4
+ model: ElevationProfileScene;
5
+ }
6
+ declare class PointListDialog extends Dialog<ElevationProfileScene> {
7
+ $textarea: HTMLTextAreaElement | null;
8
+ constructor(params: IPointListDialog);
9
+ render(params?: any): this;
10
+ protected _onApplyClick: () => void;
11
+ }
12
+ export { PointListDialog };
@@ -0,0 +1,57 @@
1
+ import { Button } from "../../ui/Button";
2
+ import { View } from "../../ui/View";
3
+ import { Dialog } from "../../ui/Dialog";
4
+ import { LonLat } from "../../LonLat";
5
+ const LIST_TEMPLATE = `<div class="og-elevationprofile-list">
6
+ <textarea placeholder="[[lon, lat, height], [lon, lat, height], ..., [lon, lat, height]]"></textarea>
7
+ <div class="og-elevationprofile-list-buttons"></div>
8
+ </div>`;
9
+ class PointListDialog extends Dialog {
10
+ constructor(params) {
11
+ super({
12
+ title: "Points List",
13
+ visible: false,
14
+ resizable: true,
15
+ useHide: true,
16
+ top: 150,
17
+ left: 200,
18
+ width: 400,
19
+ height: 300,
20
+ minHeight: 100,
21
+ minWidth: 100,
22
+ ...params
23
+ });
24
+ this._onApplyClick = () => {
25
+ try {
26
+ this.model.clear();
27
+ let coordsArr = JSON.parse(this.$textarea.value);
28
+ let lonLatArr = new Array(coordsArr.length);
29
+ for (let i = 0; i < coordsArr.length; i++) {
30
+ let ci = coordsArr[i];
31
+ lonLatArr[i] = new LonLat(ci[0], ci[1], ci[2]);
32
+ }
33
+ this.model.addPointLonLatArrayAsync(lonLatArr);
34
+ }
35
+ catch (err) {
36
+ console.error(err);
37
+ }
38
+ };
39
+ this.$textarea = null;
40
+ }
41
+ render(params) {
42
+ super.render(params);
43
+ let view = new View({
44
+ template: LIST_TEMPLATE
45
+ });
46
+ view.appendTo(this.container);
47
+ let applyBtn = new Button({
48
+ classList: ["og-elevationprofile-list-apply"],
49
+ icon: "Apply"
50
+ });
51
+ applyBtn.appendTo(view.select(".og-elevationprofile-list-buttons"));
52
+ applyBtn.events.on("click", this._onApplyClick);
53
+ this.$textarea = view.select("textarea");
54
+ return this;
55
+ }
56
+ }
57
+ export { PointListDialog };
@@ -25,4 +25,5 @@ import { HeightRuler } from "./heightRuler/HeightRuler";
25
25
  import { Ruler } from "./ruler/Ruler";
26
26
  import { Selection } from "./selection/Selection";
27
27
  import { TimelineControl } from "./timeline/TimelineControl";
28
- export { CompassButton, Control, DebugInfo, DrawingControl, DrawingSwitcher, EarthCoordinates, EarthNavigation, GeoImageDragControl, HeightRuler, KeyboardNavigation, LayerAnimation, LayerSwitcher, Lighting, MouseNavigation, MouseWheelZoomControl, Ruler, RulerSwitcher, ScaleControl, Selection, ShowFps, SimpleNavigation, SimpleSkyBackground, Sun, TimelineControl, ToggleWireframe, TouchNavigation, ZoomControl };
28
+ import { ElevationProfileControl } from "./elevationProfile/ElevationProfileControl";
29
+ export { CompassButton, Control, DebugInfo, DrawingControl, DrawingSwitcher, EarthCoordinates, EarthNavigation, GeoImageDragControl, HeightRuler, KeyboardNavigation, LayerAnimation, LayerSwitcher, Lighting, MouseNavigation, MouseWheelZoomControl, Ruler, RulerSwitcher, ScaleControl, Selection, ShowFps, SimpleNavigation, SimpleSkyBackground, Sun, TimelineControl, ToggleWireframe, TouchNavigation, ZoomControl, ElevationProfileControl };
@@ -25,4 +25,5 @@ import { HeightRuler } from "./heightRuler/HeightRuler";
25
25
  import { Ruler } from "./ruler/Ruler";
26
26
  import { Selection } from "./selection/Selection";
27
27
  import { TimelineControl } from "./timeline/TimelineControl";
28
- export { CompassButton, Control, DebugInfo, DrawingControl, DrawingSwitcher, EarthCoordinates, EarthNavigation, GeoImageDragControl, HeightRuler, KeyboardNavigation, LayerAnimation, LayerSwitcher, Lighting, MouseNavigation, MouseWheelZoomControl, Ruler, RulerSwitcher, ScaleControl, Selection, ShowFps, SimpleNavigation, SimpleSkyBackground, Sun, TimelineControl, ToggleWireframe, TouchNavigation, ZoomControl };
28
+ import { ElevationProfileControl } from "./elevationProfile/ElevationProfileControl";
29
+ export { CompassButton, Control, DebugInfo, DrawingControl, DrawingSwitcher, EarthCoordinates, EarthNavigation, GeoImageDragControl, HeightRuler, KeyboardNavigation, LayerAnimation, LayerSwitcher, Lighting, MouseNavigation, MouseWheelZoomControl, Ruler, RulerSwitcher, ScaleControl, Selection, ShowFps, SimpleNavigation, SimpleSkyBackground, Sun, TimelineControl, ToggleWireframe, TouchNavigation, ZoomControl, ElevationProfileControl };
@@ -1040,7 +1040,7 @@ class Polyline {
1040
1040
  * @param {boolean} [skipEllipsoid] -
1041
1041
  */
1042
1042
  appendPoint3v(point3v, color, skipEllipsoid) {
1043
- if (this._path3v.length === 0) {
1043
+ if (this._path3v.length === 0 || !this._renderNode) {
1044
1044
  this._pathColors.push([color || this._defaultColor]);
1045
1045
  this.addPoint3v(point3v);
1046
1046
  }
@@ -32,6 +32,7 @@ class GeoImage extends BaseGeoImage {
32
32
  this._sourceReady = false;
33
33
  this._sourceCreated = false;
34
34
  this._image = new Image();
35
+ this._image.crossOrigin = "Anonymous";
35
36
  this._onLoad_ = this._onLoad.bind(this);
36
37
  this._image.addEventListener("load", this._onLoad_);
37
38
  this._image.src = src;
@@ -46,6 +47,7 @@ class GeoImage extends BaseGeoImage {
46
47
  this._sourceCreated = false;
47
48
  this._sourceReady = false;
48
49
  this._image = image;
50
+ this._image.crossOrigin = "Anonymous";
49
51
  this._src = image.src;
50
52
  if (isImageLoaded(this._image)) {
51
53
  this._applyImage(this._image);
@@ -105,6 +107,7 @@ class GeoImage extends BaseGeoImage {
105
107
  }
106
108
  else {
107
109
  this._image = new Image();
110
+ this._image.crossOrigin = "Anonymous";
108
111
  this._onLoad_ = this._onLoad.bind(this);
109
112
  this._image.addEventListener("load", this._onLoad_);
110
113
  this._image.src = this._src;
@@ -151,7 +151,6 @@ declare class Renderer {
151
151
  screenFramePositionBuffer: WebGLBufferExt | null;
152
152
  screenTexture: Record<string, WebGLTexture>;
153
153
  outputTexture: WebGLTexture | null;
154
- protected _pickingMaskCoordinatesBuffer: WebGLBufferExt | null;
155
154
  protected _skipDistanceFrame: boolean;
156
155
  protected _distancePixelBuffer: WebGLBuffer | null;
157
156
  protected _skipPickingFrame: boolean;