inkplot 0.0.0-stage → 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +46 -2
- package/dist/adapt.d.ts +10 -0
- package/dist/adapt.js +34 -0
- package/dist/annotation.d.ts +120 -0
- package/dist/annotation.js +267 -0
- package/dist/aria.d.ts +24 -0
- package/dist/aria.js +31 -0
- package/dist/attrs.d.ts +81 -0
- package/dist/attrs.js +84 -0
- package/dist/axis.d.ts +137 -0
- package/dist/axis.js +185 -0
- package/dist/bars.d.ts +80 -0
- package/dist/bars.js +255 -0
- package/dist/boxplot.d.ts +57 -0
- package/dist/boxplot.js +177 -0
- package/dist/boxzoom.d.ts +39 -0
- package/dist/boxzoom.js +138 -0
- package/dist/brush.d.ts +60 -0
- package/dist/brush.js +185 -0
- package/dist/bucket.d.ts +22 -0
- package/dist/bucket.js +62 -0
- package/dist/callout.d.ts +30 -0
- package/dist/callout.js +98 -0
- package/dist/chart.d.ts +126 -0
- package/dist/chart.js +257 -0
- package/dist/crosshair.d.ts +28 -0
- package/dist/crosshair.js +78 -0
- package/dist/cursor.d.ts +76 -0
- package/dist/cursor.js +344 -0
- package/dist/curve.d.ts +50 -0
- package/dist/curve.js +87 -0
- package/dist/curves.d.ts +104 -0
- package/dist/curves.js +375 -0
- package/dist/data.d.ts +209 -0
- package/dist/data.js +276 -0
- package/dist/decimation.d.ts +86 -0
- package/dist/decimation.js +410 -0
- package/dist/density.d.ts +55 -0
- package/dist/density.js +252 -0
- package/dist/dimension.d.ts +103 -0
- package/dist/dimension.js +205 -0
- package/dist/dom-platform.d.ts +53 -0
- package/dist/dom-platform.js +190 -0
- package/dist/element.d.ts +232 -0
- package/dist/element.js +414 -0
- package/dist/errors.d.ts +85 -0
- package/dist/errors.js +237 -0
- package/dist/events.d.ts +144 -0
- package/dist/events.js +19 -0
- package/dist/focus.d.ts +22 -0
- package/dist/focus.js +51 -0
- package/dist/furniture.d.ts +70 -0
- package/dist/furniture.js +166 -0
- package/dist/geometry.d.ts +40 -0
- package/dist/geometry.js +7 -0
- package/dist/heatmap.d.ts +57 -0
- package/dist/heatmap.js +207 -0
- package/dist/hit.d.ts +103 -0
- package/dist/hit.js +428 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +73 -0
- package/dist/input.d.ts +42 -0
- package/dist/input.js +166 -0
- package/dist/jsx-dev-runtime.d.ts +9 -0
- package/dist/jsx-dev-runtime.js +13 -0
- package/dist/jsx-runtime.d.ts +59 -0
- package/dist/jsx-runtime.js +81 -0
- package/dist/key.d.ts +118 -0
- package/dist/key.js +199 -0
- package/dist/legend.d.ts +36 -0
- package/dist/legend.js +220 -0
- package/dist/mapped.d.ts +80 -0
- package/dist/mapped.js +106 -0
- package/dist/marker.d.ts +143 -0
- package/dist/marker.js +213 -0
- package/dist/panzoom.d.ts +119 -0
- package/dist/panzoom.js +467 -0
- package/dist/plane.d.ts +173 -0
- package/dist/plane.js +370 -0
- package/dist/platform.d.ts +113 -0
- package/dist/platform.js +80 -0
- package/dist/png.d.ts +44 -0
- package/dist/png.js +71 -0
- package/dist/pointer.d.ts +54 -0
- package/dist/pointer.js +132 -0
- package/dist/quantile.d.ts +3 -0
- package/dist/quantile.js +11 -0
- package/dist/radial.d.ts +116 -0
- package/dist/radial.js +336 -0
- package/dist/react.d.ts +441 -0
- package/dist/react.js +252 -0
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +51 -0
- package/dist/renderer.d.ts +191 -0
- package/dist/renderer.js +164 -0
- package/dist/scale.d.ts +37 -0
- package/dist/scale.js +19 -0
- package/dist/scales.d.ts +69 -0
- package/dist/scales.js +134 -0
- package/dist/serialize.d.ts +77 -0
- package/dist/serialize.js +321 -0
- package/dist/series.d.ts +304 -0
- package/dist/series.js +513 -0
- package/dist/simple.d.ts +35 -0
- package/dist/simple.js +20 -0
- package/dist/sources.d.ts +116 -0
- package/dist/sources.js +237 -0
- package/dist/stack.d.ts +61 -0
- package/dist/stack.js +172 -0
- package/dist/stats.d.ts +38 -0
- package/dist/stats.js +159 -0
- package/dist/steps.d.ts +50 -0
- package/dist/steps.js +154 -0
- package/dist/stub.d.ts +3 -0
- package/dist/stub.js +5 -0
- package/dist/style-names.d.ts +1 -0
- package/dist/style-names.js +6 -0
- package/dist/summary.d.ts +44 -0
- package/dist/summary.js +58 -0
- package/dist/surface.d.ts +94 -0
- package/dist/surface.js +145 -0
- package/dist/table.d.ts +39 -0
- package/dist/table.js +37 -0
- package/dist/text.d.ts +23 -0
- package/dist/text.js +44 -0
- package/dist/theme.d.ts +174 -0
- package/dist/theme.js +73 -0
- package/dist/themes.d.ts +9 -0
- package/dist/themes.js +56 -0
- package/dist/time-intl.d.ts +194 -0
- package/dist/time-intl.js +144 -0
- package/dist/time-temporal.d.ts +236 -0
- package/dist/time-temporal.js +58 -0
- package/dist/time.d.ts +216 -0
- package/dist/time.js +154 -0
- package/dist/trend.d.ts +151 -0
- package/dist/trend.js +500 -0
- package/dist/web-components.d.ts +62 -0
- package/dist/web-components.js +264 -0
- package/package.json +53 -3
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { TimeScale, type TimeRank, type TimeScaleAttributes, type TimeUnit } from './time.ts';
|
|
2
|
+
export interface IntlTimeScaleAttributes extends TimeScaleAttributes<Intl.DateTimeFormatOptions> {
|
|
3
|
+
/** The language the labels are written in (a BCP 47 tag). Default: the runtime's. */
|
|
4
|
+
locale?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class IntlTimeScale extends TimeScale<Intl.DateTimeFormatOptions, IntlTimeScaleAttributes> {
|
|
7
|
+
#private;
|
|
8
|
+
static attrTypes: {
|
|
9
|
+
id: 1;
|
|
10
|
+
meta: {
|
|
11
|
+
title: 1;
|
|
12
|
+
description: 1;
|
|
13
|
+
role: 1;
|
|
14
|
+
};
|
|
15
|
+
timeZone: 1;
|
|
16
|
+
weekStart: 2;
|
|
17
|
+
locale: 1;
|
|
18
|
+
formats: {
|
|
19
|
+
year: {
|
|
20
|
+
localeMatcher: 1;
|
|
21
|
+
timeZone: 1;
|
|
22
|
+
hourCycle: 1;
|
|
23
|
+
formatMatcher: 1;
|
|
24
|
+
dateStyle: 1;
|
|
25
|
+
timeStyle: 1;
|
|
26
|
+
dayPeriod: 1;
|
|
27
|
+
fractionalSecondDigits: 0;
|
|
28
|
+
calendar: 1;
|
|
29
|
+
numberingSystem: 1;
|
|
30
|
+
weekday: 1;
|
|
31
|
+
era: 1;
|
|
32
|
+
year: 1;
|
|
33
|
+
month: 1;
|
|
34
|
+
day: 1;
|
|
35
|
+
hour: 1;
|
|
36
|
+
minute: 1;
|
|
37
|
+
second: 1;
|
|
38
|
+
timeZoneName: 1;
|
|
39
|
+
};
|
|
40
|
+
month: {
|
|
41
|
+
localeMatcher: 1;
|
|
42
|
+
timeZone: 1;
|
|
43
|
+
hourCycle: 1;
|
|
44
|
+
formatMatcher: 1;
|
|
45
|
+
dateStyle: 1;
|
|
46
|
+
timeStyle: 1;
|
|
47
|
+
dayPeriod: 1;
|
|
48
|
+
fractionalSecondDigits: 0;
|
|
49
|
+
calendar: 1;
|
|
50
|
+
numberingSystem: 1;
|
|
51
|
+
weekday: 1;
|
|
52
|
+
era: 1;
|
|
53
|
+
year: 1;
|
|
54
|
+
month: 1;
|
|
55
|
+
day: 1;
|
|
56
|
+
hour: 1;
|
|
57
|
+
minute: 1;
|
|
58
|
+
second: 1;
|
|
59
|
+
timeZoneName: 1;
|
|
60
|
+
};
|
|
61
|
+
day: {
|
|
62
|
+
localeMatcher: 1;
|
|
63
|
+
timeZone: 1;
|
|
64
|
+
hourCycle: 1;
|
|
65
|
+
formatMatcher: 1;
|
|
66
|
+
dateStyle: 1;
|
|
67
|
+
timeStyle: 1;
|
|
68
|
+
dayPeriod: 1;
|
|
69
|
+
fractionalSecondDigits: 0;
|
|
70
|
+
calendar: 1;
|
|
71
|
+
numberingSystem: 1;
|
|
72
|
+
weekday: 1;
|
|
73
|
+
era: 1;
|
|
74
|
+
year: 1;
|
|
75
|
+
month: 1;
|
|
76
|
+
day: 1;
|
|
77
|
+
hour: 1;
|
|
78
|
+
minute: 1;
|
|
79
|
+
second: 1;
|
|
80
|
+
timeZoneName: 1;
|
|
81
|
+
};
|
|
82
|
+
hour: {
|
|
83
|
+
localeMatcher: 1;
|
|
84
|
+
timeZone: 1;
|
|
85
|
+
hourCycle: 1;
|
|
86
|
+
formatMatcher: 1;
|
|
87
|
+
dateStyle: 1;
|
|
88
|
+
timeStyle: 1;
|
|
89
|
+
dayPeriod: 1;
|
|
90
|
+
fractionalSecondDigits: 0;
|
|
91
|
+
calendar: 1;
|
|
92
|
+
numberingSystem: 1;
|
|
93
|
+
weekday: 1;
|
|
94
|
+
era: 1;
|
|
95
|
+
year: 1;
|
|
96
|
+
month: 1;
|
|
97
|
+
day: 1;
|
|
98
|
+
hour: 1;
|
|
99
|
+
minute: 1;
|
|
100
|
+
second: 1;
|
|
101
|
+
timeZoneName: 1;
|
|
102
|
+
};
|
|
103
|
+
minute: {
|
|
104
|
+
localeMatcher: 1;
|
|
105
|
+
timeZone: 1;
|
|
106
|
+
hourCycle: 1;
|
|
107
|
+
formatMatcher: 1;
|
|
108
|
+
dateStyle: 1;
|
|
109
|
+
timeStyle: 1;
|
|
110
|
+
dayPeriod: 1;
|
|
111
|
+
fractionalSecondDigits: 0;
|
|
112
|
+
calendar: 1;
|
|
113
|
+
numberingSystem: 1;
|
|
114
|
+
weekday: 1;
|
|
115
|
+
era: 1;
|
|
116
|
+
year: 1;
|
|
117
|
+
month: 1;
|
|
118
|
+
day: 1;
|
|
119
|
+
hour: 1;
|
|
120
|
+
minute: 1;
|
|
121
|
+
second: 1;
|
|
122
|
+
timeZoneName: 1;
|
|
123
|
+
};
|
|
124
|
+
second: {
|
|
125
|
+
localeMatcher: 1;
|
|
126
|
+
timeZone: 1;
|
|
127
|
+
hourCycle: 1;
|
|
128
|
+
formatMatcher: 1;
|
|
129
|
+
dateStyle: 1;
|
|
130
|
+
timeStyle: 1;
|
|
131
|
+
dayPeriod: 1;
|
|
132
|
+
fractionalSecondDigits: 0;
|
|
133
|
+
calendar: 1;
|
|
134
|
+
numberingSystem: 1;
|
|
135
|
+
weekday: 1;
|
|
136
|
+
era: 1;
|
|
137
|
+
year: 1;
|
|
138
|
+
month: 1;
|
|
139
|
+
day: 1;
|
|
140
|
+
hour: 1;
|
|
141
|
+
minute: 1;
|
|
142
|
+
second: 1;
|
|
143
|
+
timeZoneName: 1;
|
|
144
|
+
};
|
|
145
|
+
millisecond: {
|
|
146
|
+
localeMatcher: 1;
|
|
147
|
+
timeZone: 1;
|
|
148
|
+
hourCycle: 1;
|
|
149
|
+
formatMatcher: 1;
|
|
150
|
+
dateStyle: 1;
|
|
151
|
+
timeStyle: 1;
|
|
152
|
+
dayPeriod: 1;
|
|
153
|
+
fractionalSecondDigits: 0;
|
|
154
|
+
calendar: 1;
|
|
155
|
+
numberingSystem: 1;
|
|
156
|
+
weekday: 1;
|
|
157
|
+
era: 1;
|
|
158
|
+
year: 1;
|
|
159
|
+
month: 1;
|
|
160
|
+
day: 1;
|
|
161
|
+
hour: 1;
|
|
162
|
+
minute: 1;
|
|
163
|
+
second: 1;
|
|
164
|
+
timeZoneName: 1;
|
|
165
|
+
};
|
|
166
|
+
full: {
|
|
167
|
+
localeMatcher: 1;
|
|
168
|
+
timeZone: 1;
|
|
169
|
+
hourCycle: 1;
|
|
170
|
+
formatMatcher: 1;
|
|
171
|
+
dateStyle: 1;
|
|
172
|
+
timeStyle: 1;
|
|
173
|
+
dayPeriod: 1;
|
|
174
|
+
fractionalSecondDigits: 0;
|
|
175
|
+
calendar: 1;
|
|
176
|
+
numberingSystem: 1;
|
|
177
|
+
weekday: 1;
|
|
178
|
+
era: 1;
|
|
179
|
+
year: 1;
|
|
180
|
+
month: 1;
|
|
181
|
+
day: 1;
|
|
182
|
+
hour: 1;
|
|
183
|
+
minute: 1;
|
|
184
|
+
second: 1;
|
|
185
|
+
timeZoneName: 1;
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
protected get defaultFormats(): Record<TimeRank, Intl.DateTimeFormatOptions>;
|
|
190
|
+
protected startOf(t: number, unit: TimeUnit): number;
|
|
191
|
+
protected add(t: number, unit: TimeUnit, n: number): number;
|
|
192
|
+
protected field(t: number, unit: Exclude<TimeUnit, 'week'>): number;
|
|
193
|
+
protected format(t: number, _rank: TimeRank, spec: Intl.DateTimeFormatOptions): string;
|
|
194
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `IntlTimeScale`: a time scale over `Date` and `Intl`, with nothing to install. The time zone, whatever it is, is worked out
|
|
3
|
+
* with `Intl.DateTimeFormat` (the wall-clock time of an instant, and so the offset from UTC at it), so any IANA zone works
|
|
4
|
+
* and daylight saving is followed. Where a wall-clock time does not exist (the hour the clocks skip) or occurs twice, the
|
|
5
|
+
* instant nearest to it is used.
|
|
6
|
+
*
|
|
7
|
+
* `formats` are `Intl.DateTimeFormatOptions`, and `locale` a BCP 47 tag (default: the runtime's).
|
|
8
|
+
*/
|
|
9
|
+
import { STRING } from './attrs.js';
|
|
10
|
+
import { TimeScale, TIME_FORMATS_TYPES } from './time.js';
|
|
11
|
+
const clock = { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' };
|
|
12
|
+
const DEFAULTS = {
|
|
13
|
+
year: { year: 'numeric' },
|
|
14
|
+
month: { month: 'short' },
|
|
15
|
+
day: { month: 'short', day: 'numeric' },
|
|
16
|
+
hour: clock,
|
|
17
|
+
minute: clock,
|
|
18
|
+
second: { ...clock, second: '2-digit' },
|
|
19
|
+
millisecond: { ...clock, second: '2-digit', fractionalSecondDigits: 3 },
|
|
20
|
+
full: { year: 'numeric', month: 'short', day: 'numeric', ...clock, second: '2-digit', timeZoneName: 'short' },
|
|
21
|
+
};
|
|
22
|
+
let local;
|
|
23
|
+
const zones = new Map();
|
|
24
|
+
function clockIn(zone) {
|
|
25
|
+
let f = zones.get(zone);
|
|
26
|
+
if (!f) {
|
|
27
|
+
f = new Intl.DateTimeFormat('en-US', { timeZone: zone, calendar: 'iso8601', numberingSystem: 'latn', hourCycle: 'h23', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });
|
|
28
|
+
zones.set(zone, f);
|
|
29
|
+
}
|
|
30
|
+
return f;
|
|
31
|
+
}
|
|
32
|
+
const utc = (w) => { const d = new Date(0); d.setUTCFullYear(w.y, w.mo - 1, w.d); d.setUTCHours(w.h, w.mi, w.s, 0); return d.getTime(); };
|
|
33
|
+
export class IntlTimeScale extends TimeScale {
|
|
34
|
+
static attrTypes = { ...TimeScale.attrTypes, locale: STRING, formats: TIME_FORMATS_TYPES };
|
|
35
|
+
get defaultFormats() { return DEFAULTS; }
|
|
36
|
+
get #zone() {
|
|
37
|
+
const z = this.attrs.timeZone ?? 'UTC';
|
|
38
|
+
return z === 'local' ? (local ??= new Intl.DateTimeFormat().resolvedOptions().timeZone) : z;
|
|
39
|
+
}
|
|
40
|
+
/** The wall-clock time at `t` in the zone. */
|
|
41
|
+
#wall(t) {
|
|
42
|
+
if (this.#zone === 'UTC') {
|
|
43
|
+
const d = new Date(t);
|
|
44
|
+
return { y: d.getUTCFullYear(), mo: d.getUTCMonth() + 1, d: d.getUTCDate(), h: d.getUTCHours(), mi: d.getUTCMinutes(), s: d.getUTCSeconds() };
|
|
45
|
+
}
|
|
46
|
+
const w = { y: 0, mo: 0, d: 0, h: 0, mi: 0, s: 0 };
|
|
47
|
+
for (const p of clockIn(this.#zone).formatToParts(t)) {
|
|
48
|
+
switch (p.type) {
|
|
49
|
+
case 'year':
|
|
50
|
+
w.y = +p.value;
|
|
51
|
+
break;
|
|
52
|
+
case 'month':
|
|
53
|
+
w.mo = +p.value;
|
|
54
|
+
break;
|
|
55
|
+
case 'day':
|
|
56
|
+
w.d = +p.value;
|
|
57
|
+
break;
|
|
58
|
+
case 'hour':
|
|
59
|
+
w.h = +p.value;
|
|
60
|
+
break;
|
|
61
|
+
case 'minute':
|
|
62
|
+
w.mi = +p.value;
|
|
63
|
+
break;
|
|
64
|
+
case 'second':
|
|
65
|
+
w.s = +p.value;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return w;
|
|
70
|
+
}
|
|
71
|
+
/** The zone's offset from UTC at `t`, in milliseconds. */
|
|
72
|
+
#offset(t) { return utc(this.#wall(t)) - Math.floor(t / 1000) * 1000; }
|
|
73
|
+
/** The instant a wall-clock time shows (days, months and so on beyond their range carry over). */
|
|
74
|
+
#at(w) {
|
|
75
|
+
const wall = utc(w);
|
|
76
|
+
if (this.#zone === 'UTC')
|
|
77
|
+
return wall;
|
|
78
|
+
let t = wall - this.#offset(wall);
|
|
79
|
+
const o = this.#offset(t);
|
|
80
|
+
if (wall - t !== o)
|
|
81
|
+
t = wall - o;
|
|
82
|
+
return t;
|
|
83
|
+
}
|
|
84
|
+
startOf(t, unit) {
|
|
85
|
+
const ms = ((t % 1000) + 1000) % 1000;
|
|
86
|
+
switch (unit) {
|
|
87
|
+
case 'second': return t - ms;
|
|
88
|
+
case 'minute': {
|
|
89
|
+
const w = this.#wall(t);
|
|
90
|
+
return t - ms - w.s * 1000;
|
|
91
|
+
}
|
|
92
|
+
case 'hour': {
|
|
93
|
+
const w = this.#wall(t);
|
|
94
|
+
return t - ms - w.s * 1000 - w.mi * 60000;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const w = this.#wall(t);
|
|
98
|
+
switch (unit) {
|
|
99
|
+
case 'day': return this.#at({ ...w, h: 0, mi: 0, s: 0 });
|
|
100
|
+
case 'week': {
|
|
101
|
+
const dow = new Date(utc({ ...w, h: 0, mi: 0, s: 0 })).getUTCDay(); // the weekday of the date, read as if it were UTC
|
|
102
|
+
return this.#at({ ...w, d: w.d - ((dow - this.weekStart + 7) % 7), h: 0, mi: 0, s: 0 });
|
|
103
|
+
}
|
|
104
|
+
case 'month': return this.#at({ ...w, d: 1, h: 0, mi: 0, s: 0 });
|
|
105
|
+
default: return this.#at({ ...w, mo: 1, d: 1, h: 0, mi: 0, s: 0 });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
add(t, unit, n) {
|
|
109
|
+
switch (unit) {
|
|
110
|
+
case 'second': return t + n * 1000;
|
|
111
|
+
case 'minute': return t + n * 60000;
|
|
112
|
+
case 'hour': return t + n * 3600000;
|
|
113
|
+
}
|
|
114
|
+
const w = this.#wall(t);
|
|
115
|
+
switch (unit) {
|
|
116
|
+
case 'day': return this.#at({ ...w, d: w.d + n });
|
|
117
|
+
case 'week': return this.#at({ ...w, d: w.d + 7 * n });
|
|
118
|
+
case 'month': return this.#at({ ...w, mo: w.mo + n });
|
|
119
|
+
default: return this.#at({ ...w, y: w.y + n });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
field(t, unit) {
|
|
123
|
+
const w = this.#wall(t);
|
|
124
|
+
switch (unit) {
|
|
125
|
+
case 'year': return w.y;
|
|
126
|
+
case 'month': return w.mo - 1;
|
|
127
|
+
case 'day': return w.d;
|
|
128
|
+
case 'hour': return w.h;
|
|
129
|
+
case 'minute': return w.mi;
|
|
130
|
+
default: return w.s;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
#formats = new Map();
|
|
134
|
+
format(t, _rank, spec) {
|
|
135
|
+
const locale = this.attrs.locale ?? this.chart?.attrs.locale;
|
|
136
|
+
const key = `${locale}|${this.#zone}|${JSON.stringify(spec)}`;
|
|
137
|
+
let f = this.#formats.get(key);
|
|
138
|
+
if (!f) {
|
|
139
|
+
f = new Intl.DateTimeFormat(locale, { ...spec, timeZone: this.#zone });
|
|
140
|
+
this.#formats.set(key, f);
|
|
141
|
+
}
|
|
142
|
+
return f.format(t);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `TemporalTimeScale`: a time scale over `Temporal`, which does the calendar and the time zones itself. Daylight saving, skipped
|
|
3
|
+
* and repeated hours and non-hour offsets are `Temporal`'s own.
|
|
4
|
+
*
|
|
5
|
+
* Uses the runtime's `Temporal`, or the one given as the `temporal` attribute (the namespace of a polyfill: a reference to a
|
|
6
|
+
* live object, not text, so a chart loaded from JSON takes it from its references like any other). `formats` are
|
|
7
|
+
* `Intl.DateTimeFormatOptions` for `toLocaleString`, without a `timeZone` (the instant brings its own), and `locale` a BCP 47 tag.
|
|
8
|
+
*/
|
|
9
|
+
import { type Opaque } from './attrs.ts';
|
|
10
|
+
import { TimeScale, type TimeRank, type TimeScaleAttributes, type TimeUnit } from './time.ts';
|
|
11
|
+
/** The part of a `Temporal.ZonedDateTime` that this uses. */
|
|
12
|
+
export interface ZonedLike {
|
|
13
|
+
readonly year: number;
|
|
14
|
+
readonly month: number;
|
|
15
|
+
readonly day: number;
|
|
16
|
+
readonly hour: number;
|
|
17
|
+
readonly minute: number;
|
|
18
|
+
readonly second: number;
|
|
19
|
+
readonly dayOfWeek: number;
|
|
20
|
+
readonly epochMilliseconds: number;
|
|
21
|
+
with(fields: Record<string, number>): ZonedLike;
|
|
22
|
+
add(duration: Record<string, number>): ZonedLike;
|
|
23
|
+
subtract(duration: Record<string, number>): ZonedLike;
|
|
24
|
+
round(options: {
|
|
25
|
+
smallestUnit: string;
|
|
26
|
+
roundingMode: string;
|
|
27
|
+
}): ZonedLike;
|
|
28
|
+
startOfDay(): ZonedLike;
|
|
29
|
+
toLocaleString(locale?: string, options?: Intl.DateTimeFormatOptions): string;
|
|
30
|
+
}
|
|
31
|
+
/** The part of the `Temporal` namespace that this uses. */
|
|
32
|
+
export interface TemporalLike {
|
|
33
|
+
Instant: {
|
|
34
|
+
fromEpochMilliseconds(ms: number): {
|
|
35
|
+
toZonedDateTimeISO(zone: string): ZonedLike;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
Now: {
|
|
39
|
+
timeZoneId(): string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface TemporalTimeScaleAttributes extends TimeScaleAttributes<Intl.DateTimeFormatOptions> {
|
|
43
|
+
/** The language the labels are written in (a BCP 47 tag). Default: the runtime's. */
|
|
44
|
+
locale?: string;
|
|
45
|
+
/** Where `Temporal` comes from, when the runtime has none. */
|
|
46
|
+
temporal?: Opaque<TemporalLike>;
|
|
47
|
+
}
|
|
48
|
+
export declare class TemporalTimeScale extends TimeScale<Intl.DateTimeFormatOptions, TemporalTimeScaleAttributes> {
|
|
49
|
+
#private;
|
|
50
|
+
static attrTypes: {
|
|
51
|
+
id: 1;
|
|
52
|
+
meta: {
|
|
53
|
+
title: 1;
|
|
54
|
+
description: 1;
|
|
55
|
+
role: 1;
|
|
56
|
+
};
|
|
57
|
+
timeZone: 1;
|
|
58
|
+
weekStart: 2;
|
|
59
|
+
locale: 1;
|
|
60
|
+
formats: {
|
|
61
|
+
year: {
|
|
62
|
+
localeMatcher: 1;
|
|
63
|
+
timeZone: 1;
|
|
64
|
+
hourCycle: 1;
|
|
65
|
+
formatMatcher: 1;
|
|
66
|
+
dateStyle: 1;
|
|
67
|
+
timeStyle: 1;
|
|
68
|
+
dayPeriod: 1;
|
|
69
|
+
fractionalSecondDigits: 0;
|
|
70
|
+
calendar: 1;
|
|
71
|
+
numberingSystem: 1;
|
|
72
|
+
weekday: 1;
|
|
73
|
+
era: 1;
|
|
74
|
+
year: 1;
|
|
75
|
+
month: 1;
|
|
76
|
+
day: 1;
|
|
77
|
+
hour: 1;
|
|
78
|
+
minute: 1;
|
|
79
|
+
second: 1;
|
|
80
|
+
timeZoneName: 1;
|
|
81
|
+
};
|
|
82
|
+
month: {
|
|
83
|
+
localeMatcher: 1;
|
|
84
|
+
timeZone: 1;
|
|
85
|
+
hourCycle: 1;
|
|
86
|
+
formatMatcher: 1;
|
|
87
|
+
dateStyle: 1;
|
|
88
|
+
timeStyle: 1;
|
|
89
|
+
dayPeriod: 1;
|
|
90
|
+
fractionalSecondDigits: 0;
|
|
91
|
+
calendar: 1;
|
|
92
|
+
numberingSystem: 1;
|
|
93
|
+
weekday: 1;
|
|
94
|
+
era: 1;
|
|
95
|
+
year: 1;
|
|
96
|
+
month: 1;
|
|
97
|
+
day: 1;
|
|
98
|
+
hour: 1;
|
|
99
|
+
minute: 1;
|
|
100
|
+
second: 1;
|
|
101
|
+
timeZoneName: 1;
|
|
102
|
+
};
|
|
103
|
+
day: {
|
|
104
|
+
localeMatcher: 1;
|
|
105
|
+
timeZone: 1;
|
|
106
|
+
hourCycle: 1;
|
|
107
|
+
formatMatcher: 1;
|
|
108
|
+
dateStyle: 1;
|
|
109
|
+
timeStyle: 1;
|
|
110
|
+
dayPeriod: 1;
|
|
111
|
+
fractionalSecondDigits: 0;
|
|
112
|
+
calendar: 1;
|
|
113
|
+
numberingSystem: 1;
|
|
114
|
+
weekday: 1;
|
|
115
|
+
era: 1;
|
|
116
|
+
year: 1;
|
|
117
|
+
month: 1;
|
|
118
|
+
day: 1;
|
|
119
|
+
hour: 1;
|
|
120
|
+
minute: 1;
|
|
121
|
+
second: 1;
|
|
122
|
+
timeZoneName: 1;
|
|
123
|
+
};
|
|
124
|
+
hour: {
|
|
125
|
+
localeMatcher: 1;
|
|
126
|
+
timeZone: 1;
|
|
127
|
+
hourCycle: 1;
|
|
128
|
+
formatMatcher: 1;
|
|
129
|
+
dateStyle: 1;
|
|
130
|
+
timeStyle: 1;
|
|
131
|
+
dayPeriod: 1;
|
|
132
|
+
fractionalSecondDigits: 0;
|
|
133
|
+
calendar: 1;
|
|
134
|
+
numberingSystem: 1;
|
|
135
|
+
weekday: 1;
|
|
136
|
+
era: 1;
|
|
137
|
+
year: 1;
|
|
138
|
+
month: 1;
|
|
139
|
+
day: 1;
|
|
140
|
+
hour: 1;
|
|
141
|
+
minute: 1;
|
|
142
|
+
second: 1;
|
|
143
|
+
timeZoneName: 1;
|
|
144
|
+
};
|
|
145
|
+
minute: {
|
|
146
|
+
localeMatcher: 1;
|
|
147
|
+
timeZone: 1;
|
|
148
|
+
hourCycle: 1;
|
|
149
|
+
formatMatcher: 1;
|
|
150
|
+
dateStyle: 1;
|
|
151
|
+
timeStyle: 1;
|
|
152
|
+
dayPeriod: 1;
|
|
153
|
+
fractionalSecondDigits: 0;
|
|
154
|
+
calendar: 1;
|
|
155
|
+
numberingSystem: 1;
|
|
156
|
+
weekday: 1;
|
|
157
|
+
era: 1;
|
|
158
|
+
year: 1;
|
|
159
|
+
month: 1;
|
|
160
|
+
day: 1;
|
|
161
|
+
hour: 1;
|
|
162
|
+
minute: 1;
|
|
163
|
+
second: 1;
|
|
164
|
+
timeZoneName: 1;
|
|
165
|
+
};
|
|
166
|
+
second: {
|
|
167
|
+
localeMatcher: 1;
|
|
168
|
+
timeZone: 1;
|
|
169
|
+
hourCycle: 1;
|
|
170
|
+
formatMatcher: 1;
|
|
171
|
+
dateStyle: 1;
|
|
172
|
+
timeStyle: 1;
|
|
173
|
+
dayPeriod: 1;
|
|
174
|
+
fractionalSecondDigits: 0;
|
|
175
|
+
calendar: 1;
|
|
176
|
+
numberingSystem: 1;
|
|
177
|
+
weekday: 1;
|
|
178
|
+
era: 1;
|
|
179
|
+
year: 1;
|
|
180
|
+
month: 1;
|
|
181
|
+
day: 1;
|
|
182
|
+
hour: 1;
|
|
183
|
+
minute: 1;
|
|
184
|
+
second: 1;
|
|
185
|
+
timeZoneName: 1;
|
|
186
|
+
};
|
|
187
|
+
millisecond: {
|
|
188
|
+
localeMatcher: 1;
|
|
189
|
+
timeZone: 1;
|
|
190
|
+
hourCycle: 1;
|
|
191
|
+
formatMatcher: 1;
|
|
192
|
+
dateStyle: 1;
|
|
193
|
+
timeStyle: 1;
|
|
194
|
+
dayPeriod: 1;
|
|
195
|
+
fractionalSecondDigits: 0;
|
|
196
|
+
calendar: 1;
|
|
197
|
+
numberingSystem: 1;
|
|
198
|
+
weekday: 1;
|
|
199
|
+
era: 1;
|
|
200
|
+
year: 1;
|
|
201
|
+
month: 1;
|
|
202
|
+
day: 1;
|
|
203
|
+
hour: 1;
|
|
204
|
+
minute: 1;
|
|
205
|
+
second: 1;
|
|
206
|
+
timeZoneName: 1;
|
|
207
|
+
};
|
|
208
|
+
full: {
|
|
209
|
+
localeMatcher: 1;
|
|
210
|
+
timeZone: 1;
|
|
211
|
+
hourCycle: 1;
|
|
212
|
+
formatMatcher: 1;
|
|
213
|
+
dateStyle: 1;
|
|
214
|
+
timeStyle: 1;
|
|
215
|
+
dayPeriod: 1;
|
|
216
|
+
fractionalSecondDigits: 0;
|
|
217
|
+
calendar: 1;
|
|
218
|
+
numberingSystem: 1;
|
|
219
|
+
weekday: 1;
|
|
220
|
+
era: 1;
|
|
221
|
+
year: 1;
|
|
222
|
+
month: 1;
|
|
223
|
+
day: 1;
|
|
224
|
+
hour: 1;
|
|
225
|
+
minute: 1;
|
|
226
|
+
second: 1;
|
|
227
|
+
timeZoneName: 1;
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
protected get defaultFormats(): Record<TimeRank, Intl.DateTimeFormatOptions>;
|
|
232
|
+
protected startOf(t: number, unit: TimeUnit): number;
|
|
233
|
+
protected add(t: number, unit: TimeUnit, n: number): number;
|
|
234
|
+
protected field(t: number, unit: Exclude<TimeUnit, 'week'>): number;
|
|
235
|
+
protected format(t: number, _rank: TimeRank, spec: Intl.DateTimeFormatOptions): string;
|
|
236
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `TemporalTimeScale`: a time scale over `Temporal`, which does the calendar and the time zones itself. Daylight saving, skipped
|
|
3
|
+
* and repeated hours and non-hour offsets are `Temporal`'s own.
|
|
4
|
+
*
|
|
5
|
+
* Uses the runtime's `Temporal`, or the one given as the `temporal` attribute (the namespace of a polyfill: a reference to a
|
|
6
|
+
* live object, not text, so a chart loaded from JSON takes it from its references like any other). `formats` are
|
|
7
|
+
* `Intl.DateTimeFormatOptions` for `toLocaleString`, without a `timeZone` (the instant brings its own), and `locale` a BCP 47 tag.
|
|
8
|
+
*/
|
|
9
|
+
import { STRING } from './attrs.js';
|
|
10
|
+
import { TimeScale, TIME_FORMATS_TYPES } from './time.js';
|
|
11
|
+
const clock = { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' };
|
|
12
|
+
const DEFAULTS = {
|
|
13
|
+
year: { year: 'numeric' },
|
|
14
|
+
month: { month: 'short' },
|
|
15
|
+
day: { month: 'short', day: 'numeric' },
|
|
16
|
+
hour: clock,
|
|
17
|
+
minute: clock,
|
|
18
|
+
second: { ...clock, second: '2-digit' },
|
|
19
|
+
millisecond: { ...clock, second: '2-digit', fractionalSecondDigits: 3 },
|
|
20
|
+
full: { year: 'numeric', month: 'short', day: 'numeric', ...clock, second: '2-digit', timeZoneName: 'short' },
|
|
21
|
+
};
|
|
22
|
+
export class TemporalTimeScale extends TimeScale {
|
|
23
|
+
static attrTypes = { ...TimeScale.attrTypes, locale: STRING, formats: TIME_FORMATS_TYPES };
|
|
24
|
+
get defaultFormats() { return DEFAULTS; }
|
|
25
|
+
get #temporal() {
|
|
26
|
+
// oxlint-disable-next-line typescript/consistent-type-assertions -- `Temporal` is not in every runtime's global types
|
|
27
|
+
const T = this.attrs.temporal ?? globalThis.Temporal;
|
|
28
|
+
if (!T)
|
|
29
|
+
throw new Error('TemporalTimeScale: this runtime has no Temporal; pass one as the `temporal` attribute, or use IntlTimeScale');
|
|
30
|
+
return T;
|
|
31
|
+
}
|
|
32
|
+
#at(t) {
|
|
33
|
+
const T = this.#temporal, z = this.attrs.timeZone ?? 'UTC';
|
|
34
|
+
return T.Instant.fromEpochMilliseconds(Math.floor(t)).toZonedDateTimeISO(z === 'local' ? T.Now.timeZoneId() : z);
|
|
35
|
+
}
|
|
36
|
+
startOf(t, unit) {
|
|
37
|
+
const z = this.#at(t);
|
|
38
|
+
switch (unit) {
|
|
39
|
+
case 'second':
|
|
40
|
+
case 'minute':
|
|
41
|
+
case 'hour': return z.round({ smallestUnit: unit, roundingMode: 'floor' }).epochMilliseconds;
|
|
42
|
+
case 'day': return z.startOfDay().epochMilliseconds;
|
|
43
|
+
case 'week': return z.subtract({ days: (z.dayOfWeek % 7 - this.weekStart + 7) % 7 }).startOfDay().epochMilliseconds;
|
|
44
|
+
case 'month': return z.with({ day: 1 }).startOfDay().epochMilliseconds;
|
|
45
|
+
default: return z.with({ month: 1, day: 1 }).startOfDay().epochMilliseconds;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
add(t, unit, n) {
|
|
49
|
+
return this.#at(t).add(unit === 'week' ? { weeks: n } : { [unit + 's']: n }).epochMilliseconds;
|
|
50
|
+
}
|
|
51
|
+
field(t, unit) {
|
|
52
|
+
const z = this.#at(t);
|
|
53
|
+
return unit === 'month' ? z.month - 1 : z[unit];
|
|
54
|
+
}
|
|
55
|
+
format(t, _rank, spec) {
|
|
56
|
+
return this.#at(t).toLocaleString(this.attrs.locale ?? this.chart?.attrs.locale, spec);
|
|
57
|
+
}
|
|
58
|
+
}
|