@kteneyck/cesium-timeline-angular 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -2
- package/{dist/fesm2022 → fesm2022}/kteneyck-cesium-timeline-angular.mjs +39 -26
- package/fesm2022/kteneyck-cesium-timeline-angular.mjs.map +1 -0
- package/package.json +17 -23
- package/{dist/types → types}/kteneyck-cesium-timeline-angular.d.ts +10 -3
- package/dist/README.md +0 -869
- package/dist/fesm2022/kteneyck-cesium-timeline-angular.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ Angular components use standalone imports — no NgModule required. Selectors: `
|
|
|
123
123
|
- **Auto-scroll during playback** — visible window pans automatically when the needle reaches 10% from either edge.
|
|
124
124
|
- **Infinite scrolling window** — timeline is not clamped to `startTime`/`endTime`; the window can pan anywhere.
|
|
125
125
|
- **Adaptive tick labels** — label granularity adapts to zoom level: milliseconds → seconds → HH:MM:SS → HH:MM → Month Day → Month Year → Year. Tick dates are shown only when the visible window spans more than 24 hours.
|
|
126
|
-
- **
|
|
126
|
+
- **Configurable timezone** — tick labels and the datetime display can show any IANA timezone (e.g. `"UTC"`, `"America/New_York"`) or the browser's local time. A short abbreviation (e.g. `UTC`, `EST`, `PDT`) is displayed to the right of the date line whenever a non-local timezone is active.
|
|
127
127
|
- **Netflix/Hulu-style controls** — transport buttons (⏮ ◀◀ ▶/⏸ ▶▶ ⏭) always stay centered; speed badge and LIVE button in the left column never cause layout shift.
|
|
128
128
|
- **Conditional start/end buttons** — ⏮ and ⏭ are only rendered when `startTime` and `endTime` props are explicitly provided.
|
|
129
129
|
- **Speed cycling** — FF cycles through `ffSpeeds` (default `2×→4×→8×→16×→32×→1×`); RW cycles through `rwSpeeds` (default `−1×→−2×→−4×→−8×→−16×→−32×`). Both arrays are fully configurable.
|
|
@@ -135,6 +135,7 @@ Angular components use standalone imports — no NgModule required. Selectors: `
|
|
|
135
135
|
- **Max tick limit** — `maxTicks` prop prevents the canvas from becoming overloaded at wide zoom levels by coarsening the tick scale automatically.
|
|
136
136
|
- **Swim lanes** — display time intervals and instants as horizontal rows inside the canvas. Supports customizable styling, click/hover/double-click event hooks, drag-to-reorder, and vertical scrolling when lanes overflow.
|
|
137
137
|
- **Fully themeable** — 16 theme properties cover every color, size, and font setting, including swim lane item border defaults.
|
|
138
|
+
- **Localizable labels** — every control-bar label and tooltip is overridable via the `labels` prop; dynamic tooltips accept a `(multiplier: number) => string` callback. See [Labels & i18n](#labels--i18n).
|
|
138
139
|
- **Responsive** — fills container width; `ResizeObserver` redraws on resize.
|
|
139
140
|
|
|
140
141
|
---
|
|
@@ -159,6 +160,7 @@ Angular components use standalone imports — no NgModule required. Selectors: `
|
|
|
159
160
|
| `ffSpeeds` | `number[]` | `[2,4,8,16,32,1]` | Speed steps cycled by the ▶▶ button. Last entry wraps back to first. |
|
|
160
161
|
| `rwSpeeds` | `number[]` | `[1,2,4,8,16,32]` | Absolute-value speed steps cycled by the ◀◀ button (negated internally). |
|
|
161
162
|
| `dateTimeFormat` | `string` | `'MMM DD YYYY HH:mm:ss'` | Token-based format string for the controls datetime display |
|
|
163
|
+
| `timezone` | `string` | browser local | IANA timezone name (e.g. `'UTC'`, `'America/New_York'`) or `'local'` for the browser's timezone. Controls both tick labels and the datetime display. When set, a short abbreviation (e.g. `UTC`, `EST`) appears to the right of the date. |
|
|
162
164
|
| `onDateTimeClick` | `() => void` | — | Called when the user clicks the datetime display. Use to open your own date picker. |
|
|
163
165
|
| `jumpToTime` | `JulianDate \| Date` | — | Set to programmatically jump the timeline to a moment (pans canvas + sets time). |
|
|
164
166
|
| `theme` | `Partial<TimelineTheme>` | `defaultTheme` | Theme overrides (merged with defaults) |
|
|
@@ -172,6 +174,7 @@ Angular components use standalone imports — no NgModule required. Selectors: `
|
|
|
172
174
|
| `onSwimLaneItemHover` | `(info: SwimLaneEventInfo \| null) => void` | — | Fires when mouse enters/leaves a swim lane item |
|
|
173
175
|
| `onSwimLaneItemDoubleClick` | `(info: SwimLaneEventInfo) => void` | — | Fires when a swim lane item is double-clicked |
|
|
174
176
|
| `onSwimLaneReorder` | `(orderedIds: string[]) => void` | — | Fires when swim lanes are reordered via drag. Receives the new lane id order. |
|
|
177
|
+
| `labels` | `Partial<TimelineLabels>` | English defaults | Override any control-bar label or tooltip string. See [Labels & i18n](#labels--i18n). |
|
|
175
178
|
|
|
176
179
|
---
|
|
177
180
|
|
|
@@ -229,6 +232,60 @@ const theme = useMemo(() => {
|
|
|
229
232
|
|
|
230
233
|
---
|
|
231
234
|
|
|
235
|
+
## Timezone
|
|
236
|
+
|
|
237
|
+
By default the timeline displays all times in the **browser's local timezone**. Pass the `timezone` prop to use UTC or any [IANA timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) instead.
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
// UTC
|
|
241
|
+
<Timeline clock={viewer.clock} timezone="UTC" ... />
|
|
242
|
+
|
|
243
|
+
// A named IANA zone
|
|
244
|
+
<Timeline clock={viewer.clock} timezone="America/New_York" ... />
|
|
245
|
+
|
|
246
|
+
// Back to local (or simply omit the prop)
|
|
247
|
+
<Timeline clock={viewer.clock} timezone="local" ... />
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Both the **canvas tick labels** and the **control bar datetime display** update to reflect the chosen timezone. When a non-local timezone is active a short abbreviation (e.g. `UTC`, `EST`, `PDT`) is shown to the right of the date line. The abbreviation is DST-aware — it automatically switches between `EST` and `EDT`, `PST` and `PDT`, etc.
|
|
251
|
+
|
|
252
|
+
### `Timezones` constants
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import { Timezones } from '@kteneyck/cesium-timeline-react';
|
|
256
|
+
|
|
257
|
+
<Timeline timezone={Timezones.UTC} ... /> // "UTC"
|
|
258
|
+
<Timeline timezone={Timezones.LOCAL} ... /> // "local" (default behavior)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### `getTimezoneAbbr` utility
|
|
262
|
+
|
|
263
|
+
Returns the short abbreviation for a given date and timezone, or `null` for local.
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
import { getTimezoneAbbr } from '@kteneyck/cesium-timeline-react';
|
|
267
|
+
|
|
268
|
+
getTimezoneAbbr(new Date(), 'UTC'); // → "UTC"
|
|
269
|
+
getTimezoneAbbr(new Date(), 'America/Chicago'); // → "CDT" or "CST"
|
|
270
|
+
getTimezoneAbbr(new Date()); // → null (local)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### `formatDateTime` with timezone
|
|
274
|
+
|
|
275
|
+
The `formatDateTime` utility accepts an optional third argument:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
import { formatDateTime, DateTimeFormats } from '@kteneyck/cesium-timeline-react';
|
|
279
|
+
|
|
280
|
+
formatDateTime(new Date(), DateTimeFormats.ISO, 'UTC');
|
|
281
|
+
// → "2026-02-24 14:04:07" (always in UTC regardless of local browser timezone)
|
|
282
|
+
|
|
283
|
+
formatDateTime(new Date(), DateTimeFormats.DEFAULT, 'America/Los_Angeles');
|
|
284
|
+
// → "Feb 24 2026 06:04:07"
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
232
289
|
## DateTime Format
|
|
233
290
|
|
|
234
291
|
The `dateTimeFormat` prop controls the two-line datetime display in the control bar. It accepts a token-based format string.
|
|
@@ -357,6 +414,88 @@ const [pickerOpen, setPickerOpen] = useState(false);
|
|
|
357
414
|
|
|
358
415
|
---
|
|
359
416
|
|
|
417
|
+
## Labels & i18n
|
|
418
|
+
|
|
419
|
+
Every label and tooltip in the control bar is overridable via the `labels` prop. Pass a `Partial<TimelineLabels>` object — only the keys you provide are changed; everything else falls back to the English defaults.
|
|
420
|
+
|
|
421
|
+
### `TimelineLabels` reference
|
|
422
|
+
|
|
423
|
+
| Key | Default (English) | Notes |
|
|
424
|
+
|-----|-------------------|-------|
|
|
425
|
+
| `dateTimeClickTooltip` | `"Click to jump to a date/time"` | Tooltip on the datetime display when `onDateTimeClick` is wired up |
|
|
426
|
+
| `liveLabel` | `"LIVE"` | LIVE button text when not at live time |
|
|
427
|
+
| `liveActiveLabel` | `"● LIVE"` | LIVE button text when at live time |
|
|
428
|
+
| `liveTooltip` | `"Jump to live (now)"` | LIVE button tooltip when not at live time |
|
|
429
|
+
| `liveActiveTooltip` | `"Currently live"` | LIVE button tooltip when at live time |
|
|
430
|
+
| `resetSpeedTooltip` | `"Reset to 1× speed"` | Tooltip on the speed-reset badge |
|
|
431
|
+
| `jumpToStartTooltip` | `"Jump to start"` | ⏮ button tooltip when a start time is set |
|
|
432
|
+
| `noStartTimeTooltip` | `"No start time set"` | ⏮ button tooltip when no start time is set |
|
|
433
|
+
| `jumpToEndTooltip` | `"Jump to end"` | ⏭ button tooltip when an end time is set |
|
|
434
|
+
| `noEndTimeTooltip` | `"No end time set"` | ⏭ button tooltip when no end time is set |
|
|
435
|
+
| `rewindTooltip` | `"Rewind"` | ◀◀ button tooltip at normal speed |
|
|
436
|
+
| `rewindActiveTooltip` | `(n) => "Reverse N× — click to speed up…"` | ◀◀ button tooltip while rewinding — receives the current multiplier |
|
|
437
|
+
| `playTooltip` | `"Play"` | ▶ button tooltip when stopped |
|
|
438
|
+
| `playFromRewindTooltip` | `"Play (reset to 1×)"` | ▶ button tooltip when coming out of rewind |
|
|
439
|
+
| `pauseTooltip` | `"Pause"` | ▶ button tooltip when playing |
|
|
440
|
+
| `fastForwardTooltip` | `"Fast forward"` | ▶▶ button tooltip at normal speed |
|
|
441
|
+
| `fastForwardActiveTooltip` | `(n) => "N× speed — click to increase…"` | ▶▶ button tooltip while fast-forwarding — receives the current multiplier |
|
|
442
|
+
| `collapseSwimLanesTooltip` | `"Collapse swim lanes"` | Chevron button tooltip when lanes are visible |
|
|
443
|
+
| `expandSwimLanesTooltip` | `"Expand swim lanes"` | Chevron button tooltip when lanes are hidden |
|
|
444
|
+
|
|
445
|
+
Dynamic fields (`rewindActiveTooltip`, `fastForwardActiveTooltip`) accept either a **static string** or a **function** `(multiplier: number) => string`. Use a function when you want to embed the speed value in your translated string.
|
|
446
|
+
|
|
447
|
+
### React example
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
import { Timeline } from '@kteneyck/cesium-timeline-react';
|
|
451
|
+
import type { TimelineLabels } from '@kteneyck/cesium-timeline-core';
|
|
452
|
+
|
|
453
|
+
const frLabels: Partial<TimelineLabels> = {
|
|
454
|
+
playTooltip: 'Lecture',
|
|
455
|
+
pauseTooltip: 'Pause',
|
|
456
|
+
liveLabel: 'EN DIRECT',
|
|
457
|
+
liveActiveLabel: '● EN DIRECT',
|
|
458
|
+
liveTooltip: 'Aller en direct',
|
|
459
|
+
liveActiveTooltip: 'Vous êtes en direct',
|
|
460
|
+
rewindTooltip: 'Retour rapide',
|
|
461
|
+
rewindActiveTooltip: (n) => `Retour ${n}× — cliquer pour accélérer`,
|
|
462
|
+
fastForwardTooltip: 'Avance rapide',
|
|
463
|
+
fastForwardActiveTooltip: (n) => `${n}× — cliquer pour augmenter la vitesse`,
|
|
464
|
+
collapseSwimLanesTooltip: 'Réduire les pistes',
|
|
465
|
+
expandSwimLanesTooltip: 'Développer les pistes',
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
<Timeline clock={viewer.clock} labels={frLabels} height={120} />
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Angular example
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// component.ts
|
|
475
|
+
import type { TimelineLabels } from '@kteneyck/cesium-timeline-core';
|
|
476
|
+
|
|
477
|
+
@Component({ ... })
|
|
478
|
+
export class AppComponent {
|
|
479
|
+
frLabels: Partial<TimelineLabels> = {
|
|
480
|
+
playTooltip: 'Lecture',
|
|
481
|
+
pauseTooltip: 'Pause',
|
|
482
|
+
liveLabel: 'EN DIRECT',
|
|
483
|
+
liveActiveLabel: '● EN DIRECT',
|
|
484
|
+
liveTooltip: 'Aller en direct',
|
|
485
|
+
liveActiveTooltip: 'Vous êtes en direct',
|
|
486
|
+
rewindActiveTooltip: (n) => `Retour ${n}× — cliquer pour accélérer`,
|
|
487
|
+
fastForwardActiveTooltip: (n) => `${n}× — cliquer pour augmenter la vitesse`,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
```html
|
|
493
|
+
<!-- component.html -->
|
|
494
|
+
<ct-timeline [clock]="clock" [labels]="frLabels" [height]="120" />
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
360
499
|
## Exports
|
|
361
500
|
|
|
362
501
|
### React
|
|
@@ -385,7 +524,10 @@ import {
|
|
|
385
524
|
```tsx
|
|
386
525
|
import {
|
|
387
526
|
DateTimeFormats, // Format string presets
|
|
388
|
-
|
|
527
|
+
Timezones, // { LOCAL: 'local', UTC: 'UTC' } convenience constants
|
|
528
|
+
DEFAULT_LABELS, // Default English label/tooltip strings
|
|
529
|
+
formatDateTime, // Token-based date formatter (date, format, timezone?)
|
|
530
|
+
getTimezoneAbbr, // Short timezone abbreviation for a date (date, timezone?)
|
|
389
531
|
splitForDisplay, // Split format string into time/date parts
|
|
390
532
|
toJulianDate, // Convert Date | JulianDate → JulianDate
|
|
391
533
|
toDate, // Convert Date | JulianDate → Date
|
|
@@ -401,6 +543,7 @@ import {
|
|
|
401
543
|
// TypeScript types
|
|
402
544
|
import type {
|
|
403
545
|
TimelineTheme,
|
|
546
|
+
TimelineLabels,
|
|
404
547
|
SwimLane,
|
|
405
548
|
SwimLaneItem,
|
|
406
549
|
SwimLaneItemStyle,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { EventEmitter, ViewChild, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import * as Cesium from 'cesium';
|
|
4
|
-
import { splitForDisplay, formatDateTime, getTimezoneAbbr, MIN_SPAN_MS, MAX_SPAN_MS, drawTimeline, hitTestSwimLane, hitTestLaneLabel, isInSwimLaneRegion, zoomRange, DEFAULT_LANE_HEIGHT, LANE_GAP, totalSwimLaneHeight, TICK_AREA_HEIGHT, SWIM_LANE_SCROLL_SPEED, defaultTheme, toJulianDate } from '@kteneyck/cesium-timeline-core';
|
|
4
|
+
import { splitForDisplay, formatDateTime, getTimezoneAbbr, DEFAULT_LABELS, resolveLabel, MIN_SPAN_MS, MAX_SPAN_MS, drawTimeline, hitTestSwimLane, hitTestLaneLabel, isInSwimLaneRegion, zoomRange, DEFAULT_LANE_HEIGHT, LANE_GAP, totalSwimLaneHeight, TICK_AREA_HEIGHT, SWIM_LANE_SCROLL_SPEED, defaultTheme, toJulianDate } from '@kteneyck/cesium-timeline-core';
|
|
5
5
|
export * from '@kteneyck/cesium-timeline-core';
|
|
6
6
|
export { TICK_AREA_HEIGHT } from '@kteneyck/cesium-timeline-core';
|
|
7
7
|
|
|
@@ -18,6 +18,7 @@ class TimelineControlsComponent {
|
|
|
18
18
|
showJumpToEnd;
|
|
19
19
|
theme;
|
|
20
20
|
swimLanesVisible;
|
|
21
|
+
labels;
|
|
21
22
|
dateTimeClick = new EventEmitter();
|
|
22
23
|
playPause = new EventEmitter();
|
|
23
24
|
jumpToStart = new EventEmitter();
|
|
@@ -40,6 +41,10 @@ class TimelineControlsComponent {
|
|
|
40
41
|
get formattedTime() { return formatDateTime(this.currentTime, this.timeFormat, this.timezone); }
|
|
41
42
|
get formattedDate() { return formatDateTime(this.currentTime, this.dateFormat, this.timezone); }
|
|
42
43
|
get timezoneAbbr() { return getTimezoneAbbr(this.currentTime, this.timezone); }
|
|
44
|
+
/** Merged labels — defaults overridden by whatever the consumer provides. */
|
|
45
|
+
get l() { return { ...DEFAULT_LABELS, ...this.labels }; }
|
|
46
|
+
resolveRewindActive(multiplier) { return resolveLabel(this.l.rewindActiveTooltip, multiplier); }
|
|
47
|
+
resolveFastForwardActive(multiplier) { return resolveLabel(this.l.fastForwardActiveTooltip, multiplier); }
|
|
43
48
|
ngAfterViewInit() {
|
|
44
49
|
const el = this.containerRef?.nativeElement;
|
|
45
50
|
if (!el)
|
|
@@ -53,7 +58,7 @@ class TimelineControlsComponent {
|
|
|
53
58
|
this.ro?.disconnect();
|
|
54
59
|
}
|
|
55
60
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: TimelineControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
56
|
-
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" }, 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: `
|
|
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: `
|
|
57
62
|
<div
|
|
58
63
|
#container
|
|
59
64
|
[style.display]="isNarrow ? 'flex' : 'grid'"
|
|
@@ -68,7 +73,7 @@ class TimelineControlsComponent {
|
|
|
68
73
|
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
|
|
69
74
|
<div
|
|
70
75
|
(click)="dateTimeClick.emit()"
|
|
71
|
-
[title]="dateTimeClick.observed ?
|
|
76
|
+
[title]="dateTimeClick.observed ? l.dateTimeClickTooltip : ''"
|
|
72
77
|
[style.color]="theme.labelColor"
|
|
73
78
|
style="font-family:monospace;line-height:1.15;border-radius:4px;padding:2px 4px;transition:background 0.15s"
|
|
74
79
|
[style.cursor]="dateTimeClick.observed ? 'pointer' : 'default'"
|
|
@@ -102,9 +107,9 @@ class TimelineControlsComponent {
|
|
|
102
107
|
[style.border-color]="theme.buttonActiveColor"
|
|
103
108
|
[style.opacity]="isLive ? 1 : 0.55"
|
|
104
109
|
style="background:none;border:1px solid;cursor:pointer;font-size:11px;font-weight:bold;letter-spacing:0.05em;width:52px;min-width:52px;height:20px;border-radius:3px;display:flex;align-items:center;justify-content:center;padding:0;font-family:system-ui,-apple-system,sans-serif;transition:opacity 0.15s"
|
|
105
|
-
[title]="isLive ?
|
|
110
|
+
[title]="isLive ? l.liveActiveTooltip : l.liveTooltip"
|
|
106
111
|
>
|
|
107
|
-
{{ isLive ?
|
|
112
|
+
{{ isLive ? l.liveActiveLabel : l.liveLabel }}
|
|
108
113
|
</button>
|
|
109
114
|
|
|
110
115
|
<!-- Speed badge -->
|
|
@@ -115,7 +120,7 @@ class TimelineControlsComponent {
|
|
|
115
120
|
[style.color]="theme.buttonActiveColor"
|
|
116
121
|
[style.border-color]="theme.buttonActiveColor + '44'"
|
|
117
122
|
style="background:none;border:1px solid;cursor:pointer;font-size:11px;width:52px;min-width:52px;height:20px;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"
|
|
118
|
-
title="
|
|
123
|
+
[title]="l.resetSpeedTooltip"
|
|
119
124
|
>
|
|
120
125
|
{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}
|
|
121
126
|
</button>
|
|
@@ -138,7 +143,7 @@ class TimelineControlsComponent {
|
|
|
138
143
|
[style.opacity]="hasStartTime ? 1 : 0.3"
|
|
139
144
|
[style.cursor]="hasStartTime ? 'pointer' : 'default'"
|
|
140
145
|
class="ct-btn"
|
|
141
|
-
[title]="hasStartTime ?
|
|
146
|
+
[title]="hasStartTime ? l.jumpToStartTooltip : l.noStartTimeTooltip"
|
|
142
147
|
>⏮</button>
|
|
143
148
|
}
|
|
144
149
|
|
|
@@ -147,7 +152,7 @@ class TimelineControlsComponent {
|
|
|
147
152
|
[style.color]="isRewinding ? theme.buttonActiveColor : theme.buttonColor"
|
|
148
153
|
[style.border-color]="isRewinding ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
149
154
|
class="ct-btn ct-btn-wide"
|
|
150
|
-
[title]="isRewinding ?
|
|
155
|
+
[title]="isRewinding ? resolveRewindActive(absMultiplier) : l.rewindTooltip"
|
|
151
156
|
>
|
|
152
157
|
@if (isRewinding) {
|
|
153
158
|
<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>◀◀
|
|
@@ -162,7 +167,7 @@ class TimelineControlsComponent {
|
|
|
162
167
|
[style.border-color]="theme.buttonActiveColor + '55'"
|
|
163
168
|
[style.padding-left]="isPlaying ? '0' : '2px'"
|
|
164
169
|
class="ct-btn ct-btn-play"
|
|
165
|
-
[title]="isPlaying ?
|
|
170
|
+
[title]="isPlaying ? l.pauseTooltip : (isRewinding ? l.playFromRewindTooltip : l.playTooltip)"
|
|
166
171
|
>
|
|
167
172
|
@if (isPlaying) {
|
|
168
173
|
<svg width="14" height="16" viewBox="0 0 14 16" fill="currentColor">
|
|
@@ -179,7 +184,7 @@ class TimelineControlsComponent {
|
|
|
179
184
|
[style.color]="isFastForward ? theme.buttonActiveColor : theme.buttonColor"
|
|
180
185
|
[style.border-color]="isFastForward ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
181
186
|
class="ct-btn ct-btn-wide"
|
|
182
|
-
[title]="isFastForward ? absMultiplier
|
|
187
|
+
[title]="isFastForward ? resolveFastForwardActive(absMultiplier) : l.fastForwardTooltip"
|
|
183
188
|
>
|
|
184
189
|
@if (isFastForward) {
|
|
185
190
|
▶▶<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>
|
|
@@ -196,7 +201,7 @@ class TimelineControlsComponent {
|
|
|
196
201
|
[style.opacity]="hasEndTime ? 1 : 0.3"
|
|
197
202
|
[style.cursor]="hasEndTime ? 'pointer' : 'default'"
|
|
198
203
|
class="ct-btn"
|
|
199
|
-
[title]="hasEndTime ?
|
|
204
|
+
[title]="hasEndTime ? l.jumpToEndTooltip : l.noEndTimeTooltip"
|
|
200
205
|
>⏭</button>
|
|
201
206
|
}
|
|
202
207
|
</div>
|
|
@@ -210,7 +215,7 @@ class TimelineControlsComponent {
|
|
|
210
215
|
[style.color]="theme.buttonActiveColor"
|
|
211
216
|
[style.border-color]="theme.buttonActiveColor + '33'"
|
|
212
217
|
class="ct-btn"
|
|
213
|
-
[title]="swimLanesVisible ?
|
|
218
|
+
[title]="swimLanesVisible ? l.collapseSwimLanesTooltip : l.expandSwimLanesTooltip"
|
|
214
219
|
>
|
|
215
220
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
216
221
|
@if (swimLanesVisible) {
|
|
@@ -231,7 +236,7 @@ class TimelineControlsComponent {
|
|
|
231
236
|
[style.border-color]="theme.buttonActiveColor + '33'"
|
|
232
237
|
class="ct-btn"
|
|
233
238
|
style="margin-left:4px"
|
|
234
|
-
[title]="swimLanesVisible ?
|
|
239
|
+
[title]="swimLanesVisible ? l.collapseSwimLanesTooltip : l.expandSwimLanesTooltip"
|
|
235
240
|
>
|
|
236
241
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
237
242
|
@if (swimLanesVisible) {
|
|
@@ -262,7 +267,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
262
267
|
<div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
|
|
263
268
|
<div
|
|
264
269
|
(click)="dateTimeClick.emit()"
|
|
265
|
-
[title]="dateTimeClick.observed ?
|
|
270
|
+
[title]="dateTimeClick.observed ? l.dateTimeClickTooltip : ''"
|
|
266
271
|
[style.color]="theme.labelColor"
|
|
267
272
|
style="font-family:monospace;line-height:1.15;border-radius:4px;padding:2px 4px;transition:background 0.15s"
|
|
268
273
|
[style.cursor]="dateTimeClick.observed ? 'pointer' : 'default'"
|
|
@@ -296,9 +301,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
296
301
|
[style.border-color]="theme.buttonActiveColor"
|
|
297
302
|
[style.opacity]="isLive ? 1 : 0.55"
|
|
298
303
|
style="background:none;border:1px solid;cursor:pointer;font-size:11px;font-weight:bold;letter-spacing:0.05em;width:52px;min-width:52px;height:20px;border-radius:3px;display:flex;align-items:center;justify-content:center;padding:0;font-family:system-ui,-apple-system,sans-serif;transition:opacity 0.15s"
|
|
299
|
-
[title]="isLive ?
|
|
304
|
+
[title]="isLive ? l.liveActiveTooltip : l.liveTooltip"
|
|
300
305
|
>
|
|
301
|
-
{{ isLive ?
|
|
306
|
+
{{ isLive ? l.liveActiveLabel : l.liveLabel }}
|
|
302
307
|
</button>
|
|
303
308
|
|
|
304
309
|
<!-- Speed badge -->
|
|
@@ -309,7 +314,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
309
314
|
[style.color]="theme.buttonActiveColor"
|
|
310
315
|
[style.border-color]="theme.buttonActiveColor + '44'"
|
|
311
316
|
style="background:none;border:1px solid;cursor:pointer;font-size:11px;width:52px;min-width:52px;height:20px;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"
|
|
312
|
-
title="
|
|
317
|
+
[title]="l.resetSpeedTooltip"
|
|
313
318
|
>
|
|
314
319
|
{{ isRewinding ? '◀ ' + absMultiplier + '×' : absMultiplier + '× ▶' }}
|
|
315
320
|
</button>
|
|
@@ -332,7 +337,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
332
337
|
[style.opacity]="hasStartTime ? 1 : 0.3"
|
|
333
338
|
[style.cursor]="hasStartTime ? 'pointer' : 'default'"
|
|
334
339
|
class="ct-btn"
|
|
335
|
-
[title]="hasStartTime ?
|
|
340
|
+
[title]="hasStartTime ? l.jumpToStartTooltip : l.noStartTimeTooltip"
|
|
336
341
|
>⏮</button>
|
|
337
342
|
}
|
|
338
343
|
|
|
@@ -341,7 +346,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
341
346
|
[style.color]="isRewinding ? theme.buttonActiveColor : theme.buttonColor"
|
|
342
347
|
[style.border-color]="isRewinding ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
343
348
|
class="ct-btn ct-btn-wide"
|
|
344
|
-
[title]="isRewinding ?
|
|
349
|
+
[title]="isRewinding ? resolveRewindActive(absMultiplier) : l.rewindTooltip"
|
|
345
350
|
>
|
|
346
351
|
@if (isRewinding) {
|
|
347
352
|
<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>◀◀
|
|
@@ -356,7 +361,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
356
361
|
[style.border-color]="theme.buttonActiveColor + '55'"
|
|
357
362
|
[style.padding-left]="isPlaying ? '0' : '2px'"
|
|
358
363
|
class="ct-btn ct-btn-play"
|
|
359
|
-
[title]="isPlaying ?
|
|
364
|
+
[title]="isPlaying ? l.pauseTooltip : (isRewinding ? l.playFromRewindTooltip : l.playTooltip)"
|
|
360
365
|
>
|
|
361
366
|
@if (isPlaying) {
|
|
362
367
|
<svg width="14" height="16" viewBox="0 0 14 16" fill="currentColor">
|
|
@@ -373,7 +378,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
373
378
|
[style.color]="isFastForward ? theme.buttonActiveColor : theme.buttonColor"
|
|
374
379
|
[style.border-color]="isFastForward ? theme.buttonActiveColor + '33' : 'transparent'"
|
|
375
380
|
class="ct-btn ct-btn-wide"
|
|
376
|
-
[title]="isFastForward ? absMultiplier
|
|
381
|
+
[title]="isFastForward ? resolveFastForwardActive(absMultiplier) : l.fastForwardTooltip"
|
|
377
382
|
>
|
|
378
383
|
@if (isFastForward) {
|
|
379
384
|
▶▶<span style="font-size:11px;font-weight:bold">{{ absMultiplier }}×</span>
|
|
@@ -390,7 +395,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
390
395
|
[style.opacity]="hasEndTime ? 1 : 0.3"
|
|
391
396
|
[style.cursor]="hasEndTime ? 'pointer' : 'default'"
|
|
392
397
|
class="ct-btn"
|
|
393
|
-
[title]="hasEndTime ?
|
|
398
|
+
[title]="hasEndTime ? l.jumpToEndTooltip : l.noEndTimeTooltip"
|
|
394
399
|
>⏭</button>
|
|
395
400
|
}
|
|
396
401
|
</div>
|
|
@@ -404,7 +409,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
404
409
|
[style.color]="theme.buttonActiveColor"
|
|
405
410
|
[style.border-color]="theme.buttonActiveColor + '33'"
|
|
406
411
|
class="ct-btn"
|
|
407
|
-
[title]="swimLanesVisible ?
|
|
412
|
+
[title]="swimLanesVisible ? l.collapseSwimLanesTooltip : l.expandSwimLanesTooltip"
|
|
408
413
|
>
|
|
409
414
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
410
415
|
@if (swimLanesVisible) {
|
|
@@ -425,7 +430,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
425
430
|
[style.border-color]="theme.buttonActiveColor + '33'"
|
|
426
431
|
class="ct-btn"
|
|
427
432
|
style="margin-left:4px"
|
|
428
|
-
[title]="swimLanesVisible ?
|
|
433
|
+
[title]="swimLanesVisible ? l.collapseSwimLanesTooltip : l.expandSwimLanesTooltip"
|
|
429
434
|
>
|
|
430
435
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
431
436
|
@if (swimLanesVisible) {
|
|
@@ -462,6 +467,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
462
467
|
type: Input
|
|
463
468
|
}], swimLanesVisible: [{
|
|
464
469
|
type: Input
|
|
470
|
+
}], labels: [{
|
|
471
|
+
type: Input
|
|
465
472
|
}], dateTimeClick: [{
|
|
466
473
|
type: Output
|
|
467
474
|
}], playPause: [{
|
|
@@ -1193,6 +1200,8 @@ class TimelineComponent {
|
|
|
1193
1200
|
swimLanes;
|
|
1194
1201
|
showSwimLanes;
|
|
1195
1202
|
swimLaneTransition = 'animated';
|
|
1203
|
+
/** Overrides for control-bar labels and tooltips (i18n / custom verbiage). */
|
|
1204
|
+
labels;
|
|
1196
1205
|
// ── Outputs ────────────────────────────────────────────────────────────
|
|
1197
1206
|
timeChange = new EventEmitter();
|
|
1198
1207
|
playPause = new EventEmitter();
|
|
@@ -1429,7 +1438,7 @@ class TimelineComponent {
|
|
|
1429
1438
|
this.cdr.markForCheck();
|
|
1430
1439
|
}
|
|
1431
1440
|
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 });
|
|
1432
|
-
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" }, outputs: { timeChange: "timeChange", playPause: "playPause", multiplierChange: "multiplierChange", dateTimeClick: "dateTimeClick", showSwimLanesChange: "showSwimLanesChange", swimLaneItemClick: "swimLaneItemClick", swimLaneItemHover: "swimLaneItemHover", swimLaneItemDoubleClick: "swimLaneItemDoubleClick", swimLaneItemContextMenu: "swimLaneItemContextMenu", swimLaneReorder: "swimLaneReorder" }, viewQueries: [{ propertyName: "canvasComp", first: true, predicate: TimelineCanvasComponent, descendants: true }, { propertyName: "controlsRef", first: true, predicate: ["controlsEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1441
|
+
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" }, viewQueries: [{ propertyName: "canvasComp", first: true, predicate: TimelineCanvasComponent, descendants: true }, { propertyName: "controlsRef", first: true, predicate: ["controlsEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
|
|
1433
1442
|
<div
|
|
1434
1443
|
[class]="cssClass"
|
|
1435
1444
|
[style.width]="'100%'"
|
|
@@ -1464,6 +1473,7 @@ class TimelineComponent {
|
|
|
1464
1473
|
(resetSpeed)="applyMultiplier(1)"
|
|
1465
1474
|
(dateTimeClick)="dateTimeClick.emit()"
|
|
1466
1475
|
(toggleSwimLanes)="handleToggleSwimLanes()"
|
|
1476
|
+
[labels]="labels"
|
|
1467
1477
|
/>
|
|
1468
1478
|
</div>
|
|
1469
1479
|
}
|
|
@@ -1489,7 +1499,7 @@ class TimelineComponent {
|
|
|
1489
1499
|
/>
|
|
1490
1500
|
}
|
|
1491
1501
|
</div>
|
|
1492
|
-
`, 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"], 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", "swimLanes", "showSwimLanes"], outputs: ["timeChange", "dragStart", "dragEnd", "swimLaneItemClick", "swimLaneItemHover", "swimLaneItemDoubleClick", "swimLaneItemContextMenu", "swimLaneReorder"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1502
|
+
`, 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", "swimLanes", "showSwimLanes"], outputs: ["timeChange", "dragStart", "dragEnd", "swimLaneItemClick", "swimLaneItemHover", "swimLaneItemDoubleClick", "swimLaneItemContextMenu", "swimLaneReorder"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1493
1503
|
}
|
|
1494
1504
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: TimelineComponent, decorators: [{
|
|
1495
1505
|
type: Component,
|
|
@@ -1528,6 +1538,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1528
1538
|
(resetSpeed)="applyMultiplier(1)"
|
|
1529
1539
|
(dateTimeClick)="dateTimeClick.emit()"
|
|
1530
1540
|
(toggleSwimLanes)="handleToggleSwimLanes()"
|
|
1541
|
+
[labels]="labels"
|
|
1531
1542
|
/>
|
|
1532
1543
|
</div>
|
|
1533
1544
|
}
|
|
@@ -1594,6 +1605,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1594
1605
|
type: Input
|
|
1595
1606
|
}], swimLaneTransition: [{
|
|
1596
1607
|
type: Input
|
|
1608
|
+
}], labels: [{
|
|
1609
|
+
type: Input
|
|
1597
1610
|
}], timeChange: [{
|
|
1598
1611
|
type: Output
|
|
1599
1612
|
}], playPause: [{
|