@motionstudies/core 0.1.0-alpha.3 → 0.1.0-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +247 -2
  2. package/air-continents.d.ts +63 -0
  3. package/air-continents.js +43 -0
  4. package/air-enrichment.d.ts +63 -0
  5. package/air-enrichment.js +76 -0
  6. package/air-search.d.ts +3 -0
  7. package/domain/aggregate-road.d.ts +48 -0
  8. package/domain/aggregate-road.js +22 -0
  9. package/domain/air-day.d.ts +3 -1
  10. package/domain/air.d.ts +15 -0
  11. package/domain/airport.d.ts +16 -0
  12. package/domain/airport.js +23 -0
  13. package/domain/daylight.d.ts +32 -0
  14. package/domain/daylight.js +32 -0
  15. package/domain/field-paths.d.ts +35 -0
  16. package/domain/field-paths.js +43 -0
  17. package/domain/gridded-series.d.ts +30 -0
  18. package/domain/gridded-series.js +61 -0
  19. package/domain/live-airport.d.ts +42 -0
  20. package/domain/live-airport.js +32 -0
  21. package/domain/movement-board.d.ts +21 -0
  22. package/domain/movement-board.js +23 -0
  23. package/domain/network-patterns.d.ts +19 -0
  24. package/domain/network-patterns.js +73 -0
  25. package/domain/network.js +37 -1
  26. package/domain/power-day.d.ts +84 -0
  27. package/domain/power-day.js +104 -0
  28. package/domain/published-day.d.ts +133 -0
  29. package/domain/published-day.js +162 -0
  30. package/domain/route-events.d.ts +70 -0
  31. package/domain/route-events.js +38 -0
  32. package/domain/route-field.d.ts +53 -0
  33. package/domain/route-field.js +47 -0
  34. package/domain/station-calls.d.ts +48 -0
  35. package/domain/station-calls.js +73 -0
  36. package/domain/station-departures.d.ts +15 -0
  37. package/domain/station-departures.js +25 -0
  38. package/domain/supported-field.d.ts +78 -0
  39. package/domain/supported-field.js +95 -0
  40. package/domain/vehicle-calls.d.ts +11 -0
  41. package/domain/vehicle-calls.js +14 -0
  42. package/domain/vehicle-counts.d.ts +13 -0
  43. package/domain/vehicle-counts.js +33 -0
  44. package/map-labels.d.ts +24 -0
  45. package/map-labels.js +48 -0
  46. package/package.json +108 -1
  47. package/render-frame.d.ts +8 -0
  48. package/render-frame.js +13 -0
  49. package/timeline.d.ts +31 -0
  50. package/timeline.js +68 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motionstudies/core",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.31",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Transport contracts and motion primitives for Motion Studies.",
@@ -20,6 +20,11 @@
20
20
  "tag": "next"
21
21
  },
