@openglobus/og 0.14.10 → 0.15.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.
Files changed (140) hide show
  1. package/css/og.css +378 -275
  2. package/dist/@openglobus/og.css +1 -1
  3. package/dist/@openglobus/og.esm.js +2 -2
  4. package/dist/@openglobus/og.esm.js.map +1 -1
  5. package/dist/@openglobus/og.umd.js +2 -2
  6. package/dist/@openglobus/og.umd.js.map +1 -1
  7. package/package.json +18 -17
  8. package/src/og/Clock.js +218 -194
  9. package/src/og/Globe.js +5 -5
  10. package/src/og/Object3d.js +104 -145
  11. package/src/og/camera/Camera.js +31 -27
  12. package/src/og/camera/PlanetCamera.js +22 -14
  13. package/src/og/cons.js +107 -107
  14. package/src/og/control/Atmosphere.js +396 -0
  15. package/src/og/control/CompassButton.js +11 -18
  16. package/src/og/control/Control.js +187 -188
  17. package/src/og/control/GeoImageDragControl.js +84 -66
  18. package/src/og/control/LayerSwitcher.js +56 -138
  19. package/src/og/control/Lighting.js +314 -186
  20. package/src/og/control/MouseNavigation.js +2 -2
  21. package/src/og/control/RulerSwitcher.js +24 -19
  22. package/src/og/control/ScaleControl.js +30 -10
  23. package/src/og/control/SimpleSkyBackground.js +210 -0
  24. package/src/og/control/Sun.js +2 -0
  25. package/src/og/control/ZoomControl.js +30 -42
  26. package/src/og/control/index.js +6 -0
  27. package/src/og/control/ruler/RulerScene.js +5 -23
  28. package/src/og/control/selection/Selection.js +99 -0
  29. package/src/og/control/selection/SelectionScene.js +350 -0
  30. package/src/og/control/timeline/TimelineControl.js +99 -0
  31. package/src/og/control/timeline/TimelineModel.js +133 -0
  32. package/src/og/control/timeline/TimelineView.js +449 -0
  33. package/src/og/control/timeline/timelineUtils.js +132 -0
  34. package/src/og/ellipsoid/Ellipsoid.js +120 -93
  35. package/src/og/ellipsoid/wgs84.js +13 -13
  36. package/src/og/entity/Entity.js +36 -9
  37. package/src/og/entity/EntityCollection.js +0 -2
  38. package/src/og/entity/GeoObject.js +72 -56
  39. package/src/og/entity/GeoObjectHandler.js +487 -656
  40. package/src/og/entity/GeometryHandler.js +1341 -1337
  41. package/src/og/entity/Polyline.js +0 -16
  42. package/src/og/entity/Ray.js +0 -10
  43. package/src/og/entity/RayHandler.js +3 -44
  44. package/src/og/entity/Strip.js +1 -6
  45. package/src/og/index.js +10 -6
  46. package/src/og/input/input.js +3 -1
  47. package/src/og/layer/CanvasTiles.js +39 -34
  48. package/src/og/layer/Layer.js +69 -9
  49. package/src/og/layer/Material.js +1 -8
  50. package/src/og/layer/WMS.js +16 -5
  51. package/src/og/light/LightSource.js +2 -0
  52. package/src/og/math/Line3.js +140 -139
  53. package/src/og/math/Plane.js +118 -117
  54. package/src/og/math/Ray.js +242 -239
  55. package/src/og/math/Vec3.js +56 -37
  56. package/src/og/math/Vec4.js +3 -4
  57. package/src/og/math.js +21 -21
  58. package/src/og/quadTree/Node.js +5 -4
  59. package/src/og/quadTree/index.js +12 -0
  60. package/src/og/renderer/Renderer.js +64 -37
  61. package/src/og/renderer/RendererEvents.js +1071 -1065
  62. package/src/og/scene/Planet.js +352 -172
  63. package/src/og/scene/RenderNode.js +27 -12
  64. package/src/og/segment/Segment.js +0 -5
  65. package/src/og/shaders/atmos.js +332 -0
  66. package/src/og/shaders/drawnode.js +475 -109
  67. package/src/og/shaders/geoObject.js +96 -51
  68. package/src/og/shaders/polyline.js +212 -17
  69. package/src/og/shaders/ray.js +13 -6
  70. package/src/og/shaders/toneMapping.js +5 -5
  71. package/src/og/shaders/utils.js +88 -0
  72. package/src/og/terrain/GlobusTerrain.js +5 -4
  73. package/src/og/terrain/MapboxTerrain.js +231 -52
  74. package/src/og/ui/Button.js +106 -0
  75. package/src/og/ui/ButtonGroup.js +57 -0
  76. package/src/og/ui/Dialog.js +242 -0
  77. package/src/og/ui/Slider.js +144 -0
  78. package/src/og/ui/ToggleButton.js +51 -0
  79. package/src/og/{control → ui}/UIhelpers.js +11 -2
  80. package/src/og/ui/View.js +190 -0
  81. package/src/og/utils/shared.js +960 -942
  82. package/src/og/webgl/Framebuffer.js +308 -387
  83. package/src/og/webgl/Handler.js +90 -30
  84. package/src/og/webgl/Multisample.js +8 -0
  85. package/types/Clock.d.ts +7 -2
  86. package/types/Object3d.d.ts +14 -3
  87. package/types/camera/Camera.d.ts +18 -17
  88. package/types/camera/PlanetCamera.d.ts +3 -1
  89. package/types/control/Atmosphere.d.ts +15 -0
  90. package/types/control/CompassButton.d.ts +1 -2
  91. package/types/control/GeoImageDragControl.d.ts +7 -1
  92. package/types/control/LayerSwitcher.d.ts +5 -6
  93. package/types/control/Lighting.d.ts +32 -7
  94. package/types/control/ScaleControl.d.ts +2 -1
  95. package/types/control/SimpleSkyBackground.d.ts +15 -0
  96. package/types/control/ZoomControl.d.ts +0 -1
  97. package/types/control/index.d.ts +4 -1
  98. package/types/control/ruler/RulerScene.d.ts +0 -1
  99. package/types/control/selection/Selection.d.ts +49 -0
  100. package/types/control/selection/SelectionScene.d.ts +34 -0
  101. package/types/ellipsoid/Ellipsoid.d.ts +3 -2
  102. package/types/entity/Entity.d.ts +8 -0
  103. package/types/entity/GeoObject.d.ts +28 -22
  104. package/types/entity/GeoObjectHandler.d.ts +16 -56
  105. package/types/entity/Ray.d.ts +0 -3
  106. package/types/entity/RayHandler.d.ts +0 -4
  107. package/types/index.d.ts +7 -5
  108. package/types/input/input.d.ts +2 -0
  109. package/types/layer/CanvasTiles.d.ts +1 -0
  110. package/types/layer/Layer.d.ts +9 -0
  111. package/types/layer/WMS.d.ts +7 -3
  112. package/types/math/Plane.d.ts +1 -1
  113. package/types/math/Vec3.d.ts +19 -16
  114. package/types/math/Vec4.d.ts +2 -3
  115. package/types/math.d.ts +20 -20
  116. package/types/quadTree/index.d.ts +10 -0
  117. package/types/renderer/Renderer.d.ts +11 -37
  118. package/types/scene/Planet.d.ts +27 -1
  119. package/types/scene/RenderNode.d.ts +2 -1
  120. package/types/segment/Segment.d.ts +1 -1
  121. package/types/shaders/atmos.d.ts +4 -0
  122. package/types/shaders/drawnode.d.ts +3 -2
  123. package/types/shaders/utils.d.ts +1 -0
  124. package/types/terrain/GlobusTerrain.d.ts +1 -1
  125. package/types/terrain/MapboxTerrain.d.ts +2 -1
  126. package/types/ui/Button.d.ts +21 -0
  127. package/types/ui/Dialog.d.ts +41 -0
  128. package/types/ui/Slider.d.ts +30 -0
  129. package/types/ui/ToggleButton.d.ts +10 -0
  130. package/types/{control → ui}/UIhelpers.d.ts +1 -1
  131. package/types/ui/View.d.ts +32 -0
  132. package/types/utils/shared.d.ts +16 -14
  133. package/types/webgl/Framebuffer.d.ts +2 -5
  134. package/types/webgl/Handler.d.ts +15 -10
  135. package/types/webgl/Multisample.d.ts +2 -0
  136. package/src/og/ajax.js +0 -204
  137. package/src/og/entity/Object3d.js +0 -504
  138. package/src/og/utils/quadTreeType.js +0 -11
  139. package/types/ajax.d.ts +0 -24
  140. package/types/utils/quadTreeType.d.ts +0 -8
