@kteneyck/cesium-timeline-angular 0.3.0 → 0.5.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 +59 -2
- package/{dist/fesm2022 → fesm2022}/kteneyck-cesium-timeline-angular.mjs +43 -12
- 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 +7 -3
- package/dist/README.md +0 -869
- package/dist/fesm2022/kteneyck-cesium-timeline-angular.mjs.map +0 -1
package/dist/README.md
DELETED
|
@@ -1,869 +0,0 @@
|
|
|
1
|
-
# @kteneyck/cesium-timeline
|
|
2
|
-
|
|
3
|
-
A canvas-based timeline component for **React** and **Angular** with Cesium Clock integration. Provides interactive time scrubbing, smooth edge-scroll, Netflix/Hulu-style playback controls, a LIVE indicator, and a flexible token-based datetime format system.
|
|
4
|
-
|
|
5
|
-
## Packages
|
|
6
|
-
|
|
7
|
-
| Package | Description | npm |
|
|
8
|
-
|---|---|---|
|
|
9
|
-
| `@kteneyck/cesium-timeline-core` | Framework-agnostic types, utils, canvas engine | [](https://www.npmjs.com/package/@kteneyck/cesium-timeline-core) |
|
|
10
|
-
| `@kteneyck/cesium-timeline-react` | React components (thin wrappers around core) | [](https://www.npmjs.com/package/@kteneyck/cesium-timeline-react) |
|
|
11
|
-
| `@kteneyck/cesium-timeline-angular` | Angular standalone components (Angular 17+) | [](https://www.npmjs.com/package/@kteneyck/cesium-timeline-angular) |
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
16
|
-
|
|
17
|
-
### React
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install @kteneyck/cesium-timeline-react @kteneyck/cesium-timeline-core
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Peer dependencies: `react` ≥ 19, `cesium` ≥ 1.100
|
|
24
|
-
|
|
25
|
-
### Angular
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npm install @kteneyck/cesium-timeline-angular @kteneyck/cesium-timeline-core
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Peer dependencies: `@angular/core` ≥ 17, `cesium` ≥ 1.100
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## Basic Usage
|
|
36
|
-
|
|
37
|
-
### React
|
|
38
|
-
|
|
39
|
-
```tsx
|
|
40
|
-
import { Timeline } from '@kteneyck/cesium-timeline-react';
|
|
41
|
-
|
|
42
|
-
const MyComponent = () => {
|
|
43
|
-
const viewer = /* your Cesium Viewer */;
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Timeline
|
|
47
|
-
clock={viewer.clock}
|
|
48
|
-
height={120}
|
|
49
|
-
onTimeChange={(t) => { viewer.clock.currentTime = t; }}
|
|
50
|
-
onPlayPause={(playing) => { viewer.clock.shouldAnimate = playing; }}
|
|
51
|
-
onMultiplierChange={(m) => { viewer.clock.multiplier = m; }}
|
|
52
|
-
/>
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
When `clock` is provided the component subscribes to `clock.onTick` and stays in sync automatically. All `onTimeChange`, `onPlayPause`, and `onMultiplierChange` callbacks are optional — the controls still work without them if you only pass `clock`.
|
|
58
|
-
|
|
59
|
-
### Without a Cesium Clock
|
|
60
|
-
|
|
61
|
-
```tsx
|
|
62
|
-
<Timeline
|
|
63
|
-
startTime={new Date('2026-01-01T00:00:00')}
|
|
64
|
-
endTime={new Date('2026-12-31T23:59:59')}
|
|
65
|
-
height={80}
|
|
66
|
-
showControls={false}
|
|
67
|
-
onTimeChange={(t) => console.log(Cesium.JulianDate.toIso8601(t))}
|
|
68
|
-
/>
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
When no `clock` is provided the component falls back to `setInterval` and tracks real wall-clock time.
|
|
72
|
-
|
|
73
|
-
### Angular
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
import { Component } from '@angular/core';
|
|
77
|
-
import { TimelineComponent } from '@kteneyck/cesium-timeline-angular';
|
|
78
|
-
import * as Cesium from 'cesium';
|
|
79
|
-
|
|
80
|
-
@Component({
|
|
81
|
-
selector: 'app-root',
|
|
82
|
-
standalone: true,
|
|
83
|
-
imports: [TimelineComponent],
|
|
84
|
-
template: `
|
|
85
|
-
<ct-timeline
|
|
86
|
-
[clock]="viewer.clock"
|
|
87
|
-
[height]="120"
|
|
88
|
-
(timeChange)="onTimeChange($event)"
|
|
89
|
-
(playPause)="onPlayPause($event)"
|
|
90
|
-
(multiplierChange)="onMultiplierChange($event)"
|
|
91
|
-
/>
|
|
92
|
-
`,
|
|
93
|
-
})
|
|
94
|
-
export class AppComponent {
|
|
95
|
-
viewer!: Cesium.Viewer;
|
|
96
|
-
|
|
97
|
-
onTimeChange(t: Cesium.JulianDate) {
|
|
98
|
-
this.viewer.clock.currentTime = t;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
onPlayPause(playing: boolean) {
|
|
102
|
-
this.viewer.clock.shouldAnimate = playing;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
onMultiplierChange(m: number) {
|
|
106
|
-
this.viewer.clock.multiplier = m;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Angular components use standalone imports — no NgModule required. Selectors: `ct-timeline`, `ct-timeline-canvas`, `ct-timeline-controls`.
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## Features
|
|
116
|
-
|
|
117
|
-
- **Canvas rendering** — zero framework re-renders during playback or drag; all mutable state lives in refs/class properties.
|
|
118
|
-
- **Shared core engine** — identical visual output in React and Angular via `@kteneyck/cesium-timeline-core`.
|
|
119
|
-
- **Cesium Clock sync** — subscribes to `clock.onTick`; respects `shouldAnimate`, `multiplier`, and `currentTime`.
|
|
120
|
-
- **Draggable needle** — grab and drag the current-time indicator to scrub; cursor changes to `grab`/`grabbing`.
|
|
121
|
-
- **Click-to-seek** — click anywhere on the timeline to jump to that time.
|
|
122
|
-
- **Edge scroll** — drag the needle within 8% of either edge and the visible window scrolls smoothly underneath. The needle stays pinned to the cursor position as the window shifts.
|
|
123
|
-
- **Auto-scroll during playback** — visible window pans automatically when the needle reaches 10% from either edge.
|
|
124
|
-
- **Infinite scrolling window** — timeline is not clamped to `startTime`/`endTime`; the window can pan anywhere.
|
|
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
|
-
- **Local time labels** — ticks and dates reflect the user's local timezone, not UTC.
|
|
127
|
-
- **Netflix/Hulu-style controls** — transport buttons (⏮ ◀◀ ▶/⏸ ▶▶ ⏭) always stay centered; speed badge and LIVE button in the left column never cause layout shift.
|
|
128
|
-
- **Conditional start/end buttons** — ⏮ and ⏭ are only rendered when `startTime` and `endTime` props are explicitly provided.
|
|
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.
|
|
130
|
-
- **LIVE button** — filled `● LIVE` when within 10 s of wall clock; dim outline `LIVE` otherwise; clicking jumps to `Date.now()` and resets speed to 1×.
|
|
131
|
-
- **Speed badge** — shown in the left column when multiplier ≠ 1×; click to reset to 1×.
|
|
132
|
-
- **Two-line datetime display** — time displayed large/bold; date displayed smaller in the theme's active color.
|
|
133
|
-
- **Clickable datetime** — pass `onDateTimeClick` to open your own date picker; pass the result back via `jumpToTime` to pan the canvas and set the time.
|
|
134
|
-
- **Token-based datetime format** — built-in presets plus custom format strings with 17 supported tokens.
|
|
135
|
-
- **Max tick limit** — `maxTicks` prop prevents the canvas from becoming overloaded at wide zoom levels by coarsening the tick scale automatically.
|
|
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
|
-
- **Fully themeable** — 16 theme properties cover every color, size, and font setting, including swim lane item border defaults.
|
|
138
|
-
- **Responsive** — fills container width; `ResizeObserver` redraws on resize.
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
## Props
|
|
143
|
-
|
|
144
|
-
### `TimelineProps`
|
|
145
|
-
|
|
146
|
-
| Prop | Type | Default | Description |
|
|
147
|
-
|------|------|---------|-------------|
|
|
148
|
-
| `clock` | `Cesium.Clock` | — | Cesium clock to sync with. Falls back to `setInterval` if omitted. |
|
|
149
|
-
| `startTime` | `JulianDate \| Date` | now − 12 h | Left bound of initial visible window. Also shows the ⏮ button when provided. |
|
|
150
|
-
| `endTime` | `JulianDate \| Date` | now + 12 h | Right bound of initial visible window. Also shows the ⏭ button when provided. |
|
|
151
|
-
| `currentTime` | `JulianDate \| Date` | `startTime` | Initial needle position |
|
|
152
|
-
| `height` | `number` | `120` | Canvas height in pixels |
|
|
153
|
-
| `showControls` | `boolean` | `true` | Show/hide the control bar |
|
|
154
|
-
| `enableDrag` | `boolean` | `true` | Show/hide the canvas (drag/seek area) |
|
|
155
|
-
| `showLabels` | `boolean` | — | Show/hide tick labels on the canvas |
|
|
156
|
-
| `snapToTicks` | `boolean` | — | Snap needle to nearest tick on drag |
|
|
157
|
-
| `tickInterval` | `TickInterval \| number` | auto | Override automatic tick interval |
|
|
158
|
-
| `maxTicks` | `number` | unlimited | Maximum number of major ticks on the canvas at once. When exceeded the tick scale is automatically coarsened. |
|
|
159
|
-
| `ffSpeeds` | `number[]` | `[2,4,8,16,32,1]` | Speed steps cycled by the ▶▶ button. Last entry wraps back to first. |
|
|
160
|
-
| `rwSpeeds` | `number[]` | `[1,2,4,8,16,32]` | Absolute-value speed steps cycled by the ◀◀ button (negated internally). |
|
|
161
|
-
| `dateTimeFormat` | `string` | `'MMM DD YYYY HH:mm:ss'` | Token-based format string for the controls datetime display |
|
|
162
|
-
| `onDateTimeClick` | `() => void` | — | Called when the user clicks the datetime display. Use to open your own date picker. |
|
|
163
|
-
| `jumpToTime` | `JulianDate \| Date` | — | Set to programmatically jump the timeline to a moment (pans canvas + sets time). |
|
|
164
|
-
| `theme` | `Partial<TimelineTheme>` | `defaultTheme` | Theme overrides (merged with defaults) |
|
|
165
|
-
| `className` | `string` | — | CSS class applied to the root div |
|
|
166
|
-
| `onTimeChange` | `(t: JulianDate) => void` | — | Fires when needle moves (drag, click, or clock tick) |
|
|
167
|
-
| `onPlayPause` | `(playing: boolean) => void` | — | Fires on play/pause toggle |
|
|
168
|
-
| `onMultiplierChange` | `(m: number) => void` | — | Fires when speed changes |
|
|
169
|
-
| `swimLanes` | `SwimLane[]` | — | Array of swim lane definitions to render on the canvas |
|
|
170
|
-
| `showSwimLanes` | `boolean` | `true` | Show or hide the swim lanes |
|
|
171
|
-
| `onSwimLaneItemClick` | `(info: SwimLaneEventInfo) => void` | — | Fires when a swim lane item is clicked |
|
|
172
|
-
| `onSwimLaneItemHover` | `(info: SwimLaneEventInfo \| null) => void` | — | Fires when mouse enters/leaves a swim lane item |
|
|
173
|
-
| `onSwimLaneItemDoubleClick` | `(info: SwimLaneEventInfo) => void` | — | Fires when a swim lane item is double-clicked |
|
|
174
|
-
| `onSwimLaneReorder` | `(orderedIds: string[]) => void` | — | Fires when swim lanes are reordered via drag. Receives the new lane id order. |
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## Theme
|
|
179
|
-
|
|
180
|
-
Pass a partial `TimelineTheme` object to the `theme` prop. Any omitted properties fall back to `defaultTheme`.
|
|
181
|
-
|
|
182
|
-
```tsx
|
|
183
|
-
<Timeline
|
|
184
|
-
clock={viewer.clock}
|
|
185
|
-
theme={{
|
|
186
|
-
backgroundColor: '#111',
|
|
187
|
-
indicatorColor: '#ffd54f',
|
|
188
|
-
buttonActiveColor: '#ffd54f',
|
|
189
|
-
}}
|
|
190
|
-
/>
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### `TimelineTheme` Properties
|
|
194
|
-
|
|
195
|
-
| Property | Default | Description |
|
|
196
|
-
|----------|-----------|-------------|
|
|
197
|
-
| `backgroundColor` | `#1a1a1a` | Canvas background colour |
|
|
198
|
-
| `tickColor` | `#666` | Minor tick stroke colour |
|
|
199
|
-
| `majorTickColor` | `#999` | Major tick stroke colour |
|
|
200
|
-
| `labelColor` | `#ccc` | Tick label and datetime text colour |
|
|
201
|
-
| `indicatorColor` | `#d69826` | Needle (current-time line) colour |
|
|
202
|
-
| `indicatorLineWidth` | `5` | Needle stroke width in px |
|
|
203
|
-
| `majorTickHeight` | `10` | Major tick height in px |
|
|
204
|
-
| `minorTickHeight` | `5` | Minor tick height in px |
|
|
205
|
-
| `fontSize` | `12` | Tick label font size in px |
|
|
206
|
-
| `controlBarBackground` | `#242424` | Control bar background colour |
|
|
207
|
-
| `controlBarBorder` | `#333` | Control bar bottom border colour |
|
|
208
|
-
| `buttonColor` | `#666` | Normal button colour |
|
|
209
|
-
| `buttonHoverColor` | `#888` | Button hover colour |
|
|
210
|
-
| `buttonActiveColor` | `#d69826` | Active buttons, LIVE, speed badge, and date line colour |
|
|
211
|
-
| `swimLaneItemBorderColor` | `#666666` | Default border colour for swim lane interval bars. Can be overridden per-lane or per-item. |
|
|
212
|
-
| `swimLaneItemBorderWidth` | `0` | Default border width (px) for swim lane interval bars. Set to `0` to remove borders globally. Can be overridden per-lane or per-item. |
|
|
213
|
-
|
|
214
|
-
> **Note:** Theme colours must be resolved hex/rgb values. CSS variables like `var(--primary-color)` do **not** work in canvas `ctx.fillStyle`. Use `getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim()` to resolve them first.
|
|
215
|
-
|
|
216
|
-
### Resolving CSS Variables
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
const theme = useMemo(() => {
|
|
220
|
-
const style = getComputedStyle(document.documentElement);
|
|
221
|
-
return {
|
|
222
|
-
indicatorColor: style.getPropertyValue('--primary-color').trim() || '#ffd54f',
|
|
223
|
-
backgroundColor: style.getPropertyValue('--surface-ground').trim() || '#1a1a1a',
|
|
224
|
-
};
|
|
225
|
-
}, []);
|
|
226
|
-
|
|
227
|
-
<Timeline clock={viewer.clock} theme={theme} />
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
---
|
|
231
|
-
|
|
232
|
-
## DateTime Format
|
|
233
|
-
|
|
234
|
-
The `dateTimeFormat` prop controls the two-line datetime display in the control bar. It accepts a token-based format string.
|
|
235
|
-
|
|
236
|
-
### Built-in Presets (`DateTimeFormats`)
|
|
237
|
-
|
|
238
|
-
```tsx
|
|
239
|
-
import { DateTimeFormats } from '@kteneyck/cesium-timeline-react';
|
|
240
|
-
|
|
241
|
-
<Timeline dateTimeFormat={DateTimeFormats.TWELVE_HR} ... />
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
| Key | Format string | Example output |
|
|
245
|
-
|-----|--------------|----------------|
|
|
246
|
-
| `DEFAULT` | `MMM DD YYYY HH:mm:ss` | Feb 24 2026 14:04:07 |
|
|
247
|
-
| `TWELVE_HR` | `MMM DD YYYY hh:mm:ss A` | Feb 24 2026 02:04:07 PM |
|
|
248
|
-
| `ISO` | `YYYY-MM-DD HH:mm:ss` | 2026-02-24 14:04:07 |
|
|
249
|
-
| `US` | `MM/DD/YYYY HH:mm` | 02/24/2026 14:04 |
|
|
250
|
-
| `EU` | `DD/MM/YYYY HH:mm` | 24/02/2026 14:04 |
|
|
251
|
-
| `TIME_ONLY` | `HH:mm:ss` | 14:04:07 |
|
|
252
|
-
| `TIME_12` | `hh:mm:ss A` | 02:04:07 PM |
|
|
253
|
-
|
|
254
|
-
### Supported Tokens
|
|
255
|
-
|
|
256
|
-
| Token | Example | Description |
|
|
257
|
-
|-------|---------|-------------|
|
|
258
|
-
| `YYYY` | 2026 | 4-digit year |
|
|
259
|
-
| `YY` | 26 | 2-digit year |
|
|
260
|
-
| `MMMM` | February | Full month name |
|
|
261
|
-
| `MMM` | Feb | Abbreviated month name |
|
|
262
|
-
| `MM` | 02 | Zero-padded month number |
|
|
263
|
-
| `M` | 2 | Month number |
|
|
264
|
-
| `DD` | 05 | Zero-padded day |
|
|
265
|
-
| `D` | 5 | Day |
|
|
266
|
-
| `HH` | 14 | 24-hour, zero-padded |
|
|
267
|
-
| `H` | 14 | 24-hour |
|
|
268
|
-
| `hh` | 02 | 12-hour, zero-padded |
|
|
269
|
-
| `h` | 2 | 12-hour |
|
|
270
|
-
| `mm` | 04 | Minutes, zero-padded |
|
|
271
|
-
| `ss` | 07 | Seconds, zero-padded |
|
|
272
|
-
| `SSS` | 042 | Milliseconds, zero-padded |
|
|
273
|
-
| `A` | PM | AM/PM uppercase |
|
|
274
|
-
| `a` | pm | AM/PM lowercase |
|
|
275
|
-
|
|
276
|
-
The control bar automatically splits the format string into a **time line** (large/bold) and a **date line** (smaller, in `buttonActiveColor`) using the `splitForDisplay` utility.
|
|
277
|
-
|
|
278
|
-
### `formatDateTime` Utility
|
|
279
|
-
|
|
280
|
-
```tsx
|
|
281
|
-
import { formatDateTime, DateTimeFormats } from '@kteneyck/cesium-timeline-react';
|
|
282
|
-
|
|
283
|
-
const label = formatDateTime(julianDate, DateTimeFormats.ISO);
|
|
284
|
-
// → "2026-02-24 14:04:07"
|
|
285
|
-
|
|
286
|
-
const label2 = formatDateTime(new Date(), 'DD/MM/YYYY HH:mm');
|
|
287
|
-
// → "24/02/2026 14:04"
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
---
|
|
291
|
-
|
|
292
|
-
## Playback Controls
|
|
293
|
-
|
|
294
|
-
The control bar uses a 3-column CSS grid so the transport buttons are always centered regardless of the content in the left (datetime/LIVE/badge) or right (empty spacer) columns.
|
|
295
|
-
|
|
296
|
-
### Transport Buttons
|
|
297
|
-
|
|
298
|
-
| Button | Action |
|
|
299
|
-
|--------|--------|
|
|
300
|
-
| ⏮ | Jump to `startTime` — **only rendered when `startTime` prop is provided** |
|
|
301
|
-
| ◀◀ | Cycle reverse speeds through `rwSpeeds` (wraps) |
|
|
302
|
-
| ▶ / ⏸ | Play / Pause. If coming out of reverse, resets to 1× forward. |
|
|
303
|
-
| ▶▶ | Cycle forward speeds through `ffSpeeds` (wraps) |
|
|
304
|
-
| ⏭ | Jump to `endTime` — **only rendered when `endTime` prop is provided** |
|
|
305
|
-
|
|
306
|
-
### LIVE Button
|
|
307
|
-
|
|
308
|
-
- Shows `● LIVE` (filled background) when the current time is within 10 seconds of `Date.now()`.
|
|
309
|
-
- Shows `LIVE` (dim outline) otherwise.
|
|
310
|
-
- Clicking jumps to `Date.now()`, centers the visible window ±12 h, and resets speed to 1×.
|
|
311
|
-
|
|
312
|
-
### Speed Badge
|
|
313
|
-
|
|
314
|
-
- Appears to the right of LIVE when multiplier ≠ 1×.
|
|
315
|
-
- Shows `◀ N×` for reverse, `N× ▶` for fast-forward.
|
|
316
|
-
- Clicking resets to 1× speed.
|
|
317
|
-
|
|
318
|
-
### Configuring Playback Speeds
|
|
319
|
-
|
|
320
|
-
```tsx
|
|
321
|
-
// Gentle: 2× and 4× only
|
|
322
|
-
<Timeline ffSpeeds={[2, 4, 1]} rwSpeeds={[1, 2, 4]} ... />
|
|
323
|
-
|
|
324
|
-
// Scientific: fine-grained control
|
|
325
|
-
<Timeline ffSpeeds={[10, 100, 1000, 10000, 1]} rwSpeeds={[1, 10, 100, 1000]} ... />
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
---
|
|
329
|
-
|
|
330
|
-
## Date Picker Integration
|
|
331
|
-
|
|
332
|
-
Pass `onDateTimeClick` to make the datetime display clickable. When clicked, open your own picker. Pass the result back as `jumpToTime` to pan the canvas to the selected time.
|
|
333
|
-
|
|
334
|
-
```tsx
|
|
335
|
-
const [jumpToTime, setJumpToTime] = useState<Date | undefined>();
|
|
336
|
-
const [pickerOpen, setPickerOpen] = useState(false);
|
|
337
|
-
|
|
338
|
-
<Timeline
|
|
339
|
-
clock={viewer.clock}
|
|
340
|
-
onDateTimeClick={() => setPickerOpen(true)}
|
|
341
|
-
jumpToTime={jumpToTime}
|
|
342
|
-
...
|
|
343
|
-
/>
|
|
344
|
-
|
|
345
|
-
{/* Your picker — any library works */}
|
|
346
|
-
{pickerOpen && (
|
|
347
|
-
<MyDatePicker
|
|
348
|
-
onSelect={(date) => {
|
|
349
|
-
setJumpToTime(date);
|
|
350
|
-
setPickerOpen(false);
|
|
351
|
-
}}
|
|
352
|
-
/>
|
|
353
|
-
)}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
> `jumpToTime` is edge-triggered: the timeline reacts whenever the value changes. Wrap updates in a new `Date` instance (or use state) to ensure React detects the change.
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
|
|
360
|
-
## Exports
|
|
361
|
-
|
|
362
|
-
### React
|
|
363
|
-
|
|
364
|
-
```tsx
|
|
365
|
-
import {
|
|
366
|
-
Timeline, // Main component
|
|
367
|
-
TimelineCanvas, // Canvas component (imperative handle)
|
|
368
|
-
TimelineControls, // Transport controls
|
|
369
|
-
TimelineSVG, // SVG-based alternative renderer
|
|
370
|
-
} from '@kteneyck/cesium-timeline-react';
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### Angular
|
|
374
|
-
|
|
375
|
-
```typescript
|
|
376
|
-
import {
|
|
377
|
-
TimelineComponent, // <ct-timeline>
|
|
378
|
-
TimelineCanvasComponent, // <ct-timeline-canvas>
|
|
379
|
-
TimelineControlsComponent, // <ct-timeline-controls>
|
|
380
|
-
} from '@kteneyck/cesium-timeline-angular';
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
### Core (re-exported by both React and Angular packages)
|
|
384
|
-
|
|
385
|
-
```tsx
|
|
386
|
-
import {
|
|
387
|
-
DateTimeFormats, // Format string presets
|
|
388
|
-
formatDateTime, // Token-based date formatter
|
|
389
|
-
splitForDisplay, // Split format string into time/date parts
|
|
390
|
-
toJulianDate, // Convert Date | JulianDate → JulianDate
|
|
391
|
-
toDate, // Convert Date | JulianDate → Date
|
|
392
|
-
toMilliseconds, // Convert ms → number
|
|
393
|
-
fromMilliseconds, // Convert ms → JulianDate
|
|
394
|
-
getDurationMs, // Duration between two dates in ms
|
|
395
|
-
TickInterval, // Enum: FIFTEEN_MIN | THIRTY_MIN | HOURLY | CUSTOM
|
|
396
|
-
defaultTheme, // Default theme values
|
|
397
|
-
defaultSwimLaneStyle,
|
|
398
|
-
DEFAULT_LANE_HEIGHT,
|
|
399
|
-
} from '@kteneyck/cesium-timeline-core';
|
|
400
|
-
|
|
401
|
-
// TypeScript types
|
|
402
|
-
import type {
|
|
403
|
-
TimelineTheme,
|
|
404
|
-
SwimLane,
|
|
405
|
-
SwimLaneItem,
|
|
406
|
-
SwimLaneItemStyle,
|
|
407
|
-
SwimLaneStyle,
|
|
408
|
-
SwimLaneEventInfo,
|
|
409
|
-
} from '@kteneyck/cesium-timeline-core';
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
## Examples
|
|
415
|
-
|
|
416
|
-
### Full Cesium Integration
|
|
417
|
-
|
|
418
|
-
```tsx
|
|
419
|
-
import { useRef, useEffect, useMemo, useState } from 'react';
|
|
420
|
-
import * as Cesium from 'cesium';
|
|
421
|
-
import { Timeline, DateTimeFormats } from '@kteneyck/cesium-timeline-react';
|
|
422
|
-
|
|
423
|
-
const CesiumWithTimeline = () => {
|
|
424
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
425
|
-
const [clock, setClock] = useState<Cesium.Clock | undefined>();
|
|
426
|
-
|
|
427
|
-
useEffect(() => {
|
|
428
|
-
if (!containerRef.current) return;
|
|
429
|
-
const viewer = new Cesium.Viewer(containerRef.current);
|
|
430
|
-
viewer.clock.shouldAnimate = false;
|
|
431
|
-
setClock(viewer.clock);
|
|
432
|
-
return () => viewer.destroy();
|
|
433
|
-
}, []);
|
|
434
|
-
|
|
435
|
-
const theme = useMemo(() => ({
|
|
436
|
-
indicatorColor: '#ffd54f',
|
|
437
|
-
buttonActiveColor: '#ffd54f',
|
|
438
|
-
backgroundColor: '#1a1a1a',
|
|
439
|
-
}), []);
|
|
440
|
-
|
|
441
|
-
return (
|
|
442
|
-
<div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
|
|
443
|
-
<div ref={containerRef} style={{ flex: 1 }} />
|
|
444
|
-
{clock && (
|
|
445
|
-
<Timeline
|
|
446
|
-
clock={clock}
|
|
447
|
-
height={120}
|
|
448
|
-
showControls={true}
|
|
449
|
-
showLabels={true}
|
|
450
|
-
snapToTicks={false}
|
|
451
|
-
dateTimeFormat={DateTimeFormats.DEFAULT}
|
|
452
|
-
theme={theme}
|
|
453
|
-
onTimeChange={(t) => { clock.currentTime = t; }}
|
|
454
|
-
onPlayPause={(playing) => { clock.shouldAnimate = playing; }}
|
|
455
|
-
onMultiplierChange={(m) => { clock.multiplier = m; }}
|
|
456
|
-
/>
|
|
457
|
-
)}
|
|
458
|
-
</div>
|
|
459
|
-
);
|
|
460
|
-
};
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
### With Start / End Bounds
|
|
464
|
-
|
|
465
|
-
Providing `startTime` and `endTime` shows the ⏮ and ⏭ jump buttons.
|
|
466
|
-
|
|
467
|
-
```tsx
|
|
468
|
-
const start = Cesium.JulianDate.fromIso8601('2026-01-01T00:00:00Z');
|
|
469
|
-
const end = Cesium.JulianDate.fromIso8601('2026-12-31T23:59:59Z');
|
|
470
|
-
|
|
471
|
-
<Timeline
|
|
472
|
-
clock={viewer.clock}
|
|
473
|
-
startTime={start}
|
|
474
|
-
endTime={end}
|
|
475
|
-
height={120}
|
|
476
|
-
onTimeChange={(t) => { viewer.clock.currentTime = t; }}
|
|
477
|
-
onPlayPause={(playing) => { viewer.clock.shouldAnimate = playing; }}
|
|
478
|
-
onMultiplierChange={(m) => { viewer.clock.multiplier = m; }}
|
|
479
|
-
/>
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
### Configuring Max Ticks
|
|
483
|
-
|
|
484
|
-
Useful when the timeline is shown at a small height or in a compact layout.
|
|
485
|
-
|
|
486
|
-
```tsx
|
|
487
|
-
<Timeline
|
|
488
|
-
clock={viewer.clock}
|
|
489
|
-
height={40}
|
|
490
|
-
maxTicks={10}
|
|
491
|
-
/>
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
### Configuring Playback Speeds
|
|
495
|
-
|
|
496
|
-
```tsx
|
|
497
|
-
// Slow-motion / real-time / time-lapse only
|
|
498
|
-
<Timeline
|
|
499
|
-
clock={viewer.clock}
|
|
500
|
-
ffSpeeds={[0.5, 1, 2, 10, 100]}
|
|
501
|
-
rwSpeeds={[0.5, 1, 2, 10, 100]}
|
|
502
|
-
/>
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
### Timeline-Only (No Controls)
|
|
506
|
-
|
|
507
|
-
```tsx
|
|
508
|
-
<Timeline
|
|
509
|
-
clock={viewer.clock}
|
|
510
|
-
height={35}
|
|
511
|
-
showControls={false}
|
|
512
|
-
theme={{ indicatorColor: '#ff6b6b' }}
|
|
513
|
-
/>
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
### Custom Date Range
|
|
517
|
-
|
|
518
|
-
```tsx
|
|
519
|
-
const start = new Date();
|
|
520
|
-
start.setHours(0, 0, 0, 0);
|
|
521
|
-
const end = new Date();
|
|
522
|
-
end.setHours(23, 59, 59, 999);
|
|
523
|
-
|
|
524
|
-
<Timeline
|
|
525
|
-
startTime={start}
|
|
526
|
-
endTime={end}
|
|
527
|
-
height={80}
|
|
528
|
-
dateTimeFormat="HH:mm:ss"
|
|
529
|
-
/>
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
### Without Clock (Standalone)
|
|
533
|
-
|
|
534
|
-
```tsx
|
|
535
|
-
import { useState } from 'react';
|
|
536
|
-
import * as Cesium from 'cesium';
|
|
537
|
-
import { Timeline } from '@kteneyck/cesium-timeline-react';
|
|
538
|
-
|
|
539
|
-
const StandaloneTimeline = () => {
|
|
540
|
-
const [time, setTime] = useState(new Date());
|
|
541
|
-
|
|
542
|
-
return (
|
|
543
|
-
<>
|
|
544
|
-
<p>Selected: {time.toLocaleTimeString()}</p>
|
|
545
|
-
<Timeline
|
|
546
|
-
onTimeChange={(t) => setTime(Cesium.JulianDate.toDate(t))}
|
|
547
|
-
height={80}
|
|
548
|
-
showControls={false}
|
|
549
|
-
/>
|
|
550
|
-
</>
|
|
551
|
-
);
|
|
552
|
-
};
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
---
|
|
556
|
-
|
|
557
|
-
## Swim Lanes
|
|
558
|
-
|
|
559
|
-
Swim lanes render time intervals (bars) and instants (markers) as horizontal rows directly on the timeline canvas, aligned with the ticks and needle. They are ideal for visualizing satellite passes, ground contacts, scheduled events, or any temporal data.
|
|
560
|
-
|
|
561
|
-
Lanes are rendered in the upper portion of the canvas. The tick area remains fixed at the bottom. As you increase the timeline `height`, more lanes become visible. When lanes overflow the available space, a vertical scrollbar appears and you can scroll with the mouse wheel.
|
|
562
|
-
|
|
563
|
-
### Basic Swim Lane Example
|
|
564
|
-
|
|
565
|
-
```tsx
|
|
566
|
-
import * as Cesium from 'cesium';
|
|
567
|
-
import { Timeline } from '@kteneyck/cesium-timeline-react';
|
|
568
|
-
import type { SwimLane } from '@kteneyck/cesium-timeline-react';
|
|
569
|
-
|
|
570
|
-
const now = Cesium.JulianDate.now();
|
|
571
|
-
const later = Cesium.JulianDate.addHours(now, 3, new Cesium.JulianDate());
|
|
572
|
-
|
|
573
|
-
const swimLanes: SwimLane[] = [
|
|
574
|
-
{
|
|
575
|
-
id: 'passes',
|
|
576
|
-
label: 'Passes',
|
|
577
|
-
items: [
|
|
578
|
-
{
|
|
579
|
-
id: 'pass-1',
|
|
580
|
-
interval: new Cesium.TimeInterval({ start: now, stop: later }),
|
|
581
|
-
},
|
|
582
|
-
],
|
|
583
|
-
},
|
|
584
|
-
];
|
|
585
|
-
|
|
586
|
-
<Timeline
|
|
587
|
-
clock={viewer.clock}
|
|
588
|
-
height={150}
|
|
589
|
-
swimLanes={swimLanes}
|
|
590
|
-
onTimeChange={(t) => { viewer.clock.currentTime = t; }}
|
|
591
|
-
/>
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
### Intervals and Instants
|
|
595
|
-
|
|
596
|
-
Each `SwimLaneItem` can have an `interval` (rendered as a horizontal bar), an `instant` (rendered as a marker), or both.
|
|
597
|
-
|
|
598
|
-
```tsx
|
|
599
|
-
const lanes: SwimLane[] = [
|
|
600
|
-
{
|
|
601
|
-
id: 'events',
|
|
602
|
-
label: 'Events',
|
|
603
|
-
items: [
|
|
604
|
-
// Interval — rendered as a bar spanning start to stop
|
|
605
|
-
{
|
|
606
|
-
id: 'meeting',
|
|
607
|
-
interval: new Cesium.TimeInterval({
|
|
608
|
-
start: Cesium.JulianDate.fromIso8601('2026-03-05T09:00:00Z'),
|
|
609
|
-
stop: Cesium.JulianDate.fromIso8601('2026-03-05T10:30:00Z'),
|
|
610
|
-
}),
|
|
611
|
-
},
|
|
612
|
-
// Instant — rendered as a marker at a single point in time
|
|
613
|
-
{
|
|
614
|
-
id: 'alert',
|
|
615
|
-
instant: Cesium.JulianDate.fromIso8601('2026-03-05T12:00:00Z'),
|
|
616
|
-
},
|
|
617
|
-
],
|
|
618
|
-
},
|
|
619
|
-
];
|
|
620
|
-
```
|
|
621
|
-
|
|
622
|
-
### Customizing Styles
|
|
623
|
-
|
|
624
|
-
Styles cascade: `defaultSwimLaneStyle` → `theme` → `lane.style` → `item.style`. Each level is a partial override.
|
|
625
|
-
|
|
626
|
-
> **Border shortcut:** The `swimLaneItemBorderColor` and `swimLaneItemBorderWidth` theme properties let you control item borders globally without touching individual lane or item styles. Set `swimLaneItemBorderWidth: 0` in your theme to remove all borders at once.
|
|
627
|
-
|
|
628
|
-
```tsx
|
|
629
|
-
const lanes: SwimLane[] = [
|
|
630
|
-
{
|
|
631
|
-
id: 'maintenance',
|
|
632
|
-
label: 'Maint.',
|
|
633
|
-
// Lane-level style: all items in this lane default to grey
|
|
634
|
-
style: {
|
|
635
|
-
color: '#78909c',
|
|
636
|
-
backgroundColor: 'rgba(120,144,156,0.1)',
|
|
637
|
-
},
|
|
638
|
-
items: [
|
|
639
|
-
{
|
|
640
|
-
id: 'window-1',
|
|
641
|
-
interval: new Cesium.TimeInterval({ start: h(-2), stop: h(0) }),
|
|
642
|
-
// Item-level override: this specific item is red
|
|
643
|
-
style: { color: '#f44336', opacity: 1.0 },
|
|
644
|
-
},
|
|
645
|
-
{
|
|
646
|
-
id: 'window-2',
|
|
647
|
-
interval: new Cesium.TimeInterval({ start: h(4), stop: h(6) }),
|
|
648
|
-
// Inherits lane style (grey)
|
|
649
|
-
},
|
|
650
|
-
],
|
|
651
|
-
},
|
|
652
|
-
];
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
#### `SwimLaneItemStyle` Properties
|
|
656
|
-
|
|
657
|
-
| Property | Type | Default | Description |
|
|
658
|
-
|----------|------|---------|-------------|
|
|
659
|
-
| `color` | `string` | `#4da6ff` | Fill colour for interval bars and instant markers |
|
|
660
|
-
| `borderColor` | `string` | `#2980b9` | Border colour for interval bars |
|
|
661
|
-
| `borderWidth` | `number` | `1` | Border width in px for interval bars |
|
|
662
|
-
| `opacity` | `number` | `0.8` | Opacity (0–1) |
|
|
663
|
-
| `markerShape` | `'diamond' \| 'circle' \| 'line'` | `'diamond'` | Shape used to render instant markers |
|
|
664
|
-
| `markerSize` | `number` | `10` | Size in px for instant markers |
|
|
665
|
-
|
|
666
|
-
#### `SwimLaneStyle` Properties (extends `SwimLaneItemStyle`)
|
|
667
|
-
|
|
668
|
-
| Property | Type | Default | Description |
|
|
669
|
-
|----------|------|---------|-------------|
|
|
670
|
-
| `labelColor` | `string` | `#cccccc` | Colour of the lane label text |
|
|
671
|
-
| `backgroundColor` | `string` | `transparent` | Background colour of the lane row |
|
|
672
|
-
|
|
673
|
-
### Instant Marker Shapes
|
|
674
|
-
|
|
675
|
-
Three marker shapes are available for instants:
|
|
676
|
-
|
|
677
|
-
```tsx
|
|
678
|
-
// Diamond (default)
|
|
679
|
-
{ id: 'a', instant: someDate, style: { markerShape: 'diamond' } }
|
|
680
|
-
|
|
681
|
-
// Circle
|
|
682
|
-
{ id: 'b', instant: someDate, style: { markerShape: 'circle' } }
|
|
683
|
-
|
|
684
|
-
// Vertical line
|
|
685
|
-
{ id: 'c', instant: someDate, style: { markerShape: 'line' } }
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
### Event Hooks
|
|
689
|
-
|
|
690
|
-
Swim lane items support click, hover, and double-click events. Each callback receives a `SwimLaneEventInfo` object.
|
|
691
|
-
|
|
692
|
-
```tsx
|
|
693
|
-
import type { SwimLaneEventInfo } from '@kteneyck/cesium-timeline-react';
|
|
694
|
-
|
|
695
|
-
const handleClick = (info: SwimLaneEventInfo) => {
|
|
696
|
-
console.log(`Clicked item ${info.item.id} in lane ${info.laneId}`);
|
|
697
|
-
console.log('Custom data:', info.item.data);
|
|
698
|
-
};
|
|
699
|
-
|
|
700
|
-
const handleHover = (info: SwimLaneEventInfo | null) => {
|
|
701
|
-
if (info) {
|
|
702
|
-
showTooltip(`${info.item.id} in ${info.laneId}`);
|
|
703
|
-
} else {
|
|
704
|
-
hideTooltip();
|
|
705
|
-
}
|
|
706
|
-
};
|
|
707
|
-
|
|
708
|
-
const handleDoubleClick = (info: SwimLaneEventInfo) => {
|
|
709
|
-
openDetailPanel(info.item.data);
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
<Timeline
|
|
713
|
-
clock={viewer.clock}
|
|
714
|
-
height={150}
|
|
715
|
-
swimLanes={lanes}
|
|
716
|
-
onSwimLaneItemClick={handleClick}
|
|
717
|
-
onSwimLaneItemHover={handleHover}
|
|
718
|
-
onSwimLaneItemDoubleClick={handleDoubleClick}
|
|
719
|
-
/>
|
|
720
|
-
```
|
|
721
|
-
|
|
722
|
-
#### `SwimLaneEventInfo`
|
|
723
|
-
|
|
724
|
-
| Property | Type | Description |
|
|
725
|
-
|----------|------|-------------|
|
|
726
|
-
| `laneId` | `string` | The `id` of the lane containing the item |
|
|
727
|
-
| `item` | `SwimLaneItem` | The item that was interacted with |
|
|
728
|
-
| `originalEvent` | `MouseEvent` | The native DOM mouse event |
|
|
729
|
-
|
|
730
|
-
### Attaching Custom Data
|
|
731
|
-
|
|
732
|
-
Use the `data` field on `SwimLaneItem` to attach arbitrary metadata. It's passed through in event callbacks.
|
|
733
|
-
|
|
734
|
-
```tsx
|
|
735
|
-
const lanes: SwimLane[] = [
|
|
736
|
-
{
|
|
737
|
-
id: 'contacts',
|
|
738
|
-
label: 'Contacts',
|
|
739
|
-
items: [
|
|
740
|
-
{
|
|
741
|
-
id: 'c-1',
|
|
742
|
-
interval: new Cesium.TimeInterval({ start: t1, stop: t2 }),
|
|
743
|
-
data: { satellite: 'ISS', groundStation: 'Goldstone', snr: 42.5 },
|
|
744
|
-
},
|
|
745
|
-
],
|
|
746
|
-
},
|
|
747
|
-
];
|
|
748
|
-
|
|
749
|
-
const handleClick = (info: SwimLaneEventInfo) => {
|
|
750
|
-
const { satellite, groundStation, snr } = info.item.data as ContactData;
|
|
751
|
-
console.log(`${satellite} → ${groundStation} (SNR: ${snr})`);
|
|
752
|
-
};
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
### Drag-to-Reorder
|
|
756
|
-
|
|
757
|
-
Pass `onSwimLaneReorder` to enable drag-to-reorder. Grab a lane by its label (left side) and drag up or down. An insertion indicator shows where the lane will be placed.
|
|
758
|
-
|
|
759
|
-
```tsx
|
|
760
|
-
const [lanes, setLanes] = useState<SwimLane[]>(initialLanes);
|
|
761
|
-
|
|
762
|
-
const handleReorder = (orderedIds: string[]) => {
|
|
763
|
-
// orderedIds is the new order of lane IDs
|
|
764
|
-
setLanes(prev => orderedIds.map(id => prev.find(l => l.id === id)!));
|
|
765
|
-
};
|
|
766
|
-
|
|
767
|
-
<Timeline
|
|
768
|
-
clock={viewer.clock}
|
|
769
|
-
height={150}
|
|
770
|
-
swimLanes={lanes}
|
|
771
|
-
onSwimLaneReorder={handleReorder}
|
|
772
|
-
/>
|
|
773
|
-
```
|
|
774
|
-
|
|
775
|
-
### Show / Hide Swim Lanes
|
|
776
|
-
|
|
777
|
-
Toggle visibility without removing the data:
|
|
778
|
-
|
|
779
|
-
```tsx
|
|
780
|
-
const [showSwimLanes, setShowSwimLanes] = useState(true);
|
|
781
|
-
|
|
782
|
-
<Timeline
|
|
783
|
-
clock={viewer.clock}
|
|
784
|
-
height={150}
|
|
785
|
-
swimLanes={lanes}
|
|
786
|
-
showSwimLanes={showSwimLanes}
|
|
787
|
-
/>
|
|
788
|
-
|
|
789
|
-
<button onClick={() => setShowSwimLanes(v => !v)}>
|
|
790
|
-
{showSwimLanes ? 'Hide' : 'Show'} Swim Lanes
|
|
791
|
-
</button>
|
|
792
|
-
```
|
|
793
|
-
|
|
794
|
-
When hidden, the full canvas height is used for the tick/label area as normal.
|
|
795
|
-
|
|
796
|
-
### Lane Height and Scrolling
|
|
797
|
-
|
|
798
|
-
Each lane defaults to 24px tall. Override per-lane with the `height` property:
|
|
799
|
-
|
|
800
|
-
```tsx
|
|
801
|
-
const lanes: SwimLane[] = [
|
|
802
|
-
{ id: 'big', label: 'Important', height: 40, items: [...] },
|
|
803
|
-
{ id: 'small', label: 'Minor', height: 16, items: [...] },
|
|
804
|
-
];
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
When the total lane height exceeds the available space (canvas height minus the 36px tick area), a scrollbar appears and the mouse wheel scrolls vertically in the swim lane region. Outside the lane region, the mouse wheel zooms the timeline as usual.
|
|
808
|
-
|
|
809
|
-
### Imperative API
|
|
810
|
-
|
|
811
|
-
The `TimelineCanvasHandle` (accessible via a ref on `Timeline`) exposes methods for programmatic swim lane management:
|
|
812
|
-
|
|
813
|
-
```tsx
|
|
814
|
-
const timelineRef = useRef<TimelineCanvasHandle>(null);
|
|
815
|
-
|
|
816
|
-
// Append a new lane
|
|
817
|
-
timelineRef.current?.appendSwimLane(newLane);
|
|
818
|
-
|
|
819
|
-
// Update an existing lane
|
|
820
|
-
timelineRef.current?.updateSwimLane('lane-id', updatedLane);
|
|
821
|
-
|
|
822
|
-
// Remove a lane
|
|
823
|
-
timelineRef.current?.removeSwimLane('lane-id');
|
|
824
|
-
|
|
825
|
-
// Reorder lanes
|
|
826
|
-
timelineRef.current?.reorderSwimLanes(['lane-b', 'lane-a', 'lane-c']);
|
|
827
|
-
```
|
|
828
|
-
|
|
829
|
-
---
|
|
830
|
-
|
|
831
|
-
## Building
|
|
832
|
-
|
|
833
|
-
```bash
|
|
834
|
-
cd cesium-timeline
|
|
835
|
-
npm install
|
|
836
|
-
|
|
837
|
-
# Build all packages (core → react → angular)
|
|
838
|
-
npm run build
|
|
839
|
-
|
|
840
|
-
# Build individually
|
|
841
|
-
npm run build:core
|
|
842
|
-
npm run build:react
|
|
843
|
-
npm run build:angular
|
|
844
|
-
|
|
845
|
-
# Development
|
|
846
|
-
npm run dev:demo # React demo with hot reload
|
|
847
|
-
npm run typecheck # TypeScript check (core + react)
|
|
848
|
-
npm run clean # Remove all build artifacts
|
|
849
|
-
```
|
|
850
|
-
|
|
851
|
-
### Project Structure
|
|
852
|
-
|
|
853
|
-
```
|
|
854
|
-
cesium-timeline/
|
|
855
|
-
├── packages/
|
|
856
|
-
│ ├── core/ → @kteneyck/cesium-timeline-core (types, utils, canvas engine)
|
|
857
|
-
│ ├── react/ → @kteneyck/cesium-timeline-react (React components)
|
|
858
|
-
│ └── angular/ → @kteneyck/cesium-timeline-angular (Angular standalone components)
|
|
859
|
-
├── demo-react/ → React demo app (npm run dev:demo)
|
|
860
|
-
├── src/ → Original source (preserved, not used by packages)
|
|
861
|
-
└── package.json → npm workspace root
|
|
862
|
-
```
|
|
863
|
-
|
|
864
|
-
---
|
|
865
|
-
|
|
866
|
-
## License
|
|
867
|
-
|
|
868
|
-
MIT
|
|
869
|
-
|