22
22
  "exports": {
23
+ "./air-continents": {
24
+ "types": "./air-continents.d.ts",
25
+ "import": "./air-continents.js",
26
+ "default": "./air-continents.js"
27
+ },
23
28
  "./air-search": {
24
29
  "types": "./air-search.d.ts",
25
30
  "import": "./air-search.js",
@@ -65,6 +70,11 @@
65
70
  "import": "./domain/airport.js",
66
71
  "default": "./domain/airport.js"
67
72
  },
73
+ "./domain/movement-board": {
74
+ "types": "./domain/movement-board.d.ts",
75
+ "import": "./domain/movement-board.js",
76
+ "default": "./domain/movement-board.js"
77
+ },
68
78
  "./domain/boundary": {
69
79
  "types": "./domain/boundary.d.ts",
70
80
  "import": "./domain/boundary.js",
@@ -100,6 +110,16 @@
100
110
  "import": "./domain/network-day.js",
101
111
  "default": "./domain/network-day.js"
102
112
  },
113
+ "./domain/network-patterns": {
114
+ "types": "./domain/network-patterns.d.ts",
115
+ "import": "./domain/network-patterns.js",
116
+ "default": "./domain/network-patterns.js"
117
+ },
118
+ "./domain/station-calls": {
119
+ "types": "./domain/station-calls.d.ts",
120
+ "import": "./domain/station-calls.js",
121
+ "default": "./domain/station-calls.js"
122
+ },
103
123
  "./domain/network-layers": {
104
124
  "types": "./domain/network-layers.d.ts",
105
125
  "import": "./domain/network-layers.js",
@@ -139,6 +159,91 @@
139
159
  "types": "./domain/train-time-index.d.ts",
140
160
  "import": "./domain/train-time-index.js",
141
161
  "default": "./domain/train-time-index.js"
162
+ },
163
+ "./domain/live-airport": {
164
+ "types": "./domain/live-airport.d.ts",
165
+ "import": "./domain/live-airport.js",
166
+ "default": "./domain/live-airport.js"
167
+ },
168
+ "./domain/station-departures": {
169
+ "types": "./domain/station-departures.d.ts",
170
+ "import": "./domain/station-departures.js",
171
+ "default": "./domain/station-departures.js"
172
+ },
173
+ "./domain/vehicle-counts": {
174
+ "types": "./domain/vehicle-counts.d.ts",
175
+ "import": "./domain/vehicle-counts.js",
176
+ "default": "./domain/vehicle-counts.js"
177
+ },
178
+ "./domain/aggregate-road": {
179
+ "types": "./domain/aggregate-road.d.ts",
180
+ "import": "./domain/aggregate-road.js",
181
+ "default": "./domain/aggregate-road.js"
182
+ },
183
+ "./domain/vehicle-calls": {
184
+ "types": "./domain/vehicle-calls.d.ts",
185
+ "import": "./domain/vehicle-calls.js",
186
+ "default": "./domain/vehicle-calls.js"
187
+ },
188
+ "./domain/supported-field": {
189
+ "types": "./domain/supported-field.d.ts",
190
+ "import": "./domain/supported-field.js",
191
+ "default": "./domain/supported-field.js"
192
+ },
193
+ "./domain/gridded-series": {
194
+ "types": "./domain/gridded-series.d.ts",
195
+ "import": "./domain/gridded-series.js",
196
+ "default": "./domain/gridded-series.js"
197
+ },
198
+ "./domain/published-day": {
199
+ "types": "./domain/published-day.d.ts",
200
+ "import": "./domain/published-day.js",
201
+ "default": "./domain/published-day.js"
202
+ },
203
+ "./domain/field-paths": {
204
+ "types": "./domain/field-paths.d.ts",
205
+ "import": "./domain/field-paths.js",
206
+ "default": "./domain/field-paths.js"
207
+ },
208
+ "./domain/route-field": {
209
+ "types": "./domain/route-field.d.ts",
210
+ "import": "./domain/route-field.js",
211
+ "default": "./domain/route-field.js"
212
+ },
213
+ "./domain/route-events": {
214
+ "types": "./domain/route-events.d.ts",
215
+ "import": "./domain/route-events.js",
216
+ "default": "./domain/route-events.js"
217
+ },
218
+ "./domain/daylight": {
219
+ "types": "./domain/daylight.d.ts",
220
+ "import": "./domain/daylight.js",
221
+ "default": "./domain/daylight.js"
222
+ },
223
+ "./domain/power-day": {
224
+ "types": "./domain/power-day.d.ts",
225
+ "import": "./domain/power-day.js",
226
+ "default": "./domain/power-day.js"
227
+ },
228
+ "./timeline": {
229
+ "types": "./timeline.d.ts",
230
+ "import": "./timeline.js",
231
+ "default": "./timeline.js"
232
+ },
233
+ "./render-frame": {
234
+ "types": "./render-frame.d.ts",
235
+ "import": "./render-frame.js",
236
+ "default": "./render-frame.js"
237
+ },
238
+ "./map-labels": {
239
+ "types": "./map-labels.d.ts",
240
+ "import": "./map-labels.js",
241
+ "default": "./map-labels.js"
242
+ },
243
+ "./air-enrichment": {
244
+ "types": "./air-enrichment.d.ts",
245
+ "import": "./air-enrichment.js",
246
+ "default": "./air-enrichment.js"
142
247
  }
143
248
  },
144
249
  "files": [
@@ -147,6 +252,8 @@
147
252
  "**/*.d.ts",
148
253
  "**/*.d.mts",
149
254
  "**/*.css",
255
+ "**/*.woff2",
256
+ "**/*-OFL.txt",
150
257
  "README.md",
151
258
  "LICENSE"
152
259
  ],
