@kteneyck/cesium-timeline-angular 0.9.0 → 0.11.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); }
|
|
@@ -57,8 +67,8 @@ class TimelineControlsComponent {
|
|
|
57
67
|
ngOnDestroy() {
|
|
58
68
|
this.ro?.disconnect();
|
|
59
69
|
}
|
|
60
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
61
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimelineControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", 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()"
|
|
@@ -250,7 +319,7 @@ class TimelineControlsComponent {
|
|
|
250
319
|
</div>
|
|
251
320
|
`, isInline: true, styles: [":host{display:block}.ct-btn{background:none;border:1px solid transparent;cursor:pointer;font-size:16px;padding:0;display:flex;align-items:center;justify-content:center;min-width:32px;width:32px;height:32px;border-radius:4px;transition:background-color .15s,color .15s;font-family:system-ui,-apple-system,sans-serif;flex-shrink:0;line-height:1}.ct-btn:hover{background-color:#ffffff1a}.ct-btn-wide{width:64px;min-width:64px;gap:3px}.ct-btn-play{font-size:18px;width:40px;min-width:40px;height:40px;border-radius:50%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
252
321
|
}
|
|
253
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
322
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimelineControlsComponent, decorators: [{
|
|
254
323
|
type: Component,
|
|
255
324
|
args: [{ selector: 'ct-timeline-controls', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
256
325
|
<div
|
|
@@ -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;
|
|
@@ -832,6 +973,22 @@ class TimelineCanvasComponent {
|
|
|
832
973
|
const needleX = ((this.curMs - this.startMs) / (this.endMs - this.startMs)) * rect.width;
|
|
833
974
|
const nearNeedle = Math.abs(x - needleX) <= 10;
|
|
834
975
|
const inTickArea = y >= rect.height - TICK_AREA_HEIGHT;
|
|
976
|
+
if (this.disableNeedleDrag) {
|
|
977
|
+
if (!nearNeedle && inTickArea) {
|
|
978
|
+
// In live mode: allow range-select zoom in the tick area; needle scrub is still disabled.
|
|
979
|
+
this.mouseMode = 'rangeSelectPending';
|
|
980
|
+
this.rangeAnchorX = x;
|
|
981
|
+
this.rangeAnchorMs = this.startMs + (x / rect.width) * (this.endMs - this.startMs);
|
|
982
|
+
canvas.style.cursor = 'crosshair';
|
|
983
|
+
this.ngZone.run(() => this.dragStart.emit());
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
986
|
+
// Outside tick area — left-click becomes a pan.
|
|
987
|
+
this.mouseMode = 'slide';
|
|
988
|
+
this.mouseX = e.clientX;
|
|
989
|
+
}
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
835
992
|
if (!nearNeedle && inTickArea) {
|
|
836
993
|
this.mouseMode = 'rangeSelectPending';
|
|
837
994
|
this.rangeAnchorX = x;
|
|
@@ -982,13 +1139,38 @@ class TimelineCanvasComponent {
|
|
|
982
1139
|
const sel = this.rangeSelection;
|
|
983
1140
|
this.rangeSelection = null;
|
|
984
1141
|
if (sel) {
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
this.
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1142
|
+
let selStart = Math.min(sel.startMs, sel.endMs);
|
|
1143
|
+
let selEnd = Math.max(sel.startMs, sel.endMs);
|
|
1144
|
+
if (this.disableNeedleDrag) {
|
|
1145
|
+
// In live mode: don't move the needle. Expand the selection to keep
|
|
1146
|
+
// the needle (current time) visible on screen.
|
|
1147
|
+
selStart = Math.min(selStart, this.curMs);
|
|
1148
|
+
selEnd = Math.max(selEnd, this.curMs);
|
|
1149
|
+
this.startMs = selStart;
|
|
1150
|
+
this.endMs = selEnd;
|
|
1151
|
+
const startJd = Cesium.JulianDate.fromDate(new Date(selStart));
|
|
1152
|
+
const endJd = Cesium.JulianDate.fromDate(new Date(selEnd));
|
|
1153
|
+
this.ngZone.run(() => this.rangeSelect.emit({ start: startJd, end: endJd }));
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
this.startMs = selStart;
|
|
1157
|
+
this.endMs = selEnd;
|
|
1158
|
+
// If the needle is outside the selected range, clamp it to the nearest
|
|
1159
|
+
// edge so the clock-tick auto-scroll doesn't immediately override the zoom.
|
|
1160
|
+
const clampedMs = Math.max(selStart, Math.min(selEnd, this.curMs));
|
|
1161
|
+
const needleMoved = clampedMs !== this.curMs;
|
|
1162
|
+
if (needleMoved) {
|
|
1163
|
+
this.curMs = clampedMs;
|
|
1164
|
+
}
|
|
1165
|
+
const startJd = Cesium.JulianDate.fromDate(new Date(selStart));
|
|
1166
|
+
const endJd = Cesium.JulianDate.fromDate(new Date(selEnd));
|
|
1167
|
+
this.ngZone.run(() => {
|
|
1168
|
+
this.rangeSelect.emit({ start: startJd, end: endJd });
|
|
1169
|
+
if (needleMoved) {
|
|
1170
|
+
this.timeChange.emit(Cesium.JulianDate.fromDate(new Date(clampedMs)));
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
992
1174
|
}
|
|
993
1175
|
this.mouseMode = 'none';
|
|
994
1176
|
const canvas = this.canvasRef?.nativeElement;
|
|
@@ -1005,14 +1187,25 @@ class TimelineCanvasComponent {
|
|
|
1005
1187
|
this.ngZone.run(() => this.dragEnd.emit());
|
|
1006
1188
|
}
|
|
1007
1189
|
onCanvasMouseMove(e) {
|
|
1008
|
-
if (this.mouseMode !== 'none')
|
|
1009
|
-
return;
|
|
1010
1190
|
const canvas = this.canvasRef.nativeElement;
|
|
1011
1191
|
const rect = canvas.getBoundingClientRect();
|
|
1012
1192
|
const x = e.clientX - rect.left;
|
|
1013
1193
|
const y = e.clientY - rect.top;
|
|
1194
|
+
// Update ghost needle while idle
|
|
1195
|
+
if (this.mouseMode === 'none') {
|
|
1196
|
+
if (!this.disableNeedleDrag) {
|
|
1197
|
+
this.hoverMs = this.startMs + (Math.max(0, Math.min(rect.width, x)) / rect.width) * (this.endMs - this.startMs);
|
|
1198
|
+
}
|
|
1199
|
+
else if (this.hoverMs !== null) {
|
|
1200
|
+
this.hoverMs = null;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
else {
|
|
1204
|
+
this.hoverMs = null;
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1014
1207
|
const needleX = ((this.curMs - this.startMs) / (this.endMs - this.startMs)) * rect.width;
|
|
1015
|
-
const nearNeedle = Math.abs(x - needleX) <= 10;
|
|
1208
|
+
const nearNeedle = !this.disableNeedleDrag && Math.abs(x - needleX) <= 10;
|
|
1016
1209
|
if (this.isInSwimLaneRegion(y, rect.height)) {
|
|
1017
1210
|
const hit = this.hitTestSwimLane(x, y, rect.width, rect.height);
|
|
1018
1211
|
const prev = this.hoveredItem;
|
|
@@ -1021,14 +1214,12 @@ class TimelineCanvasComponent {
|
|
|
1021
1214
|
if (!prev || prev.item.id !== hit.item.id || prev.lane.id !== hit.lane.id) {
|
|
1022
1215
|
this.hoveredItem = hit;
|
|
1023
1216
|
this.ngZone.run(() => this.swimLaneItemHover.emit({ laneId: hit.lane.id, item: hit.item, originalEvent: e }));
|
|
1024
|
-
this.draw();
|
|
1025
1217
|
}
|
|
1026
1218
|
}
|
|
1027
1219
|
else {
|
|
1028
1220
|
if (prev) {
|
|
1029
1221
|
this.hoveredItem = null;
|
|
1030
1222
|
this.ngZone.run(() => this.swimLaneItemHover.emit(null));
|
|
1031
|
-
this.draw();
|
|
1032
1223
|
}
|
|
1033
1224
|
if (nearNeedle) {
|
|
1034
1225
|
canvas.style.cursor = 'grab';
|
|
@@ -1038,12 +1229,12 @@ class TimelineCanvasComponent {
|
|
|
1038
1229
|
canvas.style.cursor = labelLane && this.swimLaneReorder.observed ? 'grab' : 'default';
|
|
1039
1230
|
}
|
|
1040
1231
|
}
|
|
1232
|
+
this.draw();
|
|
1041
1233
|
return;
|
|
1042
1234
|
}
|
|
1043
1235
|
if (this.hoveredItem) {
|
|
1044
1236
|
this.hoveredItem = null;
|
|
1045
1237
|
this.ngZone.run(() => this.swimLaneItemHover.emit(null));
|
|
1046
|
-
this.draw();
|
|
1047
1238
|
}
|
|
1048
1239
|
if (nearNeedle) {
|
|
1049
1240
|
canvas.style.cursor = 'grab';
|
|
@@ -1054,6 +1245,7 @@ class TimelineCanvasComponent {
|
|
|
1054
1245
|
else {
|
|
1055
1246
|
canvas.style.cursor = 'default';
|
|
1056
1247
|
}
|
|
1248
|
+
this.draw();
|
|
1057
1249
|
}
|
|
1058
1250
|
onCanvasClick(e) {
|
|
1059
1251
|
const elapsed = performance.now() - this.swimLaneDownTime;
|
|
@@ -1093,11 +1285,12 @@ class TimelineCanvasComponent {
|
|
|
1093
1285
|
if (this.hoveredItem) {
|
|
1094
1286
|
this.hoveredItem = null;
|
|
1095
1287
|
this.ngZone.run(() => this.swimLaneItemHover.emit(null));
|
|
1096
|
-
this.draw();
|
|
1097
1288
|
}
|
|
1289
|
+
this.hoverMs = null;
|
|
1098
1290
|
const canvas = this.canvasRef?.nativeElement;
|
|
1099
1291
|
if (this.mouseMode === 'none' && canvas)
|
|
1100
1292
|
canvas.style.cursor = 'default';
|
|
1293
|
+
this.draw();
|
|
1101
1294
|
}
|
|
1102
1295
|
// ── Wheel handler ──────────────────────────────────────────────────────
|
|
1103
1296
|
onWheel(e) {
|
|
@@ -1118,7 +1311,7 @@ class TimelineCanvasComponent {
|
|
|
1118
1311
|
return;
|
|
1119
1312
|
}
|
|
1120
1313
|
}
|
|
1121
|
-
this.zoomFrom(Math.pow(1.05, e.deltaY > 0 ? -1 : 1));
|
|
1314
|
+
this.zoomFrom(Math.pow(1.05, e.deltaY > 0 === this.invertScrollZoom ? -1 : 1));
|
|
1122
1315
|
}
|
|
1123
1316
|
// ── Touch handlers ─────────────────────────────────────────────────────
|
|
1124
1317
|
onTouchStart(e) {
|
|
@@ -1130,15 +1323,22 @@ class TimelineCanvasComponent {
|
|
|
1130
1323
|
const cx = Math.max(0, Math.min(rect.width, x));
|
|
1131
1324
|
const ms = this.startMs + (cx / rect.width) * (this.endMs - this.startMs);
|
|
1132
1325
|
this.prePinchCurMs = this.curMs;
|
|
1133
|
-
this.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
this.
|
|
1140
|
-
this.
|
|
1141
|
-
|
|
1326
|
+
if (this.disableNeedleDrag) {
|
|
1327
|
+
// In live mode single-finger becomes a pan, not a scrub.
|
|
1328
|
+
this.touchMode = 'slide';
|
|
1329
|
+
this.touchX = e.touches[0].clientX;
|
|
1330
|
+
}
|
|
1331
|
+
else {
|
|
1332
|
+
this.touchMode = 'scrub';
|
|
1333
|
+
this.touchX = e.touches[0].clientX;
|
|
1334
|
+
this.scrubClientX = e.touches[0].clientX;
|
|
1335
|
+
this.curMs = ms;
|
|
1336
|
+
this.draw();
|
|
1337
|
+
this.ngZone.run(() => {
|
|
1338
|
+
this.dragStart.emit();
|
|
1339
|
+
this.timeChange.emit(Cesium.JulianDate.fromDate(new Date(ms)));
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1142
1342
|
}
|
|
1143
1343
|
else if (e.touches.length >= 2) {
|
|
1144
1344
|
// If we were scrubbing, undo the needle move — pinch-zoom should not
|
|
@@ -1213,8 +1413,8 @@ class TimelineCanvasComponent {
|
|
|
1213
1413
|
this.touchX = e.touches[0].clientX;
|
|
1214
1414
|
}
|
|
1215
1415
|
}
|
|
1216
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1217
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.
|
|
1416
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimelineCanvasComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
1417
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.17", 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
1418
|
style="width:100%;flex:1;min-height:0;display:block;cursor:default"
|
|
1219
1419
|
(mousedown)="onCanvasMouseDown($event)"
|
|
1220
1420
|
(mousemove)="onCanvasMouseMove($event)"
|
|
@@ -1224,7 +1424,7 @@ class TimelineCanvasComponent {
|
|
|
1224
1424
|
(mouseleave)="onCanvasMouseLeave()"
|
|
1225
1425
|
></canvas>`, isInline: true, styles: [":host{display:flex;flex:1;min-height:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1226
1426
|
}
|
|
1227
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1427
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimelineCanvasComponent, decorators: [{
|
|
1228
1428
|
type: Component,
|
|
1229
1429
|
args: [{ selector: 'ct-timeline-canvas', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `<canvas #canvas
|
|
1230
1430
|
style="width:100%;flex:1;min-height:0;display:block;cursor:default"
|
|
@@ -1255,6 +1455,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1255
1455
|
type: Input
|
|
1256
1456
|
}], showSwimLanes: [{
|
|
1257
1457
|
type: Input
|
|
1458
|
+
}], disableNeedleDrag: [{
|
|
1459
|
+
type: Input
|
|
1460
|
+
}], invertScrollZoom: [{
|
|
1461
|
+
type: Input
|
|
1258
1462
|
}], timeChange: [{
|
|
1259
1463
|
type: Output
|
|
1260
1464
|
}], dragStart: [{
|
|
@@ -1306,6 +1510,13 @@ class TimelineComponent {
|
|
|
1306
1510
|
swimLaneTransition = 'animated';
|
|
1307
1511
|
/** Overrides for control-bar labels and tooltips (i18n / custom verbiage). */
|
|
1308
1512
|
labels;
|
|
1513
|
+
/** @see TimelineBaseProps.liveButtonSize */
|
|
1514
|
+
liveButtonSize;
|
|
1515
|
+
/** @see TimelineBaseProps.liveButtonPosition */
|
|
1516
|
+
liveButtonPosition;
|
|
1517
|
+
/** @see TimelineBaseProps.live */
|
|
1518
|
+
live = false;
|
|
1519
|
+
invertScrollZoom = false;
|
|
1309
1520
|
// ── Outputs ────────────────────────────────────────────────────────────
|
|
1310
1521
|
timeChange = new EventEmitter();
|
|
1311
1522
|
playPause = new EventEmitter();
|
|
@@ -1342,7 +1553,7 @@ class TimelineComponent {
|
|
|
1342
1553
|
return this.swimLanes != null && this.swimLanes.length > 0;
|
|
1343
1554
|
}
|
|
1344
1555
|
get isLive() {
|
|
1345
|
-
return Math.abs(Cesium.JulianDate.toDate(this.currentTimeState).getTime() - Date.now()) <
|
|
1556
|
+
return Math.abs(Cesium.JulianDate.toDate(this.currentTimeState).getTime() - Date.now()) < 2_000;
|
|
1346
1557
|
}
|
|
1347
1558
|
get isCollapsed() {
|
|
1348
1559
|
return this.hasSwimLanes && !this.swimLanesExpanded;
|
|
@@ -1393,7 +1604,7 @@ class TimelineComponent {
|
|
|
1393
1604
|
this.cleanupClockSync();
|
|
1394
1605
|
this.setupClockSync();
|
|
1395
1606
|
}
|
|
1396
|
-
if (changes['jumpToTime'] && this.jumpToTime) {
|
|
1607
|
+
if (changes['jumpToTime'] && this.jumpToTime && !this.live) {
|
|
1397
1608
|
const t = toJulianDate(this.jumpToTime);
|
|
1398
1609
|
this.handleTimeChange(t);
|
|
1399
1610
|
if (this.canvasComp) {
|
|
@@ -1403,6 +1614,20 @@ class TimelineComponent {
|
|
|
1403
1614
|
this.canvasComp.zoomTo(newMs - span / 2, newMs + span / 2);
|
|
1404
1615
|
}
|
|
1405
1616
|
}
|
|
1617
|
+
if ((changes['startTime'] && !changes['startTime'].firstChange) ||
|
|
1618
|
+
(changes['endTime'] && !changes['endTime'].firstChange)) {
|
|
1619
|
+
const now = Date.now();
|
|
1620
|
+
this.defaultStartMs = this.startTime
|
|
1621
|
+
? Cesium.JulianDate.toDate(toJulianDate(this.startTime)).getTime()
|
|
1622
|
+
: now - 12 * 3600 * 1000;
|
|
1623
|
+
this.defaultEndMs = this.endTime
|
|
1624
|
+
? Cesium.JulianDate.toDate(toJulianDate(this.endTime)).getTime()
|
|
1625
|
+
: now + 12 * 3600 * 1000;
|
|
1626
|
+
if (this.startTime != null && this.endTime != null) {
|
|
1627
|
+
this.canvasComp?.zoomTo(this.defaultStartMs, this.defaultEndMs);
|
|
1628
|
+
}
|
|
1629
|
+
this.cdr.markForCheck();
|
|
1630
|
+
}
|
|
1406
1631
|
}
|
|
1407
1632
|
ngOnDestroy() {
|
|
1408
1633
|
this.cleanupClockSync();
|
|
@@ -1546,8 +1771,8 @@ class TimelineComponent {
|
|
|
1546
1771
|
this.multiplierChange.emit(m);
|
|
1547
1772
|
this.cdr.markForCheck();
|
|
1548
1773
|
}
|
|
1549
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1550
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1774
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimelineComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
|
|
1775
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", 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
1776
|
<div
|
|
1552
1777
|
[class]="cssClass"
|
|
1553
1778
|
[style.width]="'100%'"
|
|
@@ -1583,11 +1808,14 @@ class TimelineComponent {
|
|
|
1583
1808
|
(dateTimeClick)="dateTimeClick.emit()"
|
|
1584
1809
|
(toggleSwimLanes)="handleToggleSwimLanes()"
|
|
1585
1810
|
[labels]="labels"
|
|
1811
|
+
[liveButtonSize]="liveButtonSize"
|
|
1812
|
+
[liveButtonPosition]="liveButtonPosition"
|
|
1813
|
+
[live]="live"
|
|
1586
1814
|
/>
|
|
1587
1815
|
</div>
|
|
1588
1816
|
}
|
|
1589
1817
|
|
|
1590
|
-
@if (enableDrag !== false) {
|
|
1818
|
+
@if (enableDrag !== false || live) {
|
|
1591
1819
|
<ct-timeline-canvas
|
|
1592
1820
|
[currentTime]="currentTimeState"
|
|
1593
1821
|
[defaultStartMs]="defaultStartMs"
|
|
@@ -1599,6 +1827,8 @@ class TimelineComponent {
|
|
|
1599
1827
|
[months]="labels?.months"
|
|
1600
1828
|
[swimLanes]="swimLanes"
|
|
1601
1829
|
[showSwimLanes]="swimLanesExpanded"
|
|
1830
|
+
[disableNeedleDrag]="live"
|
|
1831
|
+
[invertScrollZoom]="invertScrollZoom"
|
|
1602
1832
|
(timeChange)="handleTimeChange($event)"
|
|
1603
1833
|
(dragStart)="isDragging = true"
|
|
1604
1834
|
(dragEnd)="isDragging = false"
|
|
@@ -1611,9 +1841,9 @@ class TimelineComponent {
|
|
|
1611
1841
|
/>
|
|
1612
1842
|
}
|
|
1613
1843
|
</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 });
|
|
1844
|
+
`, 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
1845
|
}
|
|
1616
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1846
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TimelineComponent, decorators: [{
|
|
1617
1847
|
type: Component,
|
|
1618
1848
|
args: [{ selector: 'ct-timeline', standalone: true, imports: [TimelineControlsComponent, TimelineCanvasComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
1619
1849
|
<div
|
|
@@ -1651,11 +1881,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1651
1881
|
(dateTimeClick)="dateTimeClick.emit()"
|
|
1652
1882
|
(toggleSwimLanes)="handleToggleSwimLanes()"
|
|
1653
1883
|
[labels]="labels"
|
|
1884
|
+
[liveButtonSize]="liveButtonSize"
|
|
1885
|
+
[liveButtonPosition]="liveButtonPosition"
|
|
1886
|
+
[live]="live"
|
|
1654
1887
|
/>
|
|
1655
1888
|
</div>
|
|
1656
1889
|
}
|
|
1657
1890
|
|
|
1658
|
-
@if (enableDrag !== false) {
|
|
1891
|
+
@if (enableDrag !== false || live) {
|
|
1659
1892
|
<ct-timeline-canvas
|
|
1660
1893
|
[currentTime]="currentTimeState"
|
|
1661
1894
|
[defaultStartMs]="defaultStartMs"
|
|
@@ -1667,6 +1900,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1667
1900
|
[months]="labels?.months"
|
|
1668
1901
|
[swimLanes]="swimLanes"
|
|
1669
1902
|
[showSwimLanes]="swimLanesExpanded"
|
|
1903
|
+
[disableNeedleDrag]="live"
|
|
1904
|
+
[invertScrollZoom]="invertScrollZoom"
|
|
1670
1905
|
(timeChange)="handleTimeChange($event)"
|
|
1671
1906
|
(dragStart)="isDragging = true"
|
|
1672
1907
|
(dragEnd)="isDragging = false"
|
|
@@ -1722,6 +1957,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1722
1957
|
type: Input
|
|
1723
1958
|
}], labels: [{
|
|
1724
1959
|
type: Input
|
|
1960
|
+
}], liveButtonSize: [{
|
|
1961
|
+
type: Input
|
|
1962
|
+
}], liveButtonPosition: [{
|
|
1963
|
+
type: Input
|
|
1964
|
+
}], live: [{
|
|
1965
|
+
type: Input
|
|
1966
|
+
}], invertScrollZoom: [{
|
|
1967
|
+
type: Input
|
|
1725
1968
|
}], timeChange: [{
|
|
1726
1969
|
type: Output
|
|
1727
1970
|
}], playPause: [{
|