@matthieumordrel/chart-studio 0.2.0 → 0.2.2
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 +1 -1
- package/dist/core/chart-capabilities.d.mts +48 -0
- package/dist/core/chart-capabilities.mjs +55 -0
- package/dist/core/{colors.d.ts → colors.d.mts} +5 -3
- package/dist/core/colors.mjs +55 -0
- package/dist/core/config-utils.mjs +79 -0
- package/dist/core/date-utils.mjs +49 -0
- package/dist/core/define-chart-schema.d.mts +106 -0
- package/dist/core/define-chart-schema.mjs +47 -0
- package/dist/core/formatting.mjs +349 -0
- package/dist/core/infer-columns.d.mts +9 -0
- package/dist/core/infer-columns.mjs +481 -0
- package/dist/core/metric-utils.d.mts +13 -0
- package/dist/core/metric-utils.mjs +121 -0
- package/dist/core/pipeline-data-points.mjs +212 -0
- package/dist/core/pipeline-helpers.mjs +85 -0
- package/dist/core/{pipeline.d.ts → pipeline.d.mts} +21 -24
- package/dist/core/pipeline.mjs +153 -0
- package/dist/core/types.d.mts +957 -0
- package/dist/core/use-chart-options.d.mts +64 -0
- package/dist/core/use-chart-options.mjs +7 -0
- package/dist/core/use-chart-resolvers.mjs +34 -0
- package/dist/core/{use-chart.d.ts → use-chart.d.mts} +12 -9
- package/dist/core/use-chart.mjs +299 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +8 -0
- package/dist/ui/chart-axis-ticks.mjs +65 -0
- package/dist/ui/{chart-canvas.d.ts → chart-canvas.d.mts} +13 -6
- package/dist/ui/chart-canvas.mjs +461 -0
- package/dist/ui/chart-context.d.mts +92 -0
- package/dist/ui/chart-context.mjs +112 -0
- package/dist/ui/{chart-date-range-badge.d.ts → chart-date-range-badge.d.mts} +10 -4
- package/dist/ui/chart-date-range-badge.mjs +49 -0
- package/dist/ui/chart-date-range-panel.d.mts +18 -0
- package/dist/ui/chart-date-range-panel.mjs +208 -0
- package/dist/ui/{chart-date-range.d.ts → chart-date-range.d.mts} +10 -4
- package/dist/ui/chart-date-range.mjs +67 -0
- package/dist/ui/chart-debug.d.mts +17 -0
- package/dist/ui/chart-debug.mjs +169 -0
- package/dist/ui/chart-dropdown.mjs +92 -0
- package/dist/ui/{chart-filters-panel.d.ts → chart-filters-panel.d.mts} +12 -5
- package/dist/ui/chart-filters-panel.mjs +132 -0
- package/dist/ui/{chart-filters.d.ts → chart-filters.d.mts} +10 -4
- package/dist/ui/chart-filters.mjs +48 -0
- package/dist/ui/chart-group-by-selector.d.mts +14 -0
- package/dist/ui/chart-group-by-selector.mjs +29 -0
- package/dist/ui/{chart-metric-panel.d.ts → chart-metric-panel.d.mts} +12 -5
- package/dist/ui/chart-metric-panel.mjs +172 -0
- package/dist/ui/chart-metric-selector.d.mts +16 -0
- package/dist/ui/chart-metric-selector.mjs +50 -0
- package/dist/ui/chart-select.mjs +62 -0
- package/dist/ui/{chart-source-switcher.d.ts → chart-source-switcher.d.mts} +10 -4
- package/dist/ui/chart-source-switcher.mjs +54 -0
- package/dist/ui/chart-time-bucket-selector.d.mts +15 -0
- package/dist/ui/chart-time-bucket-selector.mjs +34 -0
- package/dist/ui/chart-toolbar-overflow.d.mts +28 -0
- package/dist/ui/chart-toolbar-overflow.mjs +209 -0
- package/dist/ui/chart-toolbar.d.mts +29 -0
- package/dist/ui/chart-toolbar.mjs +56 -0
- package/dist/ui/chart-type-selector.d.mts +14 -0
- package/dist/ui/chart-type-selector.mjs +33 -0
- package/dist/ui/chart-x-axis-selector.d.mts +14 -0
- package/dist/ui/chart-x-axis-selector.mjs +25 -0
- package/dist/ui/index.d.mts +19 -0
- package/dist/ui/index.mjs +18 -0
- package/dist/ui/toolbar-types.d.mts +7 -0
- package/dist/ui/toolbar-types.mjs +83 -0
- package/package.json +11 -10
- package/dist/core/chart-capabilities.d.ts +0 -60
- package/dist/core/chart-capabilities.d.ts.map +0 -1
- package/dist/core/chart-capabilities.js +0 -54
- package/dist/core/colors.d.ts.map +0 -1
- package/dist/core/colors.js +0 -54
- package/dist/core/config-utils.d.ts +0 -43
- package/dist/core/config-utils.d.ts.map +0 -1
- package/dist/core/config-utils.js +0 -80
- package/dist/core/date-utils.d.ts +0 -29
- package/dist/core/date-utils.d.ts.map +0 -1
- package/dist/core/date-utils.js +0 -58
- package/dist/core/define-chart-schema.d.ts +0 -105
- package/dist/core/define-chart-schema.d.ts.map +0 -1
- package/dist/core/define-chart-schema.js +0 -44
- package/dist/core/formatting.d.ts +0 -47
- package/dist/core/formatting.d.ts.map +0 -1
- package/dist/core/formatting.js +0 -396
- package/dist/core/index.d.ts +0 -17
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -12
- package/dist/core/infer-columns.d.ts +0 -6
- package/dist/core/infer-columns.d.ts.map +0 -1
- package/dist/core/infer-columns.js +0 -512
- package/dist/core/metric-utils.d.ts +0 -43
- package/dist/core/metric-utils.d.ts.map +0 -1
- package/dist/core/metric-utils.js +0 -141
- package/dist/core/pipeline-data-points.d.ts +0 -23
- package/dist/core/pipeline-data-points.d.ts.map +0 -1
- package/dist/core/pipeline-data-points.js +0 -235
- package/dist/core/pipeline-helpers.d.ts +0 -38
- package/dist/core/pipeline-helpers.d.ts.map +0 -1
- package/dist/core/pipeline-helpers.js +0 -97
- package/dist/core/pipeline.d.ts.map +0 -1
- package/dist/core/pipeline.js +0 -156
- package/dist/core/types.d.ts +0 -1109
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -14
- package/dist/core/use-chart-options.d.ts +0 -66
- package/dist/core/use-chart-options.d.ts.map +0 -1
- package/dist/core/use-chart-options.js +0 -4
- package/dist/core/use-chart-resolvers.d.ts +0 -14
- package/dist/core/use-chart-resolvers.d.ts.map +0 -1
- package/dist/core/use-chart-resolvers.js +0 -41
- package/dist/core/use-chart.d.ts.map +0 -1
- package/dist/core/use-chart.js +0 -265
- package/dist/index.d.ts +0 -36
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -35
- package/dist/ui/chart-axis-ticks.d.ts +0 -35
- package/dist/ui/chart-axis-ticks.d.ts.map +0 -1
- package/dist/ui/chart-axis-ticks.js +0 -79
- package/dist/ui/chart-canvas.d.ts.map +0 -1
- package/dist/ui/chart-canvas.js +0 -337
- package/dist/ui/chart-context.d.ts +0 -89
- package/dist/ui/chart-context.d.ts.map +0 -1
- package/dist/ui/chart-context.js +0 -128
- package/dist/ui/chart-date-range-badge.d.ts.map +0 -1
- package/dist/ui/chart-date-range-badge.js +0 -30
- package/dist/ui/chart-date-range-panel.d.ts +0 -25
- package/dist/ui/chart-date-range-panel.d.ts.map +0 -1
- package/dist/ui/chart-date-range-panel.js +0 -125
- package/dist/ui/chart-date-range.d.ts.map +0 -1
- package/dist/ui/chart-date-range.js +0 -37
- package/dist/ui/chart-debug.d.ts +0 -10
- package/dist/ui/chart-debug.d.ts.map +0 -1
- package/dist/ui/chart-debug.js +0 -126
- package/dist/ui/chart-dropdown.d.ts +0 -35
- package/dist/ui/chart-dropdown.d.ts.map +0 -1
- package/dist/ui/chart-dropdown.js +0 -76
- package/dist/ui/chart-filters-panel.d.ts.map +0 -1
- package/dist/ui/chart-filters-panel.js +0 -46
- package/dist/ui/chart-filters.d.ts.map +0 -1
- package/dist/ui/chart-filters.js +0 -26
- package/dist/ui/chart-group-by-selector.d.ts +0 -8
- package/dist/ui/chart-group-by-selector.d.ts.map +0 -1
- package/dist/ui/chart-group-by-selector.js +0 -19
- package/dist/ui/chart-metric-panel.d.ts.map +0 -1
- package/dist/ui/chart-metric-panel.js +0 -118
- package/dist/ui/chart-metric-selector.d.ts +0 -10
- package/dist/ui/chart-metric-selector.d.ts.map +0 -1
- package/dist/ui/chart-metric-selector.js +0 -27
- package/dist/ui/chart-select.d.ts +0 -25
- package/dist/ui/chart-select.d.ts.map +0 -1
- package/dist/ui/chart-select.js +0 -35
- package/dist/ui/chart-source-switcher.d.ts.map +0 -1
- package/dist/ui/chart-source-switcher.js +0 -31
- package/dist/ui/chart-time-bucket-selector.d.ts +0 -9
- package/dist/ui/chart-time-bucket-selector.d.ts.map +0 -1
- package/dist/ui/chart-time-bucket-selector.js +0 -25
- package/dist/ui/chart-toolbar-overflow.d.ts +0 -29
- package/dist/ui/chart-toolbar-overflow.d.ts.map +0 -1
- package/dist/ui/chart-toolbar-overflow.js +0 -109
- package/dist/ui/chart-toolbar.d.ts +0 -45
- package/dist/ui/chart-toolbar.d.ts.map +0 -1
- package/dist/ui/chart-toolbar.js +0 -44
- package/dist/ui/chart-type-selector.d.ts +0 -8
- package/dist/ui/chart-type-selector.d.ts.map +0 -1
- package/dist/ui/chart-type-selector.js +0 -22
- package/dist/ui/chart-x-axis-selector.d.ts +0 -8
- package/dist/ui/chart-x-axis-selector.d.ts.map +0 -1
- package/dist/ui/chart-x-axis-selector.js +0 -14
- package/dist/ui/index.d.ts +0 -25
- package/dist/ui/index.d.ts.map +0 -1
- package/dist/ui/index.js +0 -23
- package/dist/ui/toolbar-types.d.ts +0 -43
- package/dist/ui/toolbar-types.d.ts.map +0 -1
- package/dist/ui/toolbar-types.js +0 -50
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
//#region src/core/formatting.ts
|
|
2
|
+
const DURATION_UNIT_TO_SECONDS = {
|
|
3
|
+
seconds: 1,
|
|
4
|
+
minutes: 60,
|
|
5
|
+
hours: 3600,
|
|
6
|
+
days: 1440 * 60
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Build a numeric range from chart values.
|
|
10
|
+
*/
|
|
11
|
+
function createNumericRange(values) {
|
|
12
|
+
const finiteValues = values.filter((value) => Number.isFinite(value));
|
|
13
|
+
if (finiteValues.length === 0) return null;
|
|
14
|
+
let min = finiteValues[0];
|
|
15
|
+
let max = finiteValues[0];
|
|
16
|
+
for (const value of finiteValues) {
|
|
17
|
+
if (value < min) min = value;
|
|
18
|
+
if (value > max) max = value;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
min,
|
|
22
|
+
max
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decide whether an axis should keep decimal ticks for the current visible
|
|
27
|
+
* numeric values.
|
|
28
|
+
*/
|
|
29
|
+
function shouldAllowDecimalTicks(values) {
|
|
30
|
+
const finiteValues = values.filter((value) => Number.isFinite(value));
|
|
31
|
+
if (finiteValues.length === 0) return false;
|
|
32
|
+
if (shouldUsePercentByDefault(createNumericRange(finiteValues))) return true;
|
|
33
|
+
return finiteValues.some((value) => !isEffectivelyInteger(value));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Format one chart value for a specific UI surface.
|
|
37
|
+
*/
|
|
38
|
+
function formatChartValue(value, options) {
|
|
39
|
+
const { column, surface, timeBucket, numericRange, locale = "en-US", item } = options;
|
|
40
|
+
if (column.formatter) return column.formatter(value, item);
|
|
41
|
+
if (value == null) return "Unknown";
|
|
42
|
+
switch (column.type) {
|
|
43
|
+
case "boolean": return formatBooleanValue(value, column);
|
|
44
|
+
case "category": return String(value);
|
|
45
|
+
case "date": return value instanceof Date || typeof value === "string" || typeof value === "number" ? formatDateValue(value, column.format, surface, timeBucket, locale) : String(value);
|
|
46
|
+
case "number": return typeof value === "number" ? formatNumberValue(value, column.format, surface, numericRange, locale) : String(value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Format a date bucket label from the machine-friendly pipeline key.
|
|
51
|
+
*/
|
|
52
|
+
function formatTimeBucketLabel(key, bucket, surface, locale = "en-US") {
|
|
53
|
+
switch (bucket) {
|
|
54
|
+
case "day": return formatDateWithOptions(parseBucketDate(key), locale, getBucketDayOptions(surface));
|
|
55
|
+
case "week": {
|
|
56
|
+
const date = parseBucketDate(key);
|
|
57
|
+
return `${surface === "tooltip" ? "Week of " : "Wk of "}${formatDateWithOptions(date, locale, getBucketWeekOptions(surface))}`;
|
|
58
|
+
}
|
|
59
|
+
case "month": return formatDateWithOptions(parseBucketMonth(key), locale, {
|
|
60
|
+
month: "short",
|
|
61
|
+
year: "2-digit"
|
|
62
|
+
});
|
|
63
|
+
case "quarter": {
|
|
64
|
+
const { year, quarter } = parseQuarterKey(key);
|
|
65
|
+
return `Q${quarter} ${year.slice(-2)}`;
|
|
66
|
+
}
|
|
67
|
+
case "year": return key;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the boolean labels while keeping null handling in the shared entry
|
|
72
|
+
* point above.
|
|
73
|
+
*/
|
|
74
|
+
function formatBooleanValue(value, column) {
|
|
75
|
+
if (value === true) return column.trueLabel ?? "True";
|
|
76
|
+
if (value === false) return column.falseLabel ?? "False";
|
|
77
|
+
return String(value);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Format numeric values with surface-aware defaults and optional overrides.
|
|
81
|
+
*/
|
|
82
|
+
function formatNumberValue(value, format, surface, numericRange, locale) {
|
|
83
|
+
if (!Number.isFinite(value)) return String(value);
|
|
84
|
+
if (typeof format === "object" && format.kind === "duration") return formatDurationValue(value, format);
|
|
85
|
+
if (typeof format === "object" && format.kind === "number") return new Intl.NumberFormat(format.locale ?? locale, format.options).format(value);
|
|
86
|
+
const mode = resolveNumberFormatMode(format, surface, numericRange, value);
|
|
87
|
+
return new Intl.NumberFormat(locale, getNumberFormatOptions(mode, surface, numericRange, value)).format(value);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Format one numeric duration into a compact, surface-agnostic label such as
|
|
91
|
+
* `36s`, `1h36m`, or `1d5h`.
|
|
92
|
+
*/
|
|
93
|
+
function formatDurationValue(value, format) {
|
|
94
|
+
const sign = value < 0 ? "-" : "";
|
|
95
|
+
const totalSeconds = Math.round(Math.abs(value) * DURATION_UNIT_TO_SECONDS[format.unit]);
|
|
96
|
+
if (totalSeconds === 0) return `${sign}0${getDurationZeroSuffix(format.unit)}`;
|
|
97
|
+
return `${sign}${buildDurationParts(totalSeconds).slice(0, 2).map((part) => `${part.value}${part.suffix}`).join("")}`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build the ordered duration parts used by the compact formatter.
|
|
101
|
+
*/
|
|
102
|
+
function buildDurationParts(totalSeconds) {
|
|
103
|
+
const parts = [];
|
|
104
|
+
let remainingSeconds = totalSeconds;
|
|
105
|
+
const units = [
|
|
106
|
+
{
|
|
107
|
+
seconds: DURATION_UNIT_TO_SECONDS.days,
|
|
108
|
+
suffix: "d"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
seconds: DURATION_UNIT_TO_SECONDS.hours,
|
|
112
|
+
suffix: "h"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
seconds: DURATION_UNIT_TO_SECONDS.minutes,
|
|
116
|
+
suffix: "m"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
seconds: DURATION_UNIT_TO_SECONDS.seconds,
|
|
120
|
+
suffix: "s"
|
|
121
|
+
}
|
|
122
|
+
];
|
|
123
|
+
for (const unit of units) {
|
|
124
|
+
if (remainingSeconds < unit.seconds) continue;
|
|
125
|
+
const unitValue = Math.floor(remainingSeconds / unit.seconds);
|
|
126
|
+
remainingSeconds -= unitValue * unit.seconds;
|
|
127
|
+
parts.push({
|
|
128
|
+
value: unitValue,
|
|
129
|
+
suffix: unit.suffix
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return parts.length > 0 ? parts : [{
|
|
133
|
+
value: 0,
|
|
134
|
+
suffix: "s"
|
|
135
|
+
}];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Keep zero durations aligned with the unit declared by the schema author.
|
|
139
|
+
*/
|
|
140
|
+
function getDurationZeroSuffix(unit) {
|
|
141
|
+
switch (unit) {
|
|
142
|
+
case "seconds": return "s";
|
|
143
|
+
case "minutes": return "m";
|
|
144
|
+
case "hours": return "h";
|
|
145
|
+
case "days": return "d";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Format date values with either a caller-specified `Intl` config or the shared
|
|
150
|
+
* time-bucket-aware defaults.
|
|
151
|
+
*/
|
|
152
|
+
function formatDateValue(value, format, surface, timeBucket, locale) {
|
|
153
|
+
if (typeof format === "object" && format.kind === "date") return formatDateWithOptions(value, format.locale ?? locale, format.options ?? {});
|
|
154
|
+
if (timeBucket) {
|
|
155
|
+
const date = toDate(value);
|
|
156
|
+
if (date) return formatDateWithOptions(date, locale, getBucketDateOptions(timeBucket, surface));
|
|
157
|
+
}
|
|
158
|
+
return formatDateWithOptions(value, locale, getDateValueOptions(resolveDateFormatMode(format), surface));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Convert a broad value into a valid Date when possible.
|
|
162
|
+
*/
|
|
163
|
+
function toDate(value) {
|
|
164
|
+
const date = value instanceof Date ? new Date(value) : new Date(value);
|
|
165
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Safely format a parsed date, falling back to the raw string when parsing
|
|
169
|
+
* fails.
|
|
170
|
+
*/
|
|
171
|
+
function formatDateWithOptions(value, locale, options) {
|
|
172
|
+
const date = value == null ? null : toDate(value);
|
|
173
|
+
if (!date) return value == null ? "Unknown" : String(value);
|
|
174
|
+
return new Intl.DateTimeFormat(locale, options).format(date);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Decide which number family should power the current surface.
|
|
178
|
+
*/
|
|
179
|
+
function resolveNumberFormatMode(format, surface, numericRange, value) {
|
|
180
|
+
if (typeof format === "string") switch (format) {
|
|
181
|
+
case "currency": return surface === "tooltip" ? "currency" : "compact-currency";
|
|
182
|
+
case "compact-number": return "compact-number";
|
|
183
|
+
case "percent": return "percent";
|
|
184
|
+
case "number":
|
|
185
|
+
case "date":
|
|
186
|
+
case "datetime": return surface === "tooltip" ? "number" : shouldUseCompactNumber(numericRange, value) ? "compact-number" : "number";
|
|
187
|
+
}
|
|
188
|
+
if (shouldUsePercentByDefault(numericRange)) return "percent";
|
|
189
|
+
if (surface !== "tooltip" && shouldUseCompactNumber(numericRange, value)) return "compact-number";
|
|
190
|
+
return "number";
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Decide which date family should power the current surface.
|
|
194
|
+
*/
|
|
195
|
+
function resolveDateFormatMode(format) {
|
|
196
|
+
return format === "datetime" ? "datetime" : "date";
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Use percentage defaults only when the visible values all live in the
|
|
200
|
+
* percentage-like range.
|
|
201
|
+
*/
|
|
202
|
+
function shouldUsePercentByDefault(numericRange) {
|
|
203
|
+
if (!numericRange) return false;
|
|
204
|
+
const maxAbs = Math.max(Math.abs(numericRange.min), Math.abs(numericRange.max));
|
|
205
|
+
return maxAbs > 0 && maxAbs <= 1;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Compact large values on short surfaces while leaving small ranges readable.
|
|
209
|
+
*/
|
|
210
|
+
function shouldUseCompactNumber(numericRange, value) {
|
|
211
|
+
return (numericRange ? Math.max(Math.abs(numericRange.min), Math.abs(numericRange.max)) : Math.abs(value)) >= 1e3;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Treat floating-point noise around whole numbers as integers so axis policy
|
|
215
|
+
* follows the actual metric shape rather than binary rounding artifacts.
|
|
216
|
+
*/
|
|
217
|
+
function isEffectivelyInteger(value) {
|
|
218
|
+
return Math.abs(value - Math.round(value)) < 1e-9;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Produce the final `Intl.NumberFormat` options for one numeric mode.
|
|
222
|
+
*/
|
|
223
|
+
function getNumberFormatOptions(mode, surface, numericRange, value) {
|
|
224
|
+
switch (mode) {
|
|
225
|
+
case "compact-currency": return {
|
|
226
|
+
style: "currency",
|
|
227
|
+
currency: "USD",
|
|
228
|
+
notation: "compact",
|
|
229
|
+
maximumFractionDigits: 1
|
|
230
|
+
};
|
|
231
|
+
case "currency": return {
|
|
232
|
+
style: "currency",
|
|
233
|
+
currency: "USD",
|
|
234
|
+
maximumFractionDigits: getStandardFractionDigits(surface, numericRange, value)
|
|
235
|
+
};
|
|
236
|
+
case "compact-number": return {
|
|
237
|
+
notation: "compact",
|
|
238
|
+
maximumFractionDigits: 1
|
|
239
|
+
};
|
|
240
|
+
case "percent": return {
|
|
241
|
+
style: "percent",
|
|
242
|
+
maximumFractionDigits: surface === "tooltip" ? 2 : 1
|
|
243
|
+
};
|
|
244
|
+
case "number": return { maximumFractionDigits: getStandardFractionDigits(surface, numericRange, value) };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Keep tooltip values more precise than axis and data-label surfaces.
|
|
249
|
+
*/
|
|
250
|
+
function getStandardFractionDigits(surface, numericRange, value) {
|
|
251
|
+
const span = numericRange ? Math.abs(numericRange.max - numericRange.min) : Math.abs(value);
|
|
252
|
+
if (surface === "tooltip") {
|
|
253
|
+
if (span < 1) return 3;
|
|
254
|
+
if (span < 10) return 2;
|
|
255
|
+
if (span < 100) return 1;
|
|
256
|
+
return 0;
|
|
257
|
+
}
|
|
258
|
+
if (span < 1) return 2;
|
|
259
|
+
if (span < 10) return 1;
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Match raw date values to a clear default display.
|
|
264
|
+
*/
|
|
265
|
+
function getDateValueOptions(mode, surface) {
|
|
266
|
+
if (mode === "datetime") return surface === "tooltip" ? {
|
|
267
|
+
dateStyle: "medium",
|
|
268
|
+
timeStyle: "short"
|
|
269
|
+
} : {
|
|
270
|
+
month: "short",
|
|
271
|
+
day: "numeric",
|
|
272
|
+
hour: "numeric",
|
|
273
|
+
minute: "2-digit"
|
|
274
|
+
};
|
|
275
|
+
return {
|
|
276
|
+
month: "short",
|
|
277
|
+
day: "numeric",
|
|
278
|
+
year: "2-digit"
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Match bucketed dates to the active time bucket.
|
|
283
|
+
*/
|
|
284
|
+
function getBucketDateOptions(bucket, surface) {
|
|
285
|
+
switch (bucket) {
|
|
286
|
+
case "day": return getBucketDayOptions(surface);
|
|
287
|
+
case "week": return getBucketWeekOptions(surface);
|
|
288
|
+
case "month": return {
|
|
289
|
+
month: "short",
|
|
290
|
+
year: "2-digit"
|
|
291
|
+
};
|
|
292
|
+
case "quarter": return {
|
|
293
|
+
month: "short",
|
|
294
|
+
year: "2-digit"
|
|
295
|
+
};
|
|
296
|
+
case "year": return { year: "numeric" };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Keep day buckets short on axes and clearer in tooltips.
|
|
301
|
+
*/
|
|
302
|
+
function getBucketDayOptions(surface) {
|
|
303
|
+
return surface === "tooltip" ? {
|
|
304
|
+
month: "short",
|
|
305
|
+
day: "numeric",
|
|
306
|
+
year: "2-digit"
|
|
307
|
+
} : {
|
|
308
|
+
month: "short",
|
|
309
|
+
day: "numeric"
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Keep week buckets short on axes and clearer in tooltips.
|
|
314
|
+
*/
|
|
315
|
+
function getBucketWeekOptions(surface) {
|
|
316
|
+
return surface === "tooltip" ? {
|
|
317
|
+
month: "short",
|
|
318
|
+
day: "numeric",
|
|
319
|
+
year: "2-digit"
|
|
320
|
+
} : {
|
|
321
|
+
month: "short",
|
|
322
|
+
day: "numeric"
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Parse a `YYYY-MM-DD` bucket key.
|
|
327
|
+
*/
|
|
328
|
+
function parseBucketDate(key) {
|
|
329
|
+
return /* @__PURE__ */ new Date(`${key}T00:00:00`);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Parse a `YYYY-MM` bucket key.
|
|
333
|
+
*/
|
|
334
|
+
function parseBucketMonth(key) {
|
|
335
|
+
const [year, month] = key.split("-");
|
|
336
|
+
return new Date(Number(year), Number(month) - 1, 1);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Parse a `YYYY-QN` quarter key.
|
|
340
|
+
*/
|
|
341
|
+
function parseQuarterKey(key) {
|
|
342
|
+
const [year, quarter] = key.split("-Q");
|
|
343
|
+
return {
|
|
344
|
+
year: year ?? key,
|
|
345
|
+
quarter: quarter ?? "1"
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
//#endregion
|
|
349
|
+
export { createNumericRange, formatChartValue, formatTimeBucketLabel, shouldAllowDecimalTicks };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ChartColumn, ChartSchema, ResolvedColumnIdFromSchema } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/infer-columns.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolve chart columns directly from raw data and an optional explicit schema.
|
|
6
|
+
*/
|
|
7
|
+
declare function inferColumnsFromData<T, const TSchema extends ChartSchema<T, any> | undefined = undefined>(data: readonly T[], schema?: TSchema): readonly ChartColumn<T, ResolvedColumnIdFromSchema<T, TSchema>>[];
|
|
8
|
+
//#endregion
|
|
9
|
+
export { inferColumnsFromData };
|