@@ -0,0 +1,449 @@
1
+ 'use strict';
2
+
3
+ import { View } from '../../ui/View.js';
4
+ import { TimelineModel } from './TimelineModel.js';
5
+ import {
6
+ addSeconds,
7
+ createCanvasHTML,
8
+ dateToStr,
9
+ drawNotch,
10
+ drawText,
11
+ getNearestTimeLeft,
12
+ getScale
13
+ } from './timelineUtils.js';
14
+ import { ToggleButton } from "../../ui/ToggleButton.js";
15
+ import { Button } from "../../ui/Button.js";
16
+ import { ButtonGroup } from "../../ui/ButtonGroup.js";
17
+
18
+ const SECONDS_TO_MILLISECONDS = 1000.0;
19
+ const MILLISECONDS_TO_SECONDS = 1.0 / SECONDS_TO_MILLISECONDS;
20
+ const EVENT_LIST = [
21
+ 'startdrag',
22
+ 'stopdrag',
23
+ 'startdragcurrent',
24
+ 'stopdragcurrent',
25
+ 'setcurrent',
26
+ 'reset',
27
+ 'play',
28
+ 'playback',
29
+ 'pause',
30
+ 'visibility'
31
+ ];
32
+
33
+ const ICON_PLAY_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
34
+ const ICON_PAUSE_SVG = '<?xml version="1.0" ?><!DOCTYPE svg PUBLIC \'-//W3C//DTD SVG 1.1//EN\' \'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\'><svg enable-background="new 0 0 512 512" height="512px" version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Layer_6"><rect fill="#252525" height="320" width="60" x="153" y="96"/><rect fill="#252525" height="320" width="60" x="299" y="96"/></g></svg>';
35
+
36
+ const SCALE_FILL_COLOR = "rgba(64, 59, 59, 1.0)";
37
+ const SCALE_NOTCH_COLOR = "#bfbfbf";
38
+ const SCALE_TIME_COLOR = "#bfbfbf";
39
+
40
+ const TEMPLATE =
41
+ `<div class="og-timeline">
42
+
43
+ <div class="og-timeline-top">
44
+ </div>
45
+
46
+ <div class="og-timeline-frame">
47
+ <div class="og-timeline-current">
48
+ <div class="og-timeline-current-spin">
49
+ <div class="og-timeline-current-arrow"></div>
50
+ </div>
51
+ </div>
52
+ <div class="og-timeline-scale"></div>
53
+ </div>
54
+
55
+ <div class="og-timeline-bottom">
56
+ <div class="og-timeline-controls">
57
+ </div>
58
+ </div>
59
+
60
+ </div>`;
61
+
62
+ class TimelineView extends View {
63
+
64
+ constructor(options = {}) {
65
+ super({
66
+ template: TEMPLATE,
67
+ eventList: EVENT_LIST,
68
+ model: new TimelineModel({
69
+ rangeStart: options.rangeStart,
70
+ rangeEnd: options.rangeEnd,
71
+ current: options.currentDate,
72
+ minDate: options.minDate,
73
+ maxDate: options.maxDate
74
+ })
75
+ });
76
+
77
+ this.fillStyle = options.fillStyle || SCALE_FILL_COLOR;
78
+
79
+ this.$controls;
80
+
81
+ this._frameEl = null;
82
+ this._currentEl = null;
83
+ this._canvasEl = createCanvasHTML();
84
+ this._ctx = this._canvasEl.getContext('2d');
85
+
86
+ this._isMouseOver = false;
87
+ this._isDragging = false;
88
+ this._isCurrentDragging = false;
89
+ this._isCurrentMouseOver = false;
90
+
91
+ this._minWidth = 330;
92
+ this._canvasScale = 2;
93
+
94
+ this._millisecondsInPixel = 0;
95
+
96
+ this._clickPosX = 0;
97
+ this._clickRangeStart = new Date();
98
+ this._clickRangeEnd = new Date();
99
+ this._clickCurrentDate = new Date();
100
+
101
+ this._clickTime = 0;
102
+ this._clickDelay = 450;
103
+
104
+ this._onResizeObserver_ = this._onResizeObserver.bind(this);
105
+ this._resizeObserver = new ResizeObserver(this._onResizeObserver_);
106
+
107
+ this._pauseBtn = new ToggleButton({
108
+ classList: ["og-timeline-control_button"],
109
+ icon: ICON_PAUSE_SVG,
110
+ name: "pause"
111
+ });
112
+
113
+ this._playBtn = new ToggleButton({
114
+ classList: ["og-timeline-control_button"],
115
+ icon: ICON_PLAY_SVG,
116
+ name: "play",
117
+ isActive: true,
118
+ preventClick: true
119
+ });
120
+
121
+ this._buttons = new ButtonGroup({
122
+ buttons: [this._pauseBtn, this._playBtn]
123
+ })
124
+
125
+ this._visibility = null;
126
+ }
127
+
128
+ _onResizeObserver() {
129
+ this.resize();
130
+ }
131
+
132
+ get canvasScale() {
133
+ return this._canvasScale;
134
+ }
135
+
136
+ set canvasScale(scale) {
137
+ if (scale !== this._canvasScale) {
138
+ this._canvasScale = scale;
139
+ this.resize();
140
+ }
141
+ }
142
+
143
+ resize() {
144
+ this._resize();
145
+ this.draw();
146
+ }
147
+
148
+ afterRender(parentNode) {
149
+ this.resize();
150
+ }
151
+
152
+ render() {
153
+ super.render();
154
+
155
+ this.$controls = this.select(".og-timeline-controls");
156
+
157
+ this._frameEl = this.select(".og-timeline-frame");
158
+ this._currentEl = this.select(".og-timeline-current");
159
+ this.select(".og-timeline-frame .og-timeline-scale").appendChild(this._canvasEl);
160
+
161
+ this._resizeObserver.observe(this.el);
162
+
163
+ this.model.on("change", () => {
164
+ this.draw()
165
+ });
166
+
167
+ this.model.on("current", (d) => {
168
+ this._drawCurrent();
169
+ this._events.dispatch(this._events.setcurrent, d);
170
+ });
171
+
172
+ this._canvasEl.addEventListener("mouseenter", this._onMouseEnter.bind(this));
173
+ this._canvasEl.addEventListener("mouseout", this._onMouseOut.bind(this));
174
+
175
+ this._currentEl.addEventListener("mouseenter", this._onCurrentMouseEnter.bind(this));
176
+ this._currentEl.addEventListener("mouseout", this._onCurrentMouseOut.bind(this));
177
+
178
+ document.body.addEventListener("mousemove", this._onMouseMove.bind(this));
179
+ document.body.addEventListener("mousedown", this._onMouseDown.bind(this));
180
+ document.body.addEventListener("mouseup", this._onMouseUp.bind(this));
181
+ document.body.addEventListener("mousewheel", this._onMouseWheel.bind(this));
182
+
183
+ this._playBtn.appendTo(this.$controls);
184
+ this._pauseBtn.appendTo(this.$controls);
185
+
186
+ this._buttons.on("change", (btn) => {
187
+ switch (btn.name) {
188
+ case "play":
189
+ this.play();
190
+ break;
191
+ case "pause":
192
+ this.pause();
193
+ break;
194
+ }
195
+ });
196
+
197
+ // let mltView = new View({
198
+ // template: `<div class="og-timeline-multiplier">
199
+ // <select>
200
+ // <option value="0.25">0.25</option>
201
+ // <option value="0.5">0.5</option>
202
+ // <option value="1" selected>1.0</option>
203
+ // <option value="2">2.0</option>
204
+ // <option value="3">3.0</option>
205
+ // <option value="5">5.0</option>
206
+ // </select>
207
+ // </div>`
208
+ // });
209
+
210
+ //mltView.appendTo($ctl)
211
+
212
+ // let multiplierEl = this.select(".og-timeline-multiplier select");
213
+ //
214
+ // multiplierEl.value = this.model.multiplier.toString();
215
+ // multiplierEl.addEventListener("change", (e) => {
216
+ // this.model.multiplier = Math.sign(this.model.multiplier) * Number(e.target.value);
217
+ // });
218
+
219
+ this.setVisibility(true);
220
+
221
+ return this;
222
+ }
223
+
224
+ setVisibility(visibility) {
225
+ if (visibility !== this._visibility) {
226
+ this._visibility = visibility;
227
+ if (visibility) {
228
+ this.el.style.display = "block";
229
+ } else {
230
+ this.el.style.display = "none";
231
+ }
232
+ this._events.dispatch(this._events.visibility, visibility);
233
+ }
234
+ }
235
+
236
+ reset() {
237
+ this.model.stop();
238
+ this._events.dispatch(this._events.reset, this.model);
239
+ }
240
+
241
+ play() {
242
+ this.model.multiplier = Math.abs(this.model.multiplier);
243
+ this.model.play();
244
+ this._events.dispatch(this._events.play, this.model);
245
+ }
246
+
247
+ pause() {
248
+ this.model.stop();
249
+ this._events.dispatch(this._events.pause, this.model);
250
+ }
251
+
252
+ playBack() {
253
+ this.model.multiplier = -1 * Math.abs(this.model.multiplier);
254
+ this.model.play();
255
+ this._events.dispatch(this._events.playback, this.model);
256
+ }
257
+
258
+ _onMouseWheel(e) {
259
+ if (this._isMouseOver) {
260
+ let rect = this._canvasEl.getBoundingClientRect();
261
+ let pointerPosX = e.clientX - rect.left,
262
+ pointerCenterOffsetX = -(pointerPosX - this.clientWidth * 0.5);
263
+ let pointerTime = this.model.rangeStartTime + this._millisecondsInPixel * pointerPosX;
264
+ this._zoom(pointerTime, pointerCenterOffsetX, Math.sign(e.wheelDelta));
265
+ } else if (this._isCurrentMouseOver) {
266
+ let pointerCenterOffsetX = -((this.model.currentTime - this.model.rangeStartTime) / this._millisecondsInPixel - this.clientWidth * 0.5);
267
+ this._zoom(this.model.currentTime, pointerCenterOffsetX, Math.sign(e.wheelDelta));
268
+ }
269
+ }
270
+
271
+ _zoom(pointerTime, pointerCenterOffsetX, dir) {
272
+ let centerTime = this.model.rangeStartTime + 0.5 * this.model.range;
273
+
274
+ let centerTimeOffset = (pointerTime - centerTime) * MILLISECONDS_TO_SECONDS;
275
+
276
+ let rangeStart = addSeconds(this.model.rangeStart, centerTimeOffset),
277
+ rangeEnd = addSeconds(this.model.rangeEnd, centerTimeOffset);
278
+
279
+ let delta = ((rangeEnd.getTime() - rangeStart.getTime()) / 20) * MILLISECONDS_TO_SECONDS;
280
+
281
+ let newRangeStart = addSeconds(rangeStart, delta * dir);
282
+ let newRangeEnd = addSeconds(rangeEnd, -delta * dir);
283
+ let msPx = (newRangeEnd.getTime() - newRangeStart.getTime()) / this.clientWidth;
284
+
285
+ if (msPx < 31536000000 && msPx > 0.1) {
286
+ let timeOffset = msPx * pointerCenterOffsetX * MILLISECONDS_TO_SECONDS;
287
+
288
+ this.model.set(
289
+ addSeconds(newRangeStart, timeOffset),
290
+ addSeconds(newRangeEnd, timeOffset)
291
+ );
292
+ }
293
+ }
294
+
295
+ _onMouseDown(e) {
296
+ if (this._isMouseOver) {
297
+ this._isDragging = true;
298
+ document.body.classList.add("og-timeline-unselectable");
299
+
300
+ this._clickPosX = e.clientX;
301
+ this._clickTime = Date.now();
302
+
303
+ this._clickRangeStart = this.model.rangeStart;
304
+ this._clickRangeEnd = this.model.rangeEnd;
305
+
306
+ this._events.dispatch(this._events.startdrag, e);
307
+ } else if (this._isCurrentMouseOver) {
308
+ this._isCurrentDragging = true;
309
+ document.body.classList.add("og-timeline-unselectable");
310
+
311
+ this._clickPosX = e.clientX;
312
+
313
+ this._clickCurrentDate = this.model.current;
314
+
315
+ this._events.dispatch(this._events.startdragcurrent, e);
316
+ }
317
+ }
318
+
319
+ _onMouseUp(e) {
320
+ if (this._isDragging) {
321
+ this._isDragging = false;
322
+ document.body.classList.remove("og-timeline-unselectable");
323
+ if (this._clickPosX === e.clientX && (Date.now() - this._clickTime) < this._clickDelay) {
324
+ let rect = this._canvasEl.getBoundingClientRect();
325
+ let current = new Date(this.model.rangeStartTime + (e.clientX - rect.left) * this._millisecondsInPixel);
326
+ this.model.current = current;
327
+ this._events.dispatch(this._events.stopdrag, current);
328
+ this._events.dispatch(this._events.setcurrent, current);
329
+ } else {
330
+ this._events.dispatch(this._events.stopdrag, this.model.current);
331
+ }
332
+ } else if (this._isCurrentDragging) {
333
+ this._isCurrentDragging = false;
334
+ document.body.classList.remove("og-timeline-unselectable");
335
+ this._events.dispatch(this._events.stopdragcurrent, this.model.current);
336
+ }
337
+ }
338
+
339
+ _onMouseEnter() {
340
+ this._isMouseOver = true;
341
+ }
342
+
343
+ _onMouseOut() {
344
+ this._isMouseOver = false;
345
+ }
346
+
347
+ _onCurrentMouseEnter() {
348
+ this._isCurrentMouseOver = true;
349
+ }
350
+
351
+ _onCurrentMouseOut() {
352
+ this._isCurrentMouseOver = false;
353
+ }
354
+
355
+ _onMouseMove(e) {
356
+ if (this._isDragging) {
357
+ let offsetSec = (this._clickPosX - e.clientX) * this._millisecondsInPixel * MILLISECONDS_TO_SECONDS;
358
+ this.model.set(addSeconds(this._clickRangeStart, offsetSec), addSeconds(this._clickRangeEnd, offsetSec))
359
+ } else if (this._isCurrentDragging) {
360
+ let offsetSec = (this._clickPosX - e.clientX) * this._millisecondsInPixel * MILLISECONDS_TO_SECONDS;
361
+ let newCurrent = addSeconds(this._clickCurrentDate, -offsetSec);
362
+ if (newCurrent >= this.model.rangeStart && newCurrent <= this.model.rangeEnd) {
363
+ this.model.current = addSeconds(this._clickCurrentDate, -offsetSec);
364
+ }
365
+ }
366
+ }
367
+
368
+ get clientWidth() {
369
+ return this._canvasEl ? this._canvasEl.width / this._canvasScale : 0;
370
+ }
371
+
372
+ get clientHeight() {
373
+ return this._canvasEl ? this._canvasEl.height / this._canvasScale : 0;
374
+ }
375
+
376
+ _resize() {
377
+ if (this._canvasEl && this._frameEl) {
378
+ this._canvasEl.width = this._frameEl.clientWidth * this._canvasScale;
379
+ this._canvasEl.height = this._frameEl.clientHeight * this._canvasScale;
380
+ this._canvasEl.style.width = `${this._frameEl.clientWidth}px`;
381
+ this._canvasEl.style.height = `${this._frameEl.clientHeight}px`;
382
+ }
383
+ }
384
+
385
+ getOffsetbyTime(milliseconds) {
386
+ return (milliseconds - this.model.rangeStartTime) / this._millisecondsInPixel;
387
+ }
388
+
389
+ remove() {
390
+ super.remove();
391
+ this.model.stop();
392
+ }
393
+
394
+ _clearCanvas() {
395
+ if (this._ctx) {
396
+ this._ctx.fillStyle = this.fillStyle;
397
+ this._ctx.fillRect(0, 0, this.clientWidth * this._canvasScale, this.clientHeight * this._canvasScale);
398
+ }
399
+ }
400
+
401
+ _drawCurrent() {
402
+ let curPosX = (this.model.currentTime - this.model.rangeStartTime) / this._millisecondsInPixel;
403
+ if (this.model.current < this.model.rangeStart || this.model.current > this.model.rangeEnd) {
404
+ this._currentEl.style.display = "none";
405
+ } else {
406
+ this._currentEl.style.display = "block";
407
+ this._currentEl.style.transform = `translateX(${curPosX}px)`;
408
+ }
409
+ }
410
+
411
+ draw() {
412
+ if (this._ctx) {
413
+ this._millisecondsInPixel = (this.model.range / this.clientWidth);
414
+ let minWidthMs = this._minWidth * this._millisecondsInPixel;
415
+ let scaleData = getScale(minWidthMs * MILLISECONDS_TO_SECONDS);
416
+ if (scaleData) {
417
+
418
+ this._clearCanvas();
419
+
420
+ let scaleMs = scaleData[0] * SECONDS_TO_MILLISECONDS,
421
+ scalePx = scaleMs / this._millisecondsInPixel,
422
+ segCount = scaleData[1];
423
+
424
+ let originTime = getNearestTimeLeft(this.model.rangeStartTime, scaleMs);
425
+
426
+ let showMillisconds = scaleData[0] < 1.0,
427
+ showTime = scaleData[0] < 86400.0;
428
+
429
+ for (let i = originTime, rangeEnd = this.model.rangeEndTime + scaleMs; i < rangeEnd; i += scaleMs) {
430
+ let x = this.getOffsetbyTime(i);
431
+ if (x >= 0 && x <= this.clientWidth * this._canvasScale) {
432
+ drawNotch(this._ctx, x * this._canvasScale, 10 * this._canvasScale, 2 * this._canvasScale, SCALE_NOTCH_COLOR);
433
+ }
434
+ for (let j = 1; j < segCount; j++) {
435
+ let xx = x + j * (scalePx / segCount);
436
+ if (xx >= 0 && xx <= this.clientWidth * this._canvasScale) {
437
+ drawNotch(this._ctx, xx * this._canvasScale, 5 * this._canvasScale, 1 * this._canvasScale, SCALE_NOTCH_COLOR);
438
+ }
439
+ }
440
+ drawText(this._ctx, dateToStr(new Date(i), showTime, showMillisconds), x * this._canvasScale, 26 * this._canvasScale, "24px monospace", SCALE_TIME_COLOR, "center");
441
+ }
442
+
443
+ this._drawCurrent();
444
+ }
445
+ }
446
+ }
447
+ }
448
+
449
+ export { TimelineView }
@@ -0,0 +1,132 @@
1
+ 'use strict';
2
+
3
+ import * as math from '../../math.js';
4
+
5
+ export function addSeconds(date, seconds) {
6
+ return new Date(+date + seconds * 1000);
7
+ }
8
+
9
+ export function dateToStr(date, showTime = true, showMilliseconds = false) {
10
+
11
+ let month = MONTHS[date.getMonth()],
12
+ day = date.getUTCDate(),
13
+ year = date.getUTCFullYear();
14
+
15
+ if (showTime) {
16
+ let h = date.getUTCHours().toString().padStart(2, '0'),
17
+ m = date.getUTCMinutes().toString().padStart(2, '0'),
18
+ s = date.getUTCSeconds().toString().padStart(2, '0');
19
+
20
+ if (showMilliseconds) {
21
+ let ms = date.getUTCMilliseconds().toString().padStart(3, '0');
22
+ return `${month} ${day} ${year} ${h}:${m}:${s}.${ms}`;
23
+ }
24
+
25
+ return `${month} ${day} ${year} ${h}:${m}:${s}`;
26
+ }
27
+
28
+ return `${month} ${day} ${year}`;
29
+ }
30
+
31
+ export function createCanvasHTML() {
32
+ return document.createElement("canvas");
33
+ }
34
+
35
+ export function getNearestTimeLeft(t, div) {
36
+ return t - (t % div);
37
+ }
38
+
39
+ export function drawNotch(ctx, xOffset = 0, size = 10, thickness = 2, color = "white") {
40
+ ctx.lineWidth = thickness;
41
+ ctx.strokeStyle = color;
42
+ ctx.beginPath();
43
+ ctx.moveTo(xOffset, 0);
44
+ ctx.lineTo(xOffset, size);
45
+ ctx.stroke();
46
+ }
47
+
48
+ export function drawText(ctx, text, x, y, font = "12px Arial", fillStyle = "black", align = "left", baseLine = "bottom", rotDeg) {
49
+ ctx.save();
50
+ ctx.translate(x, y);
51
+ ctx.rotate(rotDeg * math.RADIANS);
52
+ ctx.fillStyle = fillStyle;
53
+ ctx.textBaseline = baseLine;
54
+ ctx.font = font;
55
+ ctx.textAlign = align;
56
+ ctx.fillText(text, 0, 0);
57
+ ctx.restore();
58
+ }
59
+
60
+ export const SCALES = [
61
+ [0.001, 10],
62
+ [0.002, 10],
63
+ [0.005, 10],
64
+ [0.01, 10],
65
+ [0.02, 10],
66
+ [0.05, 10],
67
+ [0.1, 10],
68
+ [0.25, 10],
69
+ [0.5, 5],
70
+ [1.0, 10],
71
+ [2.0, 10],
72
+ [5.0, 5],
73
+ [10.0, 10],
74
+ [15.0, 15],
75
+ [30.0, 6],
76
+ [60.0, 12], // 1min
77
+ [120.0, 12], // 2min
78
+ [300.0, 5], // 5min
79
+ [600.0, 10], // 10min
80
+ [900.0, 15], // 15min
81
+ [1800.0, 6], // 30min
82
+ [3600.0, 12], // 1hr
83
+ [7200.0, 10], // 2hr
84
+ [14400.0, 4], // 4hr
85
+ [21600.0, 6], // 6hr
86
+ [43200.0, 12], // 12hr
87
+ [86400.0, 24], // 24hr
88
+ [172800.0, 2], // 2days
89
+ [345600.0, 4], // 4days
90
+ [604800.0, 7], // 7days
91
+ [1296000.0, 15], // 15days
92
+ [2592000.0, 5], // 30days
93
+ [5184000.0, 6], // 60days
94
+ [7776000.0, 9], // 90days
95
+ [15552000.0, 18], // 180days
96
+ [31536000.0, 12], // 365days
97
+ [63072000.0, 2], // 2years
98
+ [126144000.0, 4], // 4years
99
+ [157680000.0, 5], // 5years
100
+ [315360000.0, 10], // 10years
101
+ [630720000.0, 2], // 20years
102
+ [1261440000.0, 4], // 40years
103
+ [1576800000.0, 5], // 50years
104
+ [3153600000.0, 10], // 100years
105
+ [6307200000.0, 2], // 200years
106
+ [12614400000.0, 4], // 400years
107
+ [15768000000.0, 5], // 500years
108
+ [31536000000.0, 10], // 1000years
109
+ ];
110
+
111
+ export function getScale(seconds) {
112
+ for (let i = 0, len = SCALES.length; i < len; i++) {
113
+ if (SCALES[i][0] > seconds) {
114
+ return SCALES[i - 1];
115
+ }
116
+ }
117
+ }
118
+
119
+ export const MONTHS = [
120
+ "Jan",
121
+ "Feb",
122
+ "Mar",
123
+ "Apr",
124
+ "May",
125
+ "Jun",
126
+ "Jul",
127
+ "Aug",
128
+ "Sep",
129
+ "Oct",
130
+ "Nov",
131
+ "Dec",
132
+ ];