@@ -0,0 +1,8 @@
1
+ /** Track the last submitted buffers, not the last animation callback. Create a
2
+ * fresh tracker when geometry, projection, data or selection inputs change. */
3
+ export declare class PausedVehicleFrame {
4
+ private time;
5
+ private visibility;
6
+ needsUpdate(isPlaying: boolean, time: number, visibility: number): boolean;
7
+ record(time: number, visibility: number): void;
8
+ }
@@ -0,0 +1,13 @@
1
+ /** Track the last submitted buffers, not the last animation callback. Create a
2
+ * fresh tracker when geometry, projection, data or selection inputs change. */
3
+ export class PausedVehicleFrame {
4
+ time = NaN;
5
+ visibility = NaN;
6
+ needsUpdate(isPlaying, time, visibility) {
7
+ return isPlaying || this.time !== time || this.visibility !== visibility;
8
+ }
9
+ record(time, visibility) {
10
+ this.time = time;
11
+ this.visibility = visibility;
12
+ }
13
+ }
package/timeline.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /** A measured interval. Null means missing evidence; zero is a measured zero. */
2
+ export interface TimelineBin {
3
+ start: number;
4
+ end: number;
5
+ value: number | null;
6
+ }
7
+ export interface TimelineWindow {
8
+ start: number;
9
+ end: number;
10
+ }
11
+ export interface TimelineBar extends TimelineBin {
12
+ x: number;
13
+ width: number;
14
+ height: number;
15
+ }
16
+ export interface TimelineModel {
17
+ window: TimelineWindow;
18
+ maximum: number;
19
+ bars: TimelineBar[];
20
+ lines: {
21
+ x: number;
22
+ y: number;
23
+ }[][];
24
+ }
25
+ export declare function timelinePosition(time: number, window: TimelineWindow): number;
26
+ export declare function timelineTime(position: number, window: TimelineWindow, step?: number): number;
27
+ /** Build chart geometry once per series, independently of playback and rendering. */
28
+ export declare function createTimelineModel(bins: readonly TimelineBin[], window: TimelineWindow, maximum?: number): TimelineModel;
29
+ export declare function timelineBinAt(model: TimelineModel, time: number): TimelineBar | undefined;
30
+ /** Service time, including 24:00 and times beyond midnight; no timezone inference. */
31
+ export declare function formatTimelineTime(seconds: number): string;
package/timeline.js ADDED
@@ -0,0 +1,68 @@
1
+ function checkWindow(window) {
2
+ if (!Number.isFinite(window.start) || !Number.isFinite(window.end) || window.end <= window.start)
3
+ throw new Error('Timeline needs a finite, increasing window');
4
+ }
5
+ export function timelinePosition(time, window) {
6
+ checkWindow(window);
7
+ return Number.isFinite(time) ? Math.max(0, Math.min(1, (time - window.start) / (window.end - window.start))) : 0;
8
+ }
9
+ export function timelineTime(position, window, step = 1) {
10
+ checkWindow(window);
11
+ if (!Number.isFinite(step) || step <= 0)
12
+ throw new Error('Timeline step must be positive');
13
+ const fraction = Number.isFinite(position) ? Math.max(0, Math.min(1, position)) : 0;
14
+ return Math.min(window.end, window.start + Math.round(fraction * (window.end - window.start) / step) * step);
15
+ }
16
+ /** Build chart geometry once per series, independently of playback and rendering. */
17
+ export function createTimelineModel(bins, window, maximum) {
18
+ checkWindow(window);
19
+ if (maximum !== undefined && (!Number.isFinite(maximum) || maximum < 0))
20
+ throw new Error('Timeline maximum must be non-negative');
21
+ const sorted = [...bins].sort((a, b) => a.start - b.start);
22
+ let previous = -Infinity;
23
+ for (const bin of sorted) {
24
+ if (!Number.isFinite(bin.start) || !Number.isFinite(bin.end) || bin.end <= bin.start || bin.start < previous)
25
+ throw new Error('Timeline bins must be finite, increasing and non-overlapping');
26
+ if (bin.value !== null && (!Number.isFinite(bin.value) || bin.value < 0))
27
+ throw new Error('Timeline values must be non-negative or null');
28
+ previous = bin.end;
29
+ }
30
+ const visible = sorted.filter(bin => bin.end > window.start && bin.start < window.end);
31
+ const peak = maximum ?? visible.reduce((value, bin) => Math.max(value, bin.value ?? 0), 0);
32
+ const bars = visible.map(bin => {
33
+ const start = Math.max(window.start, bin.start), end = Math.min(window.end, bin.end);
34
+ return { ...bin, start, end, x: timelinePosition(start, window), width: (end - start) / (window.end - window.start), height: peak > 0 && bin.value !== null ? Math.min(1, bin.value / peak) : 0 };
35
+ });
36
+ const lines = [];
37
+ let line = [], lastEnd = -Infinity;
38
+ for (const bar of bars) {
39
+ if (bar.value === null || bar.start !== lastEnd) {
40
+ if (line.length)
41
+ lines.push(line);
42
+ line = [];
43
+ }
44
+ if (bar.value !== null)
45
+ line.push({ x: bar.x + bar.width / 2, y: 1 - bar.height });
46
+ lastEnd = bar.end;
47
+ }
48
+ if (line.length)
49
+ lines.push(line);
50
+ return { window: { ...window }, maximum: peak, bars, lines };
51
+ }
52
+ export function timelineBinAt(model, time) {
53
+ let lo = 0, hi = model.bars.length;
54
+ while (lo < hi) {
55
+ const mid = (lo + hi) >>> 1;
56
+ if (model.bars[mid].start <= time)
57
+ lo = mid + 1;
58
+ else
59
+ hi = mid;
60
+ }
61
+ const bin = model.bars[lo - 1];
62
+ return bin && time < bin.end ? bin : undefined;
63
+ }
64
+ /** Service time, including 24:00 and times beyond midnight; no timezone inference. */
65
+ export function formatTimelineTime(seconds) {
66
+ const minutes = Math.floor(Math.max(0, Number.isFinite(seconds) ? seconds : 0) / 60);
67
+ return `${String(Math.floor(minutes / 60)).padStart(2, '0')}:${String(minutes % 60).padStart(2, '0')}`;
68
+ }