@kteneyck/cesium-timeline-angular 0.9.0 → 0.10.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.
|
@@ -19,6 +19,10 @@ class TimelineControlsComponent {
|
|
|
19
19
|
theme;
|
|
20
20
|
swimLanesVisible;
|
|
21
21
|
labels;
|
|
22
|
+
liveButtonSize = 'md';
|
|
23
|
+
liveButtonPosition = 'left';
|
|
24
|
+
/** @see TimelineBaseProps.live */
|
|
25
|
+
live = false;
|
|
22
26
|
dateTimeClick = new EventEmitter();
|
|
23
27
|
playPause = new EventEmitter();
|
|
24
28
|
jumpToStart = new EventEmitter();
|
|
@@ -36,6 +40,12 @@ class TimelineControlsComponent {
|
|
|
36
40
|
get isNormalSpeed() { return this.multiplier === 1; }
|
|
37
41
|
get absMultiplier() { return Math.abs(this.multiplier); }
|
|
38
42
|
get hasSwimLaneToggle() { return this.swimLanesVisible != null; }
|
|
43
|
+
static LIVE_SIZE_MAP = {
|
|
44
|
+
sm: { width: 44, height: 18, fontSize: '10px', dot: 5, borderRadius: '3px' },
|
|
45
|
+
md: { width: 56, height: 22, fontSize: '11px', dot: 6, borderRadius: '3px' },
|
|
46
|
+
lg: { width: 72, height: 30, fontSize: '13px', dot: 8, borderRadius: '4px' },
|
|
47
|
+
};
|
|
48
|
+
get liveSize() { return TimelineControlsComponent.LIVE_SIZE_MAP[this.liveButtonSize]; }
|
|
39
49
|
get timeFormat() { return splitForDisplay(this.dateTimeFormat).timeFormat; }
|
|
40
50
|
get dateFormat() { return splitForDisplay(this.dateTimeFormat).dateFormat; }
|
|
41
51
|
get formattedTime() { return formatDateTime(this.currentTime, this.timeFormat, this.timezone); }
|
|
@@ -58,7 +68,7 @@ class TimelineControlsComponent {
|
|
|
58
68
|
this.ro?.disconnect();
|
|
59
69
|
}
|
|
60
70
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: TimelineControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
61
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: TimelineControlsComponent, isStandalone: true, selector: "ct-timeline-controls", inputs: { currentTime: "currentTime", isPlaying: "isPlaying", multiplier: "multiplier", dateTimeFormat: "dateTimeFormat", timezone: "timezone", isLive: "isLive", hasStartTime: "hasStartTime", hasEndTime: "hasEndTime", showJumpToStart: "showJumpToStart", showJumpToEnd: "showJumpToEnd", theme: "theme", swimLanesVisible: "swimLanesVisible", labels: "labels" }, outputs: { dateTimeClick: "dateTimeClick", playPause: "playPause", jumpToStart: "jumpToStart", rewind: "rewind", fastForward: "fastForward", jumpToEnd: "jumpToEnd", jumpToLive: "jumpToLive", resetSpeed: "resetSpeed", toggleSwimLanes: "toggleSwimLanes" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: `
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: TimelineControlsComponent, isStandalone: true, selector: "ct-timeline-controls", inputs: { currentTime: "currentTime", isPlaying: "isPlaying", multiplier: "multiplier", dateTimeFormat: "dateTimeFormat", timezone: "timezone", isLive: "isLive", hasStartTime: "hasStartTime", hasEndTime: "hasEndTime", showJumpToStart: "showJumpToStart", showJumpToEnd: "showJumpToEnd", theme: "theme", swimLanesVisible: "swimLanesVisible", labels: "labels", liveButtonSize: "liveButtonSize", liveButtonPosition: "liveButtonPosition", live: "live" }, outputs: { dateTimeClick: "dateTimeClick", playPause: "playPause", jumpToStart: "jumpToStart", rewind: "rewind", fastForward: "fastForward", jumpToEnd: "jumpToEnd", jumpToLive: "jumpToLive", resetSpeed: "resetSpeed", toggleSwimLanes: "toggleSwimLanes" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: `
|
|
62
72
|
<div
|
|
63
73
|
#container
|
|
64
74
|
[style.display]="isNarrow ? 'flex' : 'grid'"
|
|
@@ -69,14 +79,14 @@ class TimelineControlsComponent {
|
|
|
69
79
|
[style.border-bottom]="'1px solid ' + theme.controlBarBorder"
|
|
70
80
|
[style.font-family]="'system-ui, -apple-system, sans-serif'"
|
|
71
81
|
>
|
|
72
|
-
<!-- Left: Datetime + LIVE
|
|
82
|
+
<!-- Left: Datetime + LIVE (if position=left) -->
|
|
73
83
|
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
|
|
74
84
|
<div
|
|
75
|
-
(click)="dateTimeClick.emit()"
|
|
76
|
-
[title]="dateTimeClick.observed ? l.dateTimeClickTooltip : ''"
|
|
85
|
+
(click)="!live && dateTimeClick.emit()"
|
|
86
|
+
[title]="(!live && dateTimeClick.observed) ? l.dateTimeClickTooltip : ''"
|
|
77
87
|
[style.color]="theme.labelColor"
|
|
78
88
|
style="font-family:monospace;line-height:1.15;border-radius:4px;padding:2px 4px;transition:background 0.15s"
|
|
79
|
-
[style.cursor]="dateTimeClick.observed ? 'pointer' : 'default'"
|
|
89
|
+
[style.cursor]="(!live && dateTimeClick.observed) ? 'pointer' : 'default'"
|
|
80
90
|
>
|
|
81
91
|
@if (timeFormat) {
|
|
82
92
|
<div style="font-size:2em;font-weight:bold;letter-spacing:0.02em">
|
|
@@ -98,35 +108,47 @@ class TimelineControlsComponent {
|
|
|
98
108
|
}
|
|
99
109
|
</div>
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
@if (liveButtonPosition === 'left') {
|
|
112
|
+
<div style="display:flex;align-items:center;gap:4px">
|
|
113
|
+
<button
|
|
114
|
+
(click)="!live && jumpToLive.emit()"
|
|
115
|
+
[style.color]="(live || isLive) ? theme.controlBarBackground : theme.buttonActiveColor"
|
|
116
|
+
[style.background-color]="(live || isLive) ? theme.buttonActiveColor : 'transparent'"
|
|
117
|
+
[style.border-color]="theme.buttonActiveColor"
|
|
118
|
+
[style.opacity]="1"
|
|
119
|
+
[style.width.px]="liveSize.width"
|
|
120
|
+
[style.min-width.px]="liveSize.width"
|
|
121
|
+
[style.height.px]="liveSize.height"
|
|
122
|
+
[style.font-size]="liveSize.fontSize"
|
|
123
|
+
[style.border-radius]="liveSize.borderRadius"
|
|
124
|
+
[style.cursor]="live ? 'default' : 'pointer'"
|
|
125
|
+
style="background:none;border:1px solid;font-weight:bold;letter-spacing:0.05em;display:flex;align-items:center;justify-content:center;padding:0;gap:4px;font-family:system-ui,-apple-system,sans-serif;transition:opacity 0.15s"
|
|
126
|
+
[title]="(live || isLive) ? l.liveActiveTooltip : l.liveTooltip"
|
|
127
|
+
>
|
|
128
|
+
@if (live || isLive) {
|
|
129
|
+
<span
|
|
130
|
+
[style.width.px]="liveSize.dot"
|
|
131
|
+
[style.height.px]="liveSize.dot"
|
|
132
|
+
[style.background-color]="theme.liveDotColor"
|
|
133
|
+
style="border-radius:50%;display:inline-block;flex-shrink:0"
|
|
134
|
+
></span>
|
|
135
|
+
}
|
|
136
|
+
{{ (live || isLive) ? l.liveActiveLabel : l.liveLabel }}
|
|
137
|
+
</button>
|
|
138
|
+
@if (!isNormalSpeed && !live) {
|
|
118
139
|
<button
|
|
119
140
|
(click)="resetSpeed.emit()"
|
|
120
141
|
[style.color]="theme.buttonActiveColor"
|
|
121
142
|
[style.border-color]="theme.buttonActiveColor + '44'"
|
|
122
|
-
style="
|
|
143
|
+
[style.width.px]="liveSize.width"
|
|
144
|
+
[style.min-width.px]="liveSize.width"
|
|
145
|
+
[style.height.px]="liveSize.height"
|
|
146
|
+
style="background:none;border:1px solid;cursor:pointer;font-size:11px;border-radius:4px;display:flex;align-items:center;justify-content:center;padding:0;font-family:system-ui,-apple-system,sans-serif;transition:background-color 0.15s"
|
|
123
147
|
[title]="l.resetSpeedTooltip"
|
|
124
|
-
>
|
|
125
|
-
{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}
|
|
126
|
-
</button>
|
|
148
|
+
>{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}</button>
|
|
127
149
|
}
|
|
128
150
|
</div>
|
|
129
|
-
|
|
151
|
+
}
|
|
130
152
|
</div>
|
|
131
153
|
|
|
132
154
|
<!-- Center: Transport buttons -->
|
|
@@ -135,7 +157,7 @@ class TimelineControlsComponent {
|
|
|
135
157
|
[style.flex]="isNarrow ? '1' : undefined"
|
|
136
158
|
[style.justify-content]="isNarrow ? 'center' : undefined"
|
|
137
159
|
>
|
|
138
|
-
@if (showJumpToStart !== false) {
|
|
160
|
+
@if (!live && showJumpToStart !== false) {
|
|
139
161
|
<button
|
|
140
162
|
(click)="hasStartTime && jumpToStart.emit()"
|
|
141
163
|
[disabled]="!hasStartTime"
|
|
@@ -147,53 +169,59 @@ class TimelineControlsComponent {
|
|
|
147
169
|
>⏮</button>
|
|
148
170
|
}
|
|
149
171
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
@if (!live) {
|
|
173
|
+
<button
|
|
174
|
+
(click)="rewind.emit()"
|
|
175
|
+
[style.color]="isRewinding ? theme.buttonActiveColor : theme.buttonColor"
|
|
176
|
+
[style.border-color]="isRewinding ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
177
|
+
class="ct-btn ct-btn-wide"
|
|
178
|
+
[title]="isRewinding ? resolveRewindActive(absMultiplier) : l.rewindTooltip"
|
|
179
|
+
>
|
|
180
|
+
@if (isRewinding) {
|
|
181
|
+
<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>◀◀
|
|
182
|
+
} @else {
|
|
183
|
+
◀◀
|
|
184
|
+
}
|
|
185
|
+
</button>
|
|
186
|
+
}
|
|
163
187
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
@if (!live) {
|
|
189
|
+
<button
|
|
190
|
+
(click)="playPause.emit(!isPlaying)"
|
|
191
|
+
[style.color]="theme.buttonActiveColor"
|
|
192
|
+
[style.border-color]="theme.buttonActiveColor + '55'"
|
|
193
|
+
[style.padding-left]="isPlaying ? '0' : '2px'"
|
|
194
|
+
class="ct-btn ct-btn-play"
|
|
195
|
+
[title]="isPlaying ? l.pauseTooltip : (isRewinding ? l.playFromRewindTooltip : l.playTooltip)"
|
|
196
|
+
>
|
|
197
|
+
@if (isPlaying) {
|
|
198
|
+
<svg width="14" height="16" viewBox="0 0 14 16" fill="currentColor">
|
|
199
|
+
<rect x="1" y="0" width="4" height="16" rx="1"/>
|
|
200
|
+
<rect x="9" y="0" width="4" height="16" rx="1"/>
|
|
201
|
+
</svg>
|
|
202
|
+
} @else {
|
|
203
|
+
▶
|
|
204
|
+
}
|
|
205
|
+
</button>
|
|
206
|
+
}
|
|
181
207
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
208
|
+
@if (!live) {
|
|
209
|
+
<button
|
|
210
|
+
(click)="fastForward.emit()"
|
|
211
|
+
[style.color]="isFastForward ? theme.buttonActiveColor : theme.buttonColor"
|
|
212
|
+
[style.border-color]="isFastForward ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
213
|
+
class="ct-btn ct-btn-wide"
|
|
214
|
+
[title]="isFastForward ? resolveFastForwardActive(absMultiplier) : l.fastForwardTooltip"
|
|
215
|
+
>
|
|
216
|
+
@if (isFastForward) {
|
|
217
|
+
▶▶<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>
|
|
218
|
+
} @else {
|
|
219
|
+
▶▶
|
|
220
|
+
}
|
|
221
|
+
</button>
|
|
222
|
+
}
|
|
195
223
|
|
|
196
|
-
@if (showJumpToEnd !== false) {
|
|
224
|
+
@if (!live && showJumpToEnd !== false) {
|
|
197
225
|
<button
|
|
198
226
|
(click)="hasEndTime && jumpToEnd.emit()"
|
|
199
227
|
[disabled]="!hasEndTime"
|
|
@@ -206,9 +234,50 @@ class TimelineControlsComponent {
|
|
|
206
234
|
}
|
|
207
235
|
</div>
|
|
208
236
|
|
|
209
|
-
<!-- Right: swim-lane toggle -->
|
|
237
|
+
<!-- Right: LIVE (if position=right) + swim-lane toggle -->
|
|
210
238
|
@if (!isNarrow) {
|
|
211
|
-
<div style="display:flex;justify-content:flex-end;align-items:center">
|
|
239
|
+
<div style="display:flex;justify-content:flex-end;align-items:center;gap:8px">
|
|
240
|
+
@if (liveButtonPosition === 'right') {
|
|
241
|
+
<div style="display:flex;align-items:center;gap:4px">
|
|
242
|
+
<button
|
|
243
|
+
(click)="!live && jumpToLive.emit()"
|
|
244
|
+
[style.color]="(live || isLive) ? theme.controlBarBackground : theme.buttonActiveColor"
|
|
245
|
+
[style.background-color]="(live || isLive) ? theme.buttonActiveColor : 'transparent'"
|
|
246
|
+
[style.border-color]="theme.buttonActiveColor"
|
|
247
|
+
[style.opacity]="1"
|
|
248
|
+
[style.width.px]="liveSize.width"
|
|
249
|
+
[style.min-width.px]="liveSize.width"
|
|
250
|
+
[style.height.px]="liveSize.height"
|
|
251
|
+
[style.font-size]="liveSize.fontSize"
|
|
252
|
+
[style.border-radius]="liveSize.borderRadius"
|
|
253
|
+
[style.cursor]="live ? 'default' : 'pointer'"
|
|
254
|
+
style="background:none;border:1px solid;font-weight:bold;letter-spacing:0.05em;display:flex;align-items:center;justify-content:center;padding:0;gap:4px;font-family:system-ui,-apple-system,sans-serif;transition:opacity 0.15s"
|
|
255
|
+
[title]="(live || isLive) ? l.liveActiveTooltip : l.liveTooltip"
|
|
256
|
+
>
|
|
257
|
+
@if (live || isLive) {
|
|
258
|
+
<span
|
|
259
|
+
[style.width.px]="liveSize.dot"
|
|
260
|
+
[style.height.px]="liveSize.dot"
|
|
261
|
+
[style.background-color]="theme.liveDotColor"
|
|
262
|
+
style="border-radius:50%;display:inline-block;flex-shrink:0"
|
|
263
|
+
></span>
|
|
264
|
+
}
|
|
265
|
+
{{ (live || isLive) ? l.liveActiveLabel : l.liveLabel }}
|
|
266
|
+
</button>
|
|
267
|
+
@if (!isNormalSpeed && !live) {
|
|
268
|
+
<button
|
|
269
|
+
(click)="resetSpeed.emit()"
|
|
270
|
+
[style.color]="theme.buttonActiveColor"
|
|
271
|
+
[style.border-color]="theme.buttonActiveColor + '44'"
|
|
272
|
+
[style.width.px]="liveSize.width"
|
|
273
|
+
[style.min-width.px]="liveSize.width"
|
|
274
|
+
[style.height.px]="liveSize.height"
|
|
275
|
+
style="background:none;border:1px solid;cursor:pointer;font-size:11px;border-radius:4px;display:flex;align-items:center;justify-content:center;padding:0;font-family:system-ui,-apple-system,sans-serif;transition:background-color 0.15s"
|
|
276
|
+
[title]="l.resetSpeedTooltip"
|
|
277
|
+
>{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}</button>
|
|
278
|
+
}
|
|
279
|
+
</div>
|
|
280
|
+
}
|
|
212
281
|
@if (hasSwimLaneToggle) {
|
|
213
282
|
<button
|
|
214
283
|
(click)="toggleSwimLanes.emit()"
|
|
@@ -263,14 +332,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
263
332
|
[style.border-bottom]="'1px solid ' + theme.controlBarBorder"
|
|
264
333
|
[style.font-family]="'system-ui, -apple-system, sans-serif'"
|
|
265
334
|
>
|
|
266
|
-
<!-- Left: Datetime + LIVE
|
|
335
|
+
<!-- Left: Datetime + LIVE (if position=left) -->
|
|
267
336
|
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
|
|
268
337
|
<div
|
|
269
|
-
(click)="dateTimeClick.emit()"
|
|
270
|
-
[title]="dateTimeClick.observed ? l.dateTimeClickTooltip : ''"
|
|
338
|
+
(click)="!live && dateTimeClick.emit()"
|
|
339
|
+
[title]="(!live && dateTimeClick.observed) ? l.dateTimeClickTooltip : ''"
|
|
271
340
|
[style.color]="theme.labelColor"
|
|
272
341
|
style="font-family:monospace;line-height:1.15;border-radius:4px;padding:2px 4px;transition:background 0.15s"
|
|
273
|
-
[style.cursor]="dateTimeClick.observed ? 'pointer' : 'default'"
|
|
342
|
+
[style.cursor]="(!live && dateTimeClick.observed) ? 'pointer' : 'default'"
|
|
274
343
|
>
|
|
275
344
|
@if (timeFormat) {
|
|
276
345
|
<div style="font-size:2em;font-weight:bold;letter-spacing:0.02em">
|
|
@@ -292,35 +361,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
292
361
|
}
|
|
293
362
|
</div>
|
|
294
363
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
364
|
+
@if (liveButtonPosition === 'left') {
|
|
365
|
+
<div style="display:flex;align-items:center;gap:4px">
|
|
366
|
+
<button
|
|
367
|
+
(click)="!live && jumpToLive.emit()"
|
|
368
|
+
[style.color]="(live || isLive) ? theme.controlBarBackground : theme.buttonActiveColor"
|
|
369
|
+
[style.background-color]="(live || isLive) ? theme.buttonActiveColor : 'transparent'"
|
|
370
|
+
[style.border-color]="theme.buttonActiveColor"
|
|
371
|
+
[style.opacity]="1"
|
|
372
|
+
[style.width.px]="liveSize.width"
|
|
373
|
+
[style.min-width.px]="liveSize.width"
|
|
374
|
+
[style.height.px]="liveSize.height"
|
|
375
|
+
[style.font-size]="liveSize.fontSize"
|
|
376
|
+
[style.border-radius]="liveSize.borderRadius"
|
|
377
|
+
[style.cursor]="live ? 'default' : 'pointer'"
|
|
378
|
+
style="background:none;border:1px solid;font-weight:bold;letter-spacing:0.05em;display:flex;align-items:center;justify-content:center;padding:0;gap:4px;font-family:system-ui,-apple-system,sans-serif;transition:opacity 0.15s"
|
|
379
|
+
[title]="(live || isLive) ? l.liveActiveTooltip : l.liveTooltip"
|
|
380
|
+
>
|
|
381
|
+
@if (live || isLive) {
|
|
382
|
+
<span
|
|
383
|
+
[style.width.px]="liveSize.dot"
|
|
384
|
+
[style.height.px]="liveSize.dot"
|
|
385
|
+
[style.background-color]="theme.liveDotColor"
|
|
386
|
+
style="border-radius:50%;display:inline-block;flex-shrink:0"
|
|
387
|
+
></span>
|
|
388
|
+
}
|
|
389
|
+
{{ (live || isLive) ? l.liveActiveLabel : l.liveLabel }}
|
|
390
|
+
</button>
|
|
391
|
+
@if (!isNormalSpeed && !live) {
|
|
312
392
|
<button
|
|
313
393
|
(click)="resetSpeed.emit()"
|
|
314
394
|
[style.color]="theme.buttonActiveColor"
|
|
315
395
|
[style.border-color]="theme.buttonActiveColor + '44'"
|
|
316
|
-
style="
|
|
396
|
+
[style.width.px]="liveSize.width"
|
|
397
|
+
[style.min-width.px]="liveSize.width"
|
|
398
|
+
[style.height.px]="liveSize.height"
|
|
399
|
+
style="background:none;border:1px solid;cursor:pointer;font-size:11px;border-radius:4px;display:flex;align-items:center;justify-content:center;padding:0;font-family:system-ui,-apple-system,sans-serif;transition:background-color 0.15s"
|
|
317
400
|
[title]="l.resetSpeedTooltip"
|
|
318
|
-
>
|
|
319
|
-
{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}
|
|
320
|
-
</button>
|
|
401
|
+
>{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}</button>
|
|
321
402
|
}
|
|
322
403
|
</div>
|
|
323
|
-
|
|
404
|
+
}
|
|
324
405
|
</div>
|
|
325
406
|
|
|
326
407
|
<!-- Center: Transport buttons -->
|
|
@@ -329,7 +410,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
329
410
|
[style.flex]="isNarrow ? '1' : undefined"
|
|
330
411
|
[style.justify-content]="isNarrow ? 'center' : undefined"
|
|
331
412
|
>
|
|
332
|
-
@if (showJumpToStart !== false) {
|
|
413
|
+
@if (!live && showJumpToStart !== false) {
|
|
333
414
|
<button
|
|
334
415
|
(click)="hasStartTime && jumpToStart.emit()"
|
|
335
416
|
[disabled]="!hasStartTime"
|
|
@@ -341,53 +422,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
341
422
|
>⏮</button>
|
|
342
423
|
}
|
|
343
424
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
425
|
+
@if (!live) {
|
|
426
|
+
<button
|
|
427
|
+
(click)="rewind.emit()"
|
|
428
|
+
[style.color]="isRewinding ? theme.buttonActiveColor : theme.buttonColor"
|
|
429
|
+
[style.border-color]="isRewinding ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
430
|
+
class="ct-btn ct-btn-wide"
|
|
431
|
+
[title]="isRewinding ? resolveRewindActive(absMultiplier) : l.rewindTooltip"
|
|
432
|
+
>
|
|
433
|
+
@if (isRewinding) {
|
|
434
|
+
<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>◀◀
|
|
435
|
+
} @else {
|
|
436
|
+
◀◀
|
|
437
|
+
}
|
|
438
|
+
</button>
|
|
439
|
+
}
|
|
357
440
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
<
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
441
|
+
@if (!live) {
|
|
442
|
+
<button
|
|
443
|
+
(click)="playPause.emit(!isPlaying)"
|
|
444
|
+
[style.color]="theme.buttonActiveColor"
|
|
445
|
+
[style.border-color]="theme.buttonActiveColor + '55'"
|
|
446
|
+
[style.padding-left]="isPlaying ? '0' : '2px'"
|
|
447
|
+
class="ct-btn ct-btn-play"
|
|
448
|
+
[title]="isPlaying ? l.pauseTooltip : (isRewinding ? l.playFromRewindTooltip : l.playTooltip)"
|
|
449
|
+
>
|
|
450
|
+
@if (isPlaying) {
|
|
451
|
+
<svg width="14" height="16" viewBox="0 0 14 16" fill="currentColor">
|
|
452
|
+
<rect x="1" y="0" width="4" height="16" rx="1"/>
|
|
453
|
+
<rect x="9" y="0" width="4" height="16" rx="1"/>
|
|
454
|
+
</svg>
|
|
455
|
+
} @else {
|
|
456
|
+
▶
|
|
457
|
+
}
|
|
458
|
+
</button>
|
|
459
|
+
}
|
|
375
460
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
461
|
+
@if (!live) {
|
|
462
|
+
<button
|
|
463
|
+
(click)="fastForward.emit()"
|
|
464
|
+
[style.color]="isFastForward ? theme.buttonActiveColor : theme.buttonColor"
|
|
465
|
+
[style.border-color]="isFastForward ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
466
|
+
class="ct-btn ct-btn-wide"
|
|
467
|
+
[title]="isFastForward ? resolveFastForwardActive(absMultiplier) : l.fastForwardTooltip"
|
|
468
|
+
>
|
|
469
|
+
@if (isFastForward) {
|
|
470
|
+
▶▶<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>
|
|
471
|
+
} @else {
|
|
472
|
+
▶▶
|
|
473
|
+
}
|
|
474
|
+
</button>
|
|
475
|
+
}
|
|
389
476
|
|
|
390
|
-
@if (showJumpToEnd !== false) {
|
|
477
|
+
@if (!live && showJumpToEnd !== false) {
|
|
391
478
|
<button
|
|
392
479
|
(click)="hasEndTime && jumpToEnd.emit()"
|
|
393
480
|
[disabled]="!hasEndTime"
|
|
@@ -400,9 +487,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
400
487
|
}
|
|
401
488
|
</div>
|
|
402
489
|
|
|
403
|
-
<!-- Right: swim-lane toggle -->
|
|
490
|
+
<!-- Right: LIVE (if position=right) + swim-lane toggle -->
|
|
404
491
|
@if (!isNarrow) {
|
|
405
|
-
<div style="display:flex;justify-content:flex-end;align-items:center">
|
|
492
|
+
<div style="display:flex;justify-content:flex-end;align-items:center;gap:8px">
|
|
493
|
+
@if (liveButtonPosition === 'right') {
|
|
494
|
+
<div style="display:flex;align-items:center;gap:4px">
|
|
495
|
+
<button
|
|
496
|
+
(click)="!live && jumpToLive.emit()"
|
|
497
|
+
[style.color]="(live || isLive) ? theme.controlBarBackground : theme.buttonActiveColor"
|
|
498
|
+
[style.background-color]="(live || isLive) ? theme.buttonActiveColor : 'transparent'"
|
|
499
|
+
[style.border-color]="theme.buttonActiveColor"
|
|
500
|
+
[style.opacity]="1"
|
|
501
|
+
[style.width.px]="liveSize.width"
|
|
502
|
+
[style.min-width.px]="liveSize.width"
|
|
503
|
+
[style.height.px]="liveSize.height"
|
|
504
|
+
[style.font-size]="liveSize.fontSize"
|
|
505
|
+
[style.border-radius]="liveSize.borderRadius"
|
|
506
|
+
[style.cursor]="live ? 'default' : 'pointer'"
|
|
507
|
+
style="background:none;border:1px solid;font-weight:bold;letter-spacing:0.05em;display:flex;align-items:center;justify-content:center;padding:0;gap:4px;font-family:system-ui,-apple-system,sans-serif;transition:opacity 0.15s"
|
|
508
|
+
[title]="(live || isLive) ? l.liveActiveTooltip : l.liveTooltip"
|
|
509
|
+
>
|
|
510
|
+
@if (live || isLive) {
|
|
511
|
+
<span
|
|
512
|
+
[style.width.px]="liveSize.dot"
|
|
513
|
+
[style.height.px]="liveSize.dot"
|
|
514
|
+
[style.background-color]="theme.liveDotColor"
|
|
515
|
+
style="border-radius:50%;display:inline-block;flex-shrink:0"
|
|
516
|
+
></span>
|
|
517
|
+
}
|
|
518
|
+
{{ (live || isLive) ? l.liveActiveLabel : l.liveLabel }}
|
|
519
|
+
</button>
|
|
520
|
+
@if (!isNormalSpeed && !live) {
|
|
521
|
+
<button
|
|
522
|
+
(click)="resetSpeed.emit()"
|
|
523
|
+
[style.color]="theme.buttonActiveColor"
|
|
524
|
+
[style.border-color]="theme.buttonActiveColor + '44'"
|
|
525
|
+
[style.width.px]="liveSize.width"
|
|
526
|
+
[style.min-width.px]="liveSize.width"
|
|
527
|
+
[style.height.px]="liveSize.height"
|
|
528
|
+
style="background:none;border:1px solid;cursor:pointer;font-size:11px;border-radius:4px;display:flex;align-items:center;justify-content:center;padding:0;font-family:system-ui,-apple-system,sans-serif;transition:background-color 0.15s"
|
|
529
|
+
[title]="l.resetSpeedTooltip"
|
|
530
|
+
>{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}</button>
|
|
531
|
+
}
|
|
532
|
+
</div>
|
|
533
|
+
}
|
|
406
534
|
@if (hasSwimLaneToggle) {
|
|
407
535
|
<button
|
|
408
536
|
(click)="toggleSwimLanes.emit()"
|
|
@@ -469,6 +597,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
469
597
|
type: Input
|
|
470
598
|
}], labels: [{
|
|
471
599
|
type: Input
|
|
600
|
+
}], liveButtonSize: [{
|
|
601
|
+
type: Input
|
|
602
|
+
}], liveButtonPosition: [{
|
|
603
|
+
type: Input
|
|
604
|
+
}], live: [{
|
|
605
|
+
type: Input
|
|
472
606
|
}], dateTimeClick: [{
|
|
473
607
|
type: Output
|
|
474
608
|
}], playPause: [{
|
|
@@ -511,6 +645,10 @@ class TimelineCanvasComponent {
|
|
|
511
645
|
months;
|
|
512
646
|
swimLanes;
|
|
513
647
|
showSwimLanes;
|
|
648
|
+
/** When true, needle scrub is disabled (left-click becomes pan). Zoom and pan remain active. */
|
|
649
|
+
disableNeedleDrag = false;
|
|
650
|
+
/** @see TimelineBaseProps.invertScrollZoom */
|
|
651
|
+
invertScrollZoom = false;
|
|
514
652
|
timeChange = new EventEmitter();
|
|
515
653
|
dragStart = new EventEmitter();
|
|
516
654
|
dragEnd = new EventEmitter();
|
|
@@ -539,6 +677,8 @@ class TimelineCanvasComponent {
|
|
|
539
677
|
rangeAnchorMs = 0;
|
|
540
678
|
rangeAnchorX = 0;
|
|
541
679
|
rangeSelection = null;
|
|
680
|
+
// Ghost needle (hover preview)
|
|
681
|
+
hoverMs = null;
|
|
542
682
|
// Touch state
|
|
543
683
|
touchMode = 'none';
|
|
544
684
|
touchX = 0;
|
|
@@ -728,6 +868,7 @@ class TimelineCanvasComponent {
|
|
|
728
868
|
scrollTop: this.scrollTop,
|
|
729
869
|
reorderState: this.reorderState,
|
|
730
870
|
rangeSelection: this.rangeSelection,
|
|
871
|
+
hoverMs: this.hoverMs,
|
|
731
872
|
});
|
|
732
873
|
if (clampedScrollTop !== this.scrollTop) {
|
|
733
874
|
this.scrollTop = clampedScrollTop;
|
|
@@ -829,6 +970,12 @@ class TimelineCanvasComponent {
|
|
|
829
970
|
}
|
|
830
971
|
}
|
|
831
972
|
if (e.button === 0) {
|
|
973
|
+
if (this.disableNeedleDrag) {
|
|
974
|
+
// In live mode left-click becomes a pan; needle scrub is disabled.
|
|
975
|
+
this.mouseMode = 'slide';
|
|
976
|
+
this.mouseX = e.clientX;
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
832
979
|
const needleX = ((this.curMs - this.startMs) / (this.endMs - this.startMs)) * rect.width;
|
|
833
980
|
const nearNeedle = Math.abs(x - needleX) <= 10;
|
|
834
981
|
const inTickArea = y >= rect.height - TICK_AREA_HEIGHT;
|
|
@@ -986,9 +1133,21 @@ class TimelineCanvasComponent {
|
|
|
986
1133
|
const selEnd = Math.max(sel.startMs, sel.endMs);
|
|
987
1134
|
this.startMs = selStart;
|
|
988
1135
|
this.endMs = selEnd;
|
|
1136
|
+
// If the needle is outside the selected range, clamp it to the nearest
|
|
1137
|
+
// edge so the clock-tick auto-scroll doesn't immediately override the zoom.
|
|
1138
|
+
const clampedMs = Math.max(selStart, Math.min(selEnd, this.curMs));
|
|
1139
|
+
const needleMoved = clampedMs !== this.curMs;
|
|
1140
|
+
if (needleMoved) {
|
|
1141
|
+
this.curMs = clampedMs;
|
|
1142
|
+
}
|
|
989
1143
|
const startJd = Cesium.JulianDate.fromDate(new Date(selStart));
|
|
990
1144
|
const endJd = Cesium.JulianDate.fromDate(new Date(selEnd));
|
|
991
|
-
this.ngZone.run(() =>
|
|
1145
|
+
this.ngZone.run(() => {
|
|
1146
|
+
this.rangeSelect.emit({ start: startJd, end: endJd });
|
|
1147
|
+
if (needleMoved) {
|
|
1148
|
+
this.timeChange.emit(Cesium.JulianDate.fromDate(new Date(clampedMs)));
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
992
1151
|
}
|
|
993
1152
|
this.mouseMode = 'none';
|
|
994
1153
|
const canvas = this.canvasRef?.nativeElement;
|
|
@@ -1005,14 +1164,25 @@ class TimelineCanvasComponent {
|
|
|
1005
1164
|
this.ngZone.run(() => this.dragEnd.emit());
|
|
1006
1165
|
}
|
|
1007
1166
|
onCanvasMouseMove(e) {
|
|
1008
|
-
if (this.mouseMode !== 'none')
|
|
1009
|
-
return;
|
|
1010
1167
|
const canvas = this.canvasRef.nativeElement;
|
|
1011
1168
|
const rect = canvas.getBoundingClientRect();
|
|
1012
1169
|
const x = e.clientX - rect.left;
|
|
1013
1170
|
const y = e.clientY - rect.top;
|
|
1171
|
+
// Update ghost needle while idle
|
|
1172
|
+
if (this.mouseMode === 'none') {
|
|
1173
|
+
if (!this.disableNeedleDrag) {
|
|
1174
|
+
this.hoverMs = this.startMs + (Math.max(0, Math.min(rect.width, x)) / rect.width) * (this.endMs - this.startMs);
|
|
1175
|
+
}
|
|
1176
|
+
else if (this.hoverMs !== null) {
|
|
1177
|
+
this.hoverMs = null;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
this.hoverMs = null;
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1014
1184
|
const needleX = ((this.curMs - this.startMs) / (this.endMs - this.startMs)) * rect.width;
|
|
1015
|
-
const nearNeedle = Math.abs(x - needleX) <= 10;
|
|
1185
|
+
const nearNeedle = !this.disableNeedleDrag && Math.abs(x - needleX) <= 10;
|
|
1016
1186
|
if (this.isInSwimLaneRegion(y, rect.height)) {
|
|
1017
1187
|
const hit = this.hitTestSwimLane(x, y, rect.width, rect.height);
|
|
1018
1188
|
const prev = this.hoveredItem;
|
|
@@ -1021,14 +1191,12 @@ class TimelineCanvasComponent {
|
|
|
1021
1191
|
if (!prev || prev.item.id !== hit.item.id || prev.lane.id !== hit.lane.id) {
|
|
1022
1192
|
this.hoveredItem = hit;
|
|
1023
1193
|
this.ngZone.run(() => this.swimLaneItemHover.emit({ laneId: hit.lane.id, item: hit.item, originalEvent: e }));
|
|
1024
|
-
this.draw();
|
|
1025
1194
|
}
|
|
1026
1195
|
}
|
|
1027
1196
|
else {
|
|
1028
1197
|
if (prev) {
|
|
1029
1198
|
this.hoveredItem = null;
|
|
1030
1199
|
this.ngZone.run(() => this.swimLaneItemHover.emit(null));
|
|
1031
|
-
this.draw();
|
|
1032
1200
|
}
|
|
1033
1201
|
if (nearNeedle) {
|
|
1034
1202
|
canvas.style.cursor = 'grab';
|
|
@@ -1038,22 +1206,23 @@ class TimelineCanvasComponent {
|
|
|
1038
1206
|
canvas.style.cursor = labelLane && this.swimLaneReorder.observed ? 'grab' : 'default';
|
|
1039
1207
|
}
|
|
1040
1208
|
}
|
|
1209
|
+
this.draw();
|
|
1041
1210
|
return;
|
|
1042
1211
|
}
|
|
1043
1212
|
if (this.hoveredItem) {
|
|
1044
1213
|
this.hoveredItem = null;
|
|
1045
1214
|
this.ngZone.run(() => this.swimLaneItemHover.emit(null));
|
|
1046
|
-
this.draw();
|
|
1047
1215
|
}
|
|
1048
1216
|
if (nearNeedle) {
|
|
1049
1217
|
canvas.style.cursor = 'grab';
|
|
1050
1218
|
}
|
|
1051
|
-
else if (y >= rect.height - TICK_AREA_HEIGHT) {
|
|
1219
|
+
else if (!this.disableNeedleDrag && y >= rect.height - TICK_AREA_HEIGHT) {
|
|
1052
1220
|
canvas.style.cursor = 'crosshair';
|
|
1053
1221
|
}
|
|
1054
1222
|
else {
|
|
1055
1223
|
canvas.style.cursor = 'default';
|
|
1056
1224
|
}
|
|
1225
|
+
this.draw();
|
|
1057
1226
|
}
|
|
1058
1227
|
onCanvasClick(e) {
|
|
1059
1228
|
const elapsed = performance.now() - this.swimLaneDownTime;
|
|
@@ -1093,11 +1262,12 @@ class TimelineCanvasComponent {
|
|
|
1093
1262
|
if (this.hoveredItem) {
|
|
1094
1263
|
this.hoveredItem = null;
|
|
1095
1264
|
this.ngZone.run(() => this.swimLaneItemHover.emit(null));
|
|
1096
|
-
this.draw();
|
|
1097
1265
|
}
|
|
1266
|
+
this.hoverMs = null;
|
|
1098
1267
|
const canvas = this.canvasRef?.nativeElement;
|
|
1099
1268
|
if (this.mouseMode === 'none' && canvas)
|
|
1100
1269
|
canvas.style.cursor = 'default';
|
|
1270
|
+
this.draw();
|
|
1101
1271
|
}
|
|
1102
1272
|
// ── Wheel handler ──────────────────────────────────────────────────────
|
|
1103
1273
|
onWheel(e) {
|
|
@@ -1118,7 +1288,7 @@ class TimelineCanvasComponent {
|
|
|
1118
1288
|
return;
|
|
1119
1289
|
}
|
|
1120
1290
|
}
|
|
1121
|
-
this.zoomFrom(Math.pow(1.05, e.deltaY > 0 ? -1 : 1));
|
|
1291
|
+
this.zoomFrom(Math.pow(1.05, e.deltaY > 0 === this.invertScrollZoom ? -1 : 1));
|
|
1122
1292
|
}
|
|
1123
1293
|
// ── Touch handlers ─────────────────────────────────────────────────────
|
|
1124
1294
|
onTouchStart(e) {
|
|
@@ -1130,15 +1300,22 @@ class TimelineCanvasComponent {
|
|
|
1130
1300
|
const cx = Math.max(0, Math.min(rect.width, x));
|
|
1131
1301
|
const ms = this.startMs + (cx / rect.width) * (this.endMs - this.startMs);
|
|
1132
1302
|
this.prePinchCurMs = this.curMs;
|
|
1133
|
-
this.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
this.
|
|
1140
|
-
this.
|
|
1141
|
-
|
|
1303
|
+
if (this.disableNeedleDrag) {
|
|
1304
|
+
// In live mode single-finger becomes a pan, not a scrub.
|
|
1305
|
+
this.touchMode = 'slide';
|
|
1306
|
+
this.touchX = e.touches[0].clientX;
|
|
1307
|
+
}
|
|
1308
|
+
else {
|
|
1309
|
+
this.touchMode = 'scrub';
|
|
1310
|
+
this.touchX = e.touches[0].clientX;
|
|
1311
|
+
this.scrubClientX = e.touches[0].clientX;
|
|
1312
|
+
this.curMs = ms;
|
|
1313
|
+
this.draw();
|
|
1314
|
+
this.ngZone.run(() => {
|
|
1315
|
+
this.dragStart.emit();
|
|
1316
|
+
this.timeChange.emit(Cesium.JulianDate.fromDate(new Date(ms)));
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1142
1319
|
}
|
|
1143
1320
|
else if (e.touches.length >= 2) {
|
|
1144
1321
|
// If we were scrubbing, undo the needle move — pinch-zoom should not
|
|
@@ -1214,7 +1391,7 @@ class TimelineCanvasComponent {
|
|
|
1214
1391
|
}
|
|
1215
1392
|
}
|
|
1216
1393
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: TimelineCanvasComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
1217
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: TimelineCanvasComponent, isStandalone: true, selector: "ct-timeline-canvas", inputs: { currentTime: "currentTime", defaultStartMs: "defaultStartMs", defaultEndMs: "defaultEndMs", theme: "theme", maxTicks: "maxTicks", timezone: "timezone", dateTimeFormat: "dateTimeFormat", months: "months", swimLanes: "swimLanes", showSwimLanes: "showSwimLanes" }, outputs: { timeChange: "timeChange", dragStart: "dragStart", dragEnd: "dragEnd", swimLaneItemClick: "swimLaneItemClick", swimLaneItemHover: "swimLaneItemHover", swimLaneItemDoubleClick: "swimLaneItemDoubleClick", swimLaneItemContextMenu: "swimLaneItemContextMenu", swimLaneReorder: "swimLaneReorder", rangeSelect: "rangeSelect" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `<canvas #canvas
|
|
1394
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: TimelineCanvasComponent, isStandalone: true, selector: "ct-timeline-canvas", inputs: { currentTime: "currentTime", defaultStartMs: "defaultStartMs", defaultEndMs: "defaultEndMs", theme: "theme", maxTicks: "maxTicks", timezone: "timezone", dateTimeFormat: "dateTimeFormat", months: "months", swimLanes: "swimLanes", showSwimLanes: "showSwimLanes", disableNeedleDrag: "disableNeedleDrag", invertScrollZoom: "invertScrollZoom" }, outputs: { timeChange: "timeChange", dragStart: "dragStart", dragEnd: "dragEnd", swimLaneItemClick: "swimLaneItemClick", swimLaneItemHover: "swimLaneItemHover", swimLaneItemDoubleClick: "swimLaneItemDoubleClick", swimLaneItemContextMenu: "swimLaneItemContextMenu", swimLaneReorder: "swimLaneReorder", rangeSelect: "rangeSelect" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `<canvas #canvas
|
|
1218
1395
|
style="width:100%;flex:1;min-height:0;display:block;cursor:default"
|
|
1219
1396
|
(mousedown)="onCanvasMouseDown($event)"
|
|
1220
1397
|
(mousemove)="onCanvasMouseMove($event)"
|
|
@@ -1255,6 +1432,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1255
1432
|
type: Input
|
|
1256
1433
|
}], showSwimLanes: [{
|
|
1257
1434
|
type: Input
|
|
1435
|
+
}], disableNeedleDrag: [{
|
|
1436
|
+
type: Input
|
|
1437
|
+
}], invertScrollZoom: [{
|
|
1438
|
+
type: Input
|
|
1258
1439
|
}], timeChange: [{
|
|
1259
1440
|
type: Output
|
|
1260
1441
|
}], dragStart: [{
|
|
@@ -1306,6 +1487,13 @@ class TimelineComponent {
|
|
|
1306
1487
|
swimLaneTransition = 'animated';
|
|
1307
1488
|
/** Overrides for control-bar labels and tooltips (i18n / custom verbiage). */
|
|
1308
1489
|
labels;
|
|
1490
|
+
/** @see TimelineBaseProps.liveButtonSize */
|
|
1491
|
+
liveButtonSize;
|
|
1492
|
+
/** @see TimelineBaseProps.liveButtonPosition */
|
|
1493
|
+
liveButtonPosition;
|
|
1494
|
+
/** @see TimelineBaseProps.live */
|
|
1495
|
+
live = false;
|
|
1496
|
+
invertScrollZoom = false;
|
|
1309
1497
|
// ── Outputs ────────────────────────────────────────────────────────────
|
|
1310
1498
|
timeChange = new EventEmitter();
|
|
1311
1499
|
playPause = new EventEmitter();
|
|
@@ -1342,7 +1530,7 @@ class TimelineComponent {
|
|
|
1342
1530
|
return this.swimLanes != null && this.swimLanes.length > 0;
|
|
1343
1531
|
}
|
|
1344
1532
|
get isLive() {
|
|
1345
|
-
return Math.abs(Cesium.JulianDate.toDate(this.currentTimeState).getTime() - Date.now()) <
|
|
1533
|
+
return Math.abs(Cesium.JulianDate.toDate(this.currentTimeState).getTime() - Date.now()) < 2_000;
|
|
1346
1534
|
}
|
|
1347
1535
|
get isCollapsed() {
|
|
1348
1536
|
return this.hasSwimLanes && !this.swimLanesExpanded;
|
|
@@ -1393,7 +1581,7 @@ class TimelineComponent {
|
|
|
1393
1581
|
this.cleanupClockSync();
|
|
1394
1582
|
this.setupClockSync();
|
|
1395
1583
|
}
|
|
1396
|
-
if (changes['jumpToTime'] && this.jumpToTime) {
|
|
1584
|
+
if (changes['jumpToTime'] && this.jumpToTime && !this.live) {
|
|
1397
1585
|
const t = toJulianDate(this.jumpToTime);
|
|
1398
1586
|
this.handleTimeChange(t);
|
|
1399
1587
|
if (this.canvasComp) {
|
|
@@ -1547,7 +1735,7 @@ class TimelineComponent {
|
|
|
1547
1735
|
this.cdr.markForCheck();
|
|
1548
1736
|
}
|
|
1549
1737
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: TimelineComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
1550
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: TimelineComponent, isStandalone: true, selector: "ct-timeline", inputs: { startTime: "startTime", endTime: "endTime", currentTime: "currentTime", clock: "clock", height: "height", showControls: "showControls", showJumpToStart: "showJumpToStart", showJumpToEnd: "showJumpToEnd", enableDrag: "enableDrag", dateTimeFormat: "dateTimeFormat", jumpToTime: "jumpToTime", maxTicks: "maxTicks", ffSpeeds: "ffSpeeds", rwSpeeds: "rwSpeeds", theme: "theme", cssClass: "cssClass", timezone: "timezone", swimLanes: "swimLanes", showSwimLanes: "showSwimLanes", swimLaneTransition: "swimLaneTransition", labels: "labels" }, outputs: { timeChange: "timeChange", playPause: "playPause", multiplierChange: "multiplierChange", dateTimeClick: "dateTimeClick", showSwimLanesChange: "showSwimLanesChange", swimLaneItemClick: "swimLaneItemClick", swimLaneItemHover: "swimLaneItemHover", swimLaneItemDoubleClick: "swimLaneItemDoubleClick", swimLaneItemContextMenu: "swimLaneItemContextMenu", swimLaneReorder: "swimLaneReorder", rangeSelect: "rangeSelect" }, viewQueries: [{ propertyName: "canvasComp", first: true, predicate: TimelineCanvasComponent, descendants: true }, { propertyName: "controlsRef", first: true, predicate: ["controlsEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1738
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: TimelineComponent, isStandalone: true, selector: "ct-timeline", inputs: { startTime: "startTime", endTime: "endTime", currentTime: "currentTime", clock: "clock", height: "height", showControls: "showControls", showJumpToStart: "showJumpToStart", showJumpToEnd: "showJumpToEnd", enableDrag: "enableDrag", dateTimeFormat: "dateTimeFormat", jumpToTime: "jumpToTime", maxTicks: "maxTicks", ffSpeeds: "ffSpeeds", rwSpeeds: "rwSpeeds", theme: "theme", cssClass: "cssClass", timezone: "timezone", swimLanes: "swimLanes", showSwimLanes: "showSwimLanes", swimLaneTransition: "swimLaneTransition", labels: "labels", liveButtonSize: "liveButtonSize", liveButtonPosition: "liveButtonPosition", live: "live", invertScrollZoom: "invertScrollZoom" }, outputs: { timeChange: "timeChange", playPause: "playPause", multiplierChange: "multiplierChange", dateTimeClick: "dateTimeClick", showSwimLanesChange: "showSwimLanesChange", swimLaneItemClick: "swimLaneItemClick", swimLaneItemHover: "swimLaneItemHover", swimLaneItemDoubleClick: "swimLaneItemDoubleClick", swimLaneItemContextMenu: "swimLaneItemContextMenu", swimLaneReorder: "swimLaneReorder", rangeSelect: "rangeSelect" }, viewQueries: [{ propertyName: "canvasComp", first: true, predicate: TimelineCanvasComponent, descendants: true }, { propertyName: "controlsRef", first: true, predicate: ["controlsEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1551
1739
|
<div
|
|
1552
1740
|
[class]="cssClass"
|
|
1553
1741
|
[style.width]="'100%'"
|
|
@@ -1583,11 +1771,14 @@ class TimelineComponent {
|
|
|
1583
1771
|
(dateTimeClick)="dateTimeClick.emit()"
|
|
1584
1772
|
(toggleSwimLanes)="handleToggleSwimLanes()"
|
|
1585
1773
|
[labels]="labels"
|
|
1774
|
+
[liveButtonSize]="liveButtonSize"
|
|
1775
|
+
[liveButtonPosition]="liveButtonPosition"
|
|
1776
|
+
[live]="live"
|
|
1586
1777
|
/>
|
|
1587
1778
|
</div>
|
|
1588
1779
|
}
|
|
1589
1780
|
|
|
1590
|
-
@if (enableDrag !== false) {
|
|
1781
|
+
@if (enableDrag !== false || live) {
|
|
1591
1782
|
<ct-timeline-canvas
|
|
1592
1783
|
[currentTime]="currentTimeState"
|
|
1593
1784
|
[defaultStartMs]="defaultStartMs"
|
|
@@ -1599,6 +1790,8 @@ class TimelineComponent {
|
|
|
1599
1790
|
[months]="labels?.months"
|
|
1600
1791
|
[swimLanes]="swimLanes"
|
|
1601
1792
|
[showSwimLanes]="swimLanesExpanded"
|
|
1793
|
+
[disableNeedleDrag]="live"
|
|
1794
|
+
[invertScrollZoom]="invertScrollZoom"
|
|
1602
1795
|
(timeChange)="handleTimeChange($event)"
|
|
1603
1796
|
(dragStart)="isDragging = true"
|
|
1604
1797
|
(dragEnd)="isDragging = false"
|
|
@@ -1611,7 +1804,7 @@ class TimelineComponent {
|
|
|
1611
1804
|
/>
|
|
1612
1805
|
}
|
|
1613
1806
|
</div>
|
|
1614
|
-
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: TimelineControlsComponent, selector: "ct-timeline-controls", inputs: ["currentTime", "isPlaying", "multiplier", "dateTimeFormat", "timezone", "isLive", "hasStartTime", "hasEndTime", "showJumpToStart", "showJumpToEnd", "theme", "swimLanesVisible", "labels"], outputs: ["dateTimeClick", "playPause", "jumpToStart", "rewind", "fastForward", "jumpToEnd", "jumpToLive", "resetSpeed", "toggleSwimLanes"] }, { kind: "component", type: TimelineCanvasComponent, selector: "ct-timeline-canvas", inputs: ["currentTime", "defaultStartMs", "defaultEndMs", "theme", "maxTicks", "timezone", "dateTimeFormat", "months", "swimLanes", "showSwimLanes"], outputs: ["timeChange", "dragStart", "dragEnd", "swimLaneItemClick", "swimLaneItemHover", "swimLaneItemDoubleClick", "swimLaneItemContextMenu", "swimLaneReorder", "rangeSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1807
|
+
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: TimelineControlsComponent, selector: "ct-timeline-controls", inputs: ["currentTime", "isPlaying", "multiplier", "dateTimeFormat", "timezone", "isLive", "hasStartTime", "hasEndTime", "showJumpToStart", "showJumpToEnd", "theme", "swimLanesVisible", "labels", "liveButtonSize", "liveButtonPosition", "live"], outputs: ["dateTimeClick", "playPause", "jumpToStart", "rewind", "fastForward", "jumpToEnd", "jumpToLive", "resetSpeed", "toggleSwimLanes"] }, { kind: "component", type: TimelineCanvasComponent, selector: "ct-timeline-canvas", inputs: ["currentTime", "defaultStartMs", "defaultEndMs", "theme", "maxTicks", "timezone", "dateTimeFormat", "months", "swimLanes", "showSwimLanes", "disableNeedleDrag", "invertScrollZoom"], outputs: ["timeChange", "dragStart", "dragEnd", "swimLaneItemClick", "swimLaneItemHover", "swimLaneItemDoubleClick", "swimLaneItemContextMenu", "swimLaneReorder", "rangeSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1615
1808
|
}
|
|
1616
1809
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: TimelineComponent, decorators: [{
|
|
1617
1810
|
type: Component,
|
|
@@ -1651,11 +1844,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1651
1844
|
(dateTimeClick)="dateTimeClick.emit()"
|
|
1652
1845
|
(toggleSwimLanes)="handleToggleSwimLanes()"
|
|
1653
1846
|
[labels]="labels"
|
|
1847
|
+
[liveButtonSize]="liveButtonSize"
|
|
1848
|
+
[liveButtonPosition]="liveButtonPosition"
|
|
1849
|
+
[live]="live"
|
|
1654
1850
|
/>
|
|
1655
1851
|
</div>
|
|
1656
1852
|
}
|
|
1657
1853
|
|
|
1658
|
-
@if (enableDrag !== false) {
|
|
1854
|
+
@if (enableDrag !== false || live) {
|
|
1659
1855
|
<ct-timeline-canvas
|
|
1660
1856
|
[currentTime]="currentTimeState"
|
|
1661
1857
|
[defaultStartMs]="defaultStartMs"
|
|
@@ -1667,6 +1863,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1667
1863
|
[months]="labels?.months"
|
|
1668
1864
|
[swimLanes]="swimLanes"
|
|
1669
1865
|
[showSwimLanes]="swimLanesExpanded"
|
|
1866
|
+
[disableNeedleDrag]="live"
|
|
1867
|
+
[invertScrollZoom]="invertScrollZoom"
|
|
1670
1868
|
(timeChange)="handleTimeChange($event)"
|
|
1671
1869
|
(dragStart)="isDragging = true"
|
|
1672
1870
|
(dragEnd)="isDragging = false"
|
|
@@ -1722,6 +1920,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1722
1920
|
type: Input
|
|
1723
1921
|
}], labels: [{
|
|
1724
1922
|
type: Input
|
|
1923
|
+
}], liveButtonSize: [{
|
|
1924
|
+
type: Input
|
|
1925
|
+
}], liveButtonPosition: [{
|
|
1926
|
+
type: Input
|
|
1927
|
+
}], live: [{
|
|
1928
|
+
type: Input
|
|
1929
|
+
}], invertScrollZoom: [{
|
|
1930
|
+
type: Input
|
|
1725
1931
|
}], timeChange: [{
|
|
1726
1932
|
type: Output
|
|
1727
1933
|
}], playPause: [{
|