@pixerate/editor 0.52.0 → 0.53.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/dist/agent/index.cjs +23 -23
- package/dist/agent/index.js +4 -4
- package/dist/chart/index.cjs +174 -131
- package/dist/chart/index.cjs.map +1 -1
- package/dist/chart/index.d.cts +68 -21
- package/dist/chart/index.d.ts +68 -21
- package/dist/chart/index.js +64 -21
- package/dist/chart/index.js.map +1 -1
- package/dist/{chunk-UAW5FEMD.js → chunk-3S72F46R.js} +66 -8
- package/dist/chunk-3S72F46R.js.map +1 -0
- package/dist/{chunk-5TWIN7ZJ.js → chunk-47WWV3LI.js} +34 -4
- package/dist/chunk-47WWV3LI.js.map +1 -0
- package/dist/{chunk-OV7UAKIY.js → chunk-633QC34G.js} +172 -1
- package/dist/chunk-633QC34G.js.map +1 -0
- package/dist/{chunk-5N6AQCVB.js → chunk-BQQZ6MOI.js} +3 -3
- package/dist/{chunk-M5Z77GFH.cjs → chunk-C3JHII3M.cjs} +53 -53
- package/dist/{chunk-M5Z77GFH.cjs.map → chunk-C3JHII3M.cjs.map} +1 -1
- package/dist/{chunk-JOX6MJW4.cjs → chunk-CKRNELPO.cjs} +176 -5
- package/dist/chunk-CKRNELPO.cjs.map +1 -0
- package/dist/{chunk-TGBCBQFV.cjs → chunk-DK6QBGCS.cjs} +45 -15
- package/dist/chunk-DK6QBGCS.cjs.map +1 -0
- package/dist/{chunk-GTZXF4BI.cjs → chunk-NK3WL5TJ.cjs} +298 -133
- package/dist/chunk-NK3WL5TJ.cjs.map +1 -0
- package/dist/{chunk-3ZBAXET6.cjs → chunk-NN3JGUSX.cjs} +80 -22
- package/dist/chunk-NN3JGUSX.cjs.map +1 -0
- package/dist/{chunk-YMKPMXZ4.js → chunk-OIKYP7XC.js} +4 -4
- package/dist/{chunk-FEMIVHN3.cjs → chunk-P43HUQRX.cjs} +16 -16
- package/dist/{chunk-FEMIVHN3.cjs.map → chunk-P43HUQRX.cjs.map} +1 -1
- package/dist/{chunk-QFTVLEVN.js → chunk-RIXTW3C4.js} +3 -3
- package/dist/{chunk-WBOAXDKD.js → chunk-VODBAO32.js} +222 -57
- package/dist/chunk-VODBAO32.js.map +1 -0
- package/dist/{chunk-2DEBI6KU.cjs → chunk-YZZMX6V7.cjs} +10 -10
- package/dist/{chunk-2DEBI6KU.cjs.map → chunk-YZZMX6V7.cjs.map} +1 -1
- package/dist/{controller-DS3drIvy.d.cts → controller-CX0QfSv0.d.cts} +53 -2
- package/dist/{controller-BdKzaxs2.d.ts → controller-DscWQbjO.d.ts} +53 -2
- package/dist/export/index.cjs +4 -4
- package/dist/export/index.js +3 -3
- package/dist/extensions/index.cjs +6 -6
- package/dist/extensions/index.d.cts +2 -2
- package/dist/extensions/index.d.ts +2 -2
- package/dist/extensions/index.js +5 -5
- package/dist/{index-Dt9lzydb.d.ts → index-CALDD35B.d.ts} +1 -1
- package/dist/{index-DOy9HzfC.d.cts → index-DIWB6xMf.d.cts} +1 -1
- package/dist/index.cjs +13 -13
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-3ZBAXET6.cjs.map +0 -1
- package/dist/chunk-5TWIN7ZJ.js.map +0 -1
- package/dist/chunk-GTZXF4BI.cjs.map +0 -1
- package/dist/chunk-JOX6MJW4.cjs.map +0 -1
- package/dist/chunk-OV7UAKIY.js.map +0 -1
- package/dist/chunk-TGBCBQFV.cjs.map +0 -1
- package/dist/chunk-UAW5FEMD.js.map +0 -1
- package/dist/chunk-WBOAXDKD.js.map +0 -1
- /package/dist/{chunk-5N6AQCVB.js.map → chunk-BQQZ6MOI.js.map} +0 -0
- /package/dist/{chunk-YMKPMXZ4.js.map → chunk-OIKYP7XC.js.map} +0 -0
- /package/dist/{chunk-QFTVLEVN.js.map → chunk-RIXTW3C4.js.map} +0 -0
|
@@ -149,12 +149,104 @@ function checkChartColors(colors, options = {}) {
|
|
|
149
149
|
return { ok: issues.length === 0, closest, contrast, issues, skipped };
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
// src/chart/errorbars.ts
|
|
153
|
+
var CHART_ERROR_BAR_TYPES = ["fixed", "percent", "stddev", "stderr", "custom"];
|
|
154
|
+
var CHART_ERROR_BAR_DIRECTIONS = ["both", "plus", "minus"];
|
|
155
|
+
var CHART_ERROR_BAR_LABELS = {
|
|
156
|
+
fixed: "Fixed amount",
|
|
157
|
+
percent: "Percentage",
|
|
158
|
+
stddev: "Standard deviation",
|
|
159
|
+
stderr: "Standard error",
|
|
160
|
+
custom: "Custom"
|
|
161
|
+
};
|
|
162
|
+
function defaultChartErrorBarValue(type) {
|
|
163
|
+
return type === "fixed" ? 1 : type === "percent" ? 5 : type === "stddev" ? 1 : void 0;
|
|
164
|
+
}
|
|
165
|
+
function meanAndSd(values) {
|
|
166
|
+
const xs = values.filter((v) => v !== null && Number.isFinite(v));
|
|
167
|
+
const n = xs.length;
|
|
168
|
+
if (!n) return { mean: 0, sd: 0, n };
|
|
169
|
+
const mean = xs.reduce((t, v) => t + v, 0) / n;
|
|
170
|
+
const sd = n > 1 ? Math.sqrt(xs.reduce((t, v) => t + (v - mean) ** 2, 0) / (n - 1)) : 0;
|
|
171
|
+
return { mean, sd, n };
|
|
172
|
+
}
|
|
173
|
+
function chartErrorAmounts(bars, values) {
|
|
174
|
+
const direction = _nullishCoalesce(bars.direction, () => ( "both"));
|
|
175
|
+
const up = direction !== "minus";
|
|
176
|
+
const down = direction !== "plus";
|
|
177
|
+
const stats = bars.type === "stddev" || bars.type === "stderr" ? meanAndSd(values) : null;
|
|
178
|
+
const amount = _nullishCoalesce(_nullishCoalesce(bars.value, () => ( defaultChartErrorBarValue(bars.type))), () => ( 0));
|
|
179
|
+
return values.map((v, i) => {
|
|
180
|
+
if (v === null || !Number.isFinite(v)) return null;
|
|
181
|
+
let plus;
|
|
182
|
+
let minus;
|
|
183
|
+
let center = v;
|
|
184
|
+
switch (bars.type) {
|
|
185
|
+
case "fixed":
|
|
186
|
+
plus = minus = Math.abs(amount);
|
|
187
|
+
break;
|
|
188
|
+
case "percent":
|
|
189
|
+
plus = minus = Math.abs(v * amount / 100);
|
|
190
|
+
break;
|
|
191
|
+
case "stddev":
|
|
192
|
+
center = stats.mean;
|
|
193
|
+
plus = minus = Math.abs(amount) * stats.sd;
|
|
194
|
+
break;
|
|
195
|
+
case "stderr":
|
|
196
|
+
plus = minus = stats.n ? stats.sd / Math.sqrt(stats.n) : 0;
|
|
197
|
+
break;
|
|
198
|
+
default: {
|
|
199
|
+
const p = _nullishCoalesce(_optionalChain([bars, 'access', _2 => _2.plus, 'optionalAccess', _3 => _3[i]]), () => ( null));
|
|
200
|
+
const m = _nullishCoalesce(_optionalChain([bars, 'access', _4 => _4.minus, 'optionalAccess', _5 => _5[i]]), () => ( (bars.minus ? null : p)));
|
|
201
|
+
if ((p === null || !Number.isFinite(p)) && (m === null || !Number.isFinite(m))) return null;
|
|
202
|
+
plus = p !== null && Number.isFinite(p) ? Math.abs(p) : 0;
|
|
203
|
+
minus = m !== null && Number.isFinite(m) ? Math.abs(m) : 0;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { center, plus: up ? plus : 0, minus: down ? minus : 0 };
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function describeChartErrorBars(bars) {
|
|
210
|
+
const sign = bars.direction === "plus" ? "+" : bars.direction === "minus" ? "\u2212" : "\xB1";
|
|
211
|
+
const value = _nullishCoalesce(bars.value, () => ( defaultChartErrorBarValue(bars.type)));
|
|
212
|
+
switch (bars.type) {
|
|
213
|
+
case "fixed":
|
|
214
|
+
return `${sign}${value} error bars`;
|
|
215
|
+
case "percent":
|
|
216
|
+
return `${sign}${value}% error bars`;
|
|
217
|
+
case "stddev":
|
|
218
|
+
return `${sign}${value} standard deviation${value === 1 ? "" : "s"} error bars`;
|
|
219
|
+
case "stderr":
|
|
220
|
+
return `${sign}standard error bars`;
|
|
221
|
+
default:
|
|
222
|
+
return "custom error bars";
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function chartErrorBarsOfType(type, current, values) {
|
|
226
|
+
if (!type) return null;
|
|
227
|
+
const keep = { ..._optionalChain([current, 'optionalAccess', _6 => _6.direction]) ? { direction: current.direction } : {}, ..._optionalChain([current, 'optionalAccess', _7 => _7.cap]) === false ? { cap: false } : {} };
|
|
228
|
+
if (type !== "custom") return { type, ...keep, ..._optionalChain([current, 'optionalAccess', _8 => _8.type]) === type && current.value !== void 0 ? { value: current.value } : {} };
|
|
229
|
+
if (_optionalChain([current, 'optionalAccess', _9 => _9.type]) === "custom") return current;
|
|
230
|
+
const amounts = chartErrorAmounts({ ..._nullishCoalesce(current, () => ( { type: "fixed" })), direction: "both" }, values);
|
|
231
|
+
const round = (n) => Number(n.toPrecision(4));
|
|
232
|
+
const plus = amounts.map((a) => a ? round(a.plus) : null);
|
|
233
|
+
const minus = amounts.map((a) => a ? round(a.minus) : null);
|
|
234
|
+
return { type, plus, ...JSON.stringify(minus) !== JSON.stringify(plus) ? { minus } : {}, ...keep };
|
|
235
|
+
}
|
|
236
|
+
function formatChartAmountList(values) {
|
|
237
|
+
return (_nullishCoalesce(values, () => ( []))).map((v) => v === null ? "-" : String(v)).join(", ");
|
|
238
|
+
}
|
|
239
|
+
function parseChartAmountList(text2) {
|
|
240
|
+
return text2.split(/[;,\s]+/).filter((t) => t !== "").map((t) => t === "-" ? null : t);
|
|
241
|
+
}
|
|
242
|
+
|
|
152
243
|
// src/chart/spec.ts
|
|
153
244
|
var CHART_TYPES = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap"];
|
|
154
245
|
var CHART_MARKERS = ["circle", "square", "diamond", "triangle", "cross", "none"];
|
|
155
246
|
var CHART_TRENDLINE_TYPES = ["linear", "exponential", "logarithmic", "power", "polynomial", "moving-average"];
|
|
156
247
|
var CHART_LABEL_POSITIONS = ["auto", "inside", "outside", "center"];
|
|
157
248
|
var CHART_AXIS_KINDS = ["category", "date"];
|
|
249
|
+
var CHART_AXIS_SCALES = ["linear", "log"];
|
|
158
250
|
var CHART_SERIES_TYPES = ["bar", "line", "area", "scatter"];
|
|
159
251
|
var CHART_STACKINGS = ["none", "stacked", "percent"];
|
|
160
252
|
var CHART_CURVES = ["linear", "smooth", "step"];
|
|
@@ -239,14 +331,14 @@ function createChartSpec(partial = {}) {
|
|
|
239
331
|
}
|
|
240
332
|
function chartSeriesColor(spec, seriesIndex) {
|
|
241
333
|
const series = spec.series[seriesIndex];
|
|
242
|
-
if (_optionalChain([series, 'optionalAccess',
|
|
334
|
+
if (_optionalChain([series, 'optionalAccess', _10 => _10.color])) return series.color;
|
|
243
335
|
return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, seriesIndex);
|
|
244
336
|
}
|
|
245
337
|
function chartSliceColor(spec, index) {
|
|
246
338
|
return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, index);
|
|
247
339
|
}
|
|
248
340
|
function chartPointColor(spec, seriesIndex, index) {
|
|
249
|
-
return _optionalChain([spec, 'access',
|
|
341
|
+
return _optionalChain([spec, 'access', _11 => _11.series, 'access', _12 => _12[seriesIndex], 'optionalAccess', _13 => _13.pointColors, 'optionalAccess', _14 => _14[index]]) || chartSeriesColor(spec, seriesIndex);
|
|
250
342
|
}
|
|
251
343
|
function chartSeriesType(spec, series) {
|
|
252
344
|
if (series.type) return series.type;
|
|
@@ -354,6 +446,24 @@ function normalizeChartAxis(value, fallback, path, issues = []) {
|
|
|
354
446
|
};
|
|
355
447
|
const kind = "kind" in value ? value.kind === null ? void 0 : pick(value.kind, CHART_AXIS_KINDS, "category", `${path}.kind`, issues) : fallback.kind;
|
|
356
448
|
if (kind && kind !== "category") axis.kind = kind;
|
|
449
|
+
const scale = "scale" in value ? value.scale === null ? "linear" : pick(value.scale, CHART_AXIS_SCALES, "linear", `${path}.scale`, issues) : _nullishCoalesce(fallback.scale, () => ( "linear"));
|
|
450
|
+
if (scale === "log") {
|
|
451
|
+
axis.scale = "log";
|
|
452
|
+
const base = "logBase" in value ? value.logBase : fallback.logBase;
|
|
453
|
+
if (base !== void 0 && base !== null) {
|
|
454
|
+
const b = Number(base);
|
|
455
|
+
if (Number.isFinite(b) && b >= 2 && b <= 1e3) {
|
|
456
|
+
if (b !== 10) axis.logBase = b;
|
|
457
|
+
} else issues.push({ path: `${path}.logBase`, message: `${path}.logBase must be a number from 2 to 1000 (default 10).` });
|
|
458
|
+
}
|
|
459
|
+
for (const end of ["min", "max"]) {
|
|
460
|
+
if (axis[end] !== null && !(axis[end] > 0)) {
|
|
461
|
+
issues.push({ path: `${path}.${end}`, message: `${path}.${end} must be greater than 0 on a logarithmic axis (or null for automatic); got ${axis[end]}.` });
|
|
462
|
+
axis[end] = null;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if ("reverse" in value ? value.reverse !== null && flag(value.reverse, false, `${path}.reverse`, issues) : fallback.reverse) axis.reverse = true;
|
|
357
467
|
return axis;
|
|
358
468
|
}
|
|
359
469
|
function normalizeLegend(value, issues) {
|
|
@@ -416,7 +526,7 @@ function normalizeSeries(value, length, used, index, issues) {
|
|
|
416
526
|
const list = normalizeChartValues(value[key2], length, `${path}.${key2}`, issues);
|
|
417
527
|
if (list.some((v) => v !== null)) series[key2] = list;
|
|
418
528
|
}
|
|
419
|
-
if (key(value, "sizes") && _optionalChain([series, 'access',
|
|
529
|
+
if (key(value, "sizes") && _optionalChain([series, 'access', _15 => _15.sizes, 'optionalAccess', _16 => _16.some, 'call', _17 => _17((v) => v !== null && v < 0)])) {
|
|
420
530
|
issues.push({ path: `${path}.sizes`, message: `${path}.sizes must not be negative.` });
|
|
421
531
|
series.sizes = series.sizes.map((v) => v !== null && v < 0 ? null : v);
|
|
422
532
|
}
|
|
@@ -437,6 +547,11 @@ function normalizeSeries(value, length, used, index, issues) {
|
|
|
437
547
|
const format = normalizeFormat(value.format, `${path}.format`, issues);
|
|
438
548
|
if (Object.keys(format).length) series.format = format;
|
|
439
549
|
}
|
|
550
|
+
for (const name of ["errorBars", "xErrorBars"]) {
|
|
551
|
+
if (!key(value, name)) continue;
|
|
552
|
+
const bars = normalizeChartErrorBars(value[name], length, `${path}.${name}`, issues);
|
|
553
|
+
if (bars) series[name] = bars;
|
|
554
|
+
}
|
|
440
555
|
if (value.trendlines !== void 0 && value.trendlines !== null) {
|
|
441
556
|
if (!Array.isArray(value.trendlines)) issues.push({ path: `${path}.trendlines`, message: `${path}.trendlines must be an array.` });
|
|
442
557
|
else {
|
|
@@ -447,6 +562,39 @@ function normalizeSeries(value, length, used, index, issues) {
|
|
|
447
562
|
return series;
|
|
448
563
|
}
|
|
449
564
|
var key = (value, name) => value[name] !== void 0 && value[name] !== null;
|
|
565
|
+
function normalizeChartErrorBars(value, length, path, issues = []) {
|
|
566
|
+
if (!isRecord(value)) {
|
|
567
|
+
issues.push({ path, message: `${path} must be an object with a type (${CHART_ERROR_BAR_TYPES.join(", ")}), or null for none.` });
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
const before = issues.length;
|
|
571
|
+
const type = pick(value.type, CHART_ERROR_BAR_TYPES, "fixed", `${path}.type`, issues);
|
|
572
|
+
if (value.type === void 0) issues.push({ path: `${path}.type`, message: `${path}.type is required: one of ${CHART_ERROR_BAR_TYPES.map((t) => `"${t}"`).join(", ")}.` });
|
|
573
|
+
const bars = { type };
|
|
574
|
+
if (key(value, "value")) {
|
|
575
|
+
const n = Number(value.value);
|
|
576
|
+
if (type === "stderr" || type === "custom") issues.push({ path: `${path}.value`, message: `${type} error bars take no value; ${type === "custom" ? "pass plus and minus amounts instead" : "the amount comes from the data"}.` });
|
|
577
|
+
else if (Number.isFinite(n) && n >= 0) bars.value = n;
|
|
578
|
+
else issues.push({ path: `${path}.value`, message: `${path}.value must be a number, 0 or more${type === "percent" ? " (a percentage, e.g. 5 for 5%)" : ""}.` });
|
|
579
|
+
}
|
|
580
|
+
for (const name of ["plus", "minus"]) {
|
|
581
|
+
if (!key(value, name)) continue;
|
|
582
|
+
if (type !== "custom") {
|
|
583
|
+
issues.push({ path: `${path}.${name}`, message: `${path}.${name} only applies to custom error bars; set type to "custom".` });
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
const list = normalizeChartValues(value[name], length, `${path}.${name}`, issues);
|
|
587
|
+
if (list.some((v) => v !== null && v < 0)) issues.push({ path: `${path}.${name}`, message: `${path}.${name} amounts must be 0 or more (distances from the point).` });
|
|
588
|
+
else bars[name] = list;
|
|
589
|
+
}
|
|
590
|
+
if (type === "custom" && !bars.plus && !bars.minus && issues.length === before) issues.push({ path: `${path}.plus`, message: `Custom error bars need plus and / or minus amounts, one per category.` });
|
|
591
|
+
if (key(value, "direction")) {
|
|
592
|
+
const direction = pick(value.direction, CHART_ERROR_BAR_DIRECTIONS, "both", `${path}.direction`, issues);
|
|
593
|
+
if (direction !== "both") bars.direction = direction;
|
|
594
|
+
}
|
|
595
|
+
if (key(value, "cap") && !flag(value.cap, true, `${path}.cap`, issues)) bars.cap = false;
|
|
596
|
+
return issues.length > before ? null : bars;
|
|
597
|
+
}
|
|
450
598
|
function normalizeChartTrendline(value, path, issues = []) {
|
|
451
599
|
if (!isRecord(value)) {
|
|
452
600
|
issues.push({ path, message: `${path} must be an object with a type.` });
|
|
@@ -547,6 +695,13 @@ function normalizeChartSpec(input) {
|
|
|
547
695
|
bins,
|
|
548
696
|
showTotal: flag(value.showTotal, true, "showTotal", issues)
|
|
549
697
|
};
|
|
698
|
+
if (spec.stacking === "percent")
|
|
699
|
+
for (const name of ["yAxis", "yAxis2"]) {
|
|
700
|
+
if (spec[name].scale !== "log") continue;
|
|
701
|
+
issues.push({ path: `${name}.scale`, message: `A logarithmic ${name} cannot show percent stacking (shares from 0% to 100% include 0); use stacking "stacked" or "none", or a linear axis.` });
|
|
702
|
+
delete spec[name].scale;
|
|
703
|
+
delete spec[name].logBase;
|
|
704
|
+
}
|
|
550
705
|
return { spec, issues };
|
|
551
706
|
}
|
|
552
707
|
function cloneChartSpec(spec) {
|
|
@@ -568,6 +723,11 @@ function cloneChartSeries(series) {
|
|
|
568
723
|
if (series.pointColors) copy.pointColors = [...series.pointColors];
|
|
569
724
|
if (series.format) copy.format = { ...series.format };
|
|
570
725
|
if (series.trendlines) copy.trendlines = series.trendlines.map((t) => ({ ...t }));
|
|
726
|
+
for (const name of ["errorBars", "xErrorBars"]) {
|
|
727
|
+
const bars = series[name];
|
|
728
|
+
if (!bars) continue;
|
|
729
|
+
copy[name] = { ...bars, ...bars.plus ? { plus: [...bars.plus] } : {}, ...bars.minus ? { minus: [...bars.minus] } : {} };
|
|
730
|
+
}
|
|
571
731
|
return copy;
|
|
572
732
|
}
|
|
573
733
|
function chartDataFromTable(rows, options = {}) {
|
|
@@ -670,5 +830,16 @@ function chartColorInputValue(color) {
|
|
|
670
830
|
|
|
671
831
|
|
|
672
832
|
|
|
673
|
-
|
|
674
|
-
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
exports.parseChartColor = parseChartColor; exports.chartRgbToHex = chartRgbToHex; exports.shadeChartColor = shadeChartColor; exports.CHART_PALETTE_SHADES = CHART_PALETTE_SHADES; exports.cyclePaletteColor = cyclePaletteColor; exports.chartLuminance = chartLuminance; exports.chartContrastRatio = chartContrastRatio; exports.chartTextOn = chartTextOn; exports.chartRgbToOklab = chartRgbToOklab; exports.chartColorDistance = chartColorDistance; exports.simulateChartVision = simulateChartVision; exports.checkChartColors = checkChartColors; exports.CHART_ERROR_BAR_TYPES = CHART_ERROR_BAR_TYPES; exports.CHART_ERROR_BAR_DIRECTIONS = CHART_ERROR_BAR_DIRECTIONS; exports.CHART_ERROR_BAR_LABELS = CHART_ERROR_BAR_LABELS; exports.defaultChartErrorBarValue = defaultChartErrorBarValue; exports.chartErrorAmounts = chartErrorAmounts; exports.describeChartErrorBars = describeChartErrorBars; exports.chartErrorBarsOfType = chartErrorBarsOfType; exports.formatChartAmountList = formatChartAmountList; exports.parseChartAmountList = parseChartAmountList; exports.CHART_TYPES = CHART_TYPES; exports.CHART_MARKERS = CHART_MARKERS; exports.CHART_TRENDLINE_TYPES = CHART_TRENDLINE_TYPES; exports.CHART_LABEL_POSITIONS = CHART_LABEL_POSITIONS; exports.CHART_AXIS_KINDS = CHART_AXIS_KINDS; exports.CHART_AXIS_SCALES = CHART_AXIS_SCALES; exports.CHART_SERIES_TYPES = CHART_SERIES_TYPES; exports.CHART_STACKINGS = CHART_STACKINGS; exports.CHART_CURVES = CHART_CURVES; exports.CHART_ORIENTATIONS = CHART_ORIENTATIONS; exports.CHART_LEGEND_POSITIONS = CHART_LEGEND_POSITIONS; exports.CHART_NUMBER_STYLES = CHART_NUMBER_STYLES; exports.CHART_TYPE_LABELS = CHART_TYPE_LABELS; exports.DEFAULT_CHART_PALETTE = DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = DEFAULT_CHART_THEME; exports.CSS_VARIABLE_CHART_THEME = CSS_VARIABLE_CHART_THEME; exports.isCartesianChart = isCartesianChart; exports.isXyChart = isXyChart; exports.chartFamily = chartFamily; exports.chartColorsByCategory = chartColorsByCategory; exports.defaultChartAxis = defaultChartAxis; exports.createChartSpec = createChartSpec; exports.chartSeriesColor = chartSeriesColor; exports.chartSliceColor = chartSliceColor; exports.chartPointColor = chartPointColor; exports.chartSeriesType = chartSeriesType; exports.uniqueChartSeriesId = uniqueChartSeriesId; exports.parseChartValue = parseChartValue; exports.normalizeChartAxis = normalizeChartAxis; exports.normalizeChartValues = normalizeChartValues; exports.normalizeChartErrorBars = normalizeChartErrorBars; exports.normalizeChartTrendline = normalizeChartTrendline; exports.normalizeChartSpec = normalizeChartSpec; exports.cloneChartSpec = cloneChartSpec; exports.cloneChartSeries = cloneChartSeries; exports.chartDataFromTable = chartDataFromTable; exports.chartDataToTable = chartDataToTable; exports.chartColorInputValue = chartColorInputValue;
|
|
845
|
+
//# sourceMappingURL=chunk-CKRNELPO.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-CKRNELPO.cjs","../src/chart/color.ts","../src/chart/errorbars.ts","../src/chart/spec.ts"],"names":["text"],"mappings":"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AAC4B,IAAA;AAChB,MAAA;AACmC,MAAA;AACjD,MAAA;AACA,MAAA;AACnB,IAAA;AACqB,EAAA;AACvB;AAG2D;AACnD,EAAA;AACH,IAAA;AAC4B,IAAA;AACS,IAAA;AACiB,IAAA;AACA,IAAA;AACG,IAAA;AACnC,IAAA;AACA,IAAA;AAC1B,EAAA;AACD;AAEmE;AACA,EAAA;AAC/B,EAAA;AACY,EAAA;AACkB,EAAA;AACb,EAAA;AAC4B,EAAA;AACvB,EAAA;AAChC,IAAA;AACb,IAAA;AACqG,IAAA;AACjH,EAAA;AACO,EAAA;AACR;AA8BiI;AACjB,EAAA;AAC9E,EAAA;AACsB,IAAA;AACc,IAAA;AACrE,EAAA;AAC8B,EAAA;AACgC,EAAA;AACX,EAAA;AACgE,EAAA;AACjF,EAAA;AACI,EAAA;AACA,EAAA;AACxB,IAAA;AACiF,IAAA;AAC9F,EAAA;AAC8B,EAAA;AACO,EAAA;AACyE,IAAA;AAC5E,IAAA;AACY,MAAA;AACnB,MAAA;AACqE,QAAA;AACvF,QAAA;AACR,MAAA;AACO,MAAA;AACP,IAAA;AACgD,IAAA;AAClD,EAAA;AAC8B,EAAA;AACA,IAAA;AACe,MAAA;AACuC,MAAA;AACjE,MAAA;AACjB,IAAA;AACkC,IAAA;AACpC,EAAA;AACoC,EAAA;AACrC;AAG0J;AAClJ,EAAA;AAC0D,IAAA;AACkC,IAAA;AACnG,EAAA;AACD;AAG4D;AACC,EAAA;AAC+C,EAAA;AACpG,EAAA;AACR;AHoHkH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-CKRNELPO.cjs","sourcesContent":[null,"// Portions ported from gridcraft-main/crates/chart/src/resolve.rs (palette tint cycle) and\n// crates/chart/src/render.rs (`on`: label colour from the fill), and designcraft-main/crates/color/src/cms/mod.rs\n// (`simulate_cvd`, Machado–Oliveira–Fernandes 2009 matrices) (MIT OR Apache-2.0, © ArtCraft Team and contributors).\n// See THIRD_PARTY_NOTICES.md.\n\n/** An sRGB colour with channels from 0 to 1. */\nexport type ChartRgb = [number, number, number];\n\nconst NAMED: Record<string, string> = {\n\tblack: '#000000',\n\twhite: '#ffffff',\n\tred: '#ff0000',\n\tgreen: '#008000',\n\tblue: '#0000ff',\n\tyellow: '#ffff00',\n\torange: '#ffa500',\n\tpurple: '#800080',\n\tgray: '#808080',\n\tgrey: '#808080',\n\tteal: '#008080',\n\tnavy: '#000080',\n\tmaroon: '#800000',\n\tolive: '#808000',\n\tsilver: '#c0c0c0',\n\tlime: '#00ff00',\n\taqua: '#00ffff',\n\tcyan: '#00ffff',\n\tfuchsia: '#ff00ff',\n\tmagenta: '#ff00ff',\n\tpink: '#ffc0cb',\n\tbrown: '#a52a2a'\n};\n\n/**\n * Reads `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb()` / `rgba()` and a few colour names. Returns\n * `null` for anything else (CSS variables, `hsl()`, …), so callers can leave such colours alone.\n */\nexport function parseChartColor(color: string): ChartRgb | null {\n\tconst text = color.trim().toLowerCase();\n\tconst hex = NAMED[text] ?? text;\n\tlet m = /^#([0-9a-f]{3})$/.exec(hex);\n\tif (m) return [...m[1]].map((c) => parseInt(c + c, 16) / 255) as ChartRgb;\n\tm = /^#([0-9a-f]{6})([0-9a-f]{2})?$/.exec(hex);\n\tif (m) return [0, 2, 4].map((i) => parseInt(m![1].slice(i, i + 2), 16) / 255) as ChartRgb;\n\tm = /^rgba?\\(\\s*([\\d.]+)%?[\\s,]+([\\d.]+)%?[\\s,]+([\\d.]+)%?(?:[\\s,/]+[\\d.]+%?)?\\s*\\)$/.exec(text);\n\tif (m) {\n\t\tconst pct = text.includes('%');\n\t\treturn [m[1], m[2], m[3]].map((v) => Math.max(0, Math.min(1, Number(v) / (pct ? 100 : 255)))) as ChartRgb;\n\t}\n\treturn null;\n}\n\nexport function chartRgbToHex(rgb: ChartRgb): string {\n\treturn `#${rgb.map((c) => Math.round(Math.max(0, Math.min(1, c)) * 255).toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * A lighter (`amount` > 0, towards white) or darker (`amount` < 0, towards black) shade of\n * `color`. Colours it cannot read (CSS variables) come back unchanged.\n */\nexport function shadeChartColor(color: string, amount: number): string {\n\tconst rgb = parseChartColor(color);\n\tif (!rgb || !amount) return color;\n\tconst t = Math.max(-1, Math.min(1, amount));\n\treturn chartRgbToHex(rgb.map((c) => (t > 0 ? c + (1 - c) * t : c * (1 + t))) as ChartRgb);\n}\n\n/** Shades used once a palette is used up: the same hues, lighter then darker (GridCraft's cycle). */\nexport const CHART_PALETTE_SHADES: readonly number[] = [0, 0.4, -0.25, 0.6, -0.5, 0.2];\n\n/** The palette colour for the `index`-th item: the palette in order, then lighter and darker rounds of it. */\nexport function cyclePaletteColor(palette: readonly string[], index: number): string {\n\tconst base = palette[index % palette.length];\n\tconst round = Math.floor(index / palette.length) % CHART_PALETTE_SHADES.length;\n\treturn shadeChartColor(base, CHART_PALETTE_SHADES[round]);\n}\n\nconst toLinear = (c: number) => (c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));\nconst fromLinear = (c: number) => (c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055);\n\n/** WCAG relative luminance (0 black – 1 white). */\nexport function chartLuminance(rgb: ChartRgb): number {\n\tconst [r, g, b] = rgb.map(toLinear);\n\treturn 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG contrast ratio (1–21) between two colours, or `null` when either cannot be read. */\nexport function chartContrastRatio(a: string, b: string): number | null {\n\tconst ra = parseChartColor(a);\n\tconst rb = parseChartColor(b);\n\tif (!ra || !rb) return null;\n\tconst la = chartLuminance(ra);\n\tconst lb = chartLuminance(rb);\n\treturn (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);\n}\n\n/**\n * Dark or white text, whichever reads better on `fill`; `fallback` when the fill cannot be\n * read (a CSS variable).\n */\nexport function chartTextOn(fill: string, fallback: string, dark = '#0f172a', light = '#ffffff'): string {\n\tconst rgb = parseChartColor(fill);\n\tif (!rgb) return fallback;\n\tconst darkRatio = chartContrastRatio(fill, dark)!;\n\tconst lightRatio = chartContrastRatio(fill, light)!;\n\treturn darkRatio >= lightRatio ? dark : light;\n}\n\n/** OKLab (Ottosson) from sRGB. */\nexport function chartRgbToOklab(rgb: ChartRgb): [number, number, number] {\n\tconst [r, g, b] = rgb.map(toLinear);\n\tconst l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n\tconst m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n\tconst s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n\treturn [\n\t\t0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n\t\t1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n\t\t0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s\n\t];\n}\n\n/** Perceptual distance between two colours (Euclidean in OKLab; ≈0.02 is just noticeable). */\nexport function chartColorDistance(a: ChartRgb, b: ChartRgb): number {\n\tconst p = chartRgbToOklab(a);\n\tconst q = chartRgbToOklab(b);\n\treturn Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]);\n}\n\nexport type ChartVision = 'normal' | 'protanopia' | 'deuteranopia' | 'tritanopia';\n\n// Machado, Oliveira & Fernandes (2009), severity 1.0, applied in linear RGB.\nconst CVD: Record<Exclude<ChartVision, 'normal'>, number[][]> = {\n\tprotanopia: [\n\t\t[0.152286, 1.052583, -0.204868],\n\t\t[0.114503, 0.786281, 0.099216],\n\t\t[-0.003882, -0.048116, 1.051998]\n\t],\n\tdeuteranopia: [\n\t\t[0.367322, 0.860646, -0.227968],\n\t\t[0.280085, 0.672501, 0.047413],\n\t\t[-0.01182, 0.04294, 0.968881]\n\t],\n\ttritanopia: [\n\t\t[1.255528, -0.076749, -0.178779],\n\t\t[-0.078411, 0.930809, 0.147602],\n\t\t[0.004733, 0.691367, 0.3039]\n\t]\n};\n\n/** How a colour looks with a colour-vision deficiency (Machado et al. 2009, full severity). */\nexport function simulateChartVision(rgb: ChartRgb, vision: ChartVision): ChartRgb {\n\tif (vision === 'normal') return rgb;\n\tconst lin = rgb.map(toLinear);\n\tconst m = CVD[vision];\n\treturn m.map((row) => fromLinear(Math.max(0, Math.min(1, row[0] * lin[0] + row[1] * lin[1] + row[2] * lin[2])))) as ChartRgb;\n}\n\nexport interface ChartColorPair {\n\ta: number;\n\tb: number;\n\tcolors: [string, string];\n\tdistance: number;\n}\n\nexport interface ChartColorCheck {\n\t/** No problems found. */\n\tok: boolean;\n\t/** Per vision: the closest pair of colours and their OKLab distance. */\n\tclosest: Partial<Record<ChartVision, ChartColorPair>>;\n\t/** Contrast ratio of each colour against the surface (null when unreadable). */\n\tcontrast: (number | null)[];\n\t/** Problems, as sentences. */\n\tissues: string[];\n\t/** Colours that could not be read (CSS variables, `hsl()`); they are skipped. */\n\tskipped: string[];\n}\n\nexport interface ChartColorCheckOptions {\n\t/** The page colour behind the marks (default white). */\n\tsurface?: string;\n\t/** Smallest OKLab distance two series may have (default 0.08). */\n\tminDistance?: number;\n\t/** Smallest contrast ratio against the surface (default 1.5; WCAG asks 3 for graphics). */\n\tminContrast?: number;\n\t/** Visions to check (default all four). */\n\tvisions?: readonly ChartVision[];\n}\n\n/**\n * Checks that series colours can be told apart, with normal vision and the three\n * colour-vision deficiencies, and stand out from the surface. Returns the closest pair per\n * vision and problems as sentences.\n */\nexport function checkChartColors(colors: readonly string[], options: ChartColorCheckOptions = {}): ChartColorCheck {\n\tconst surface = options.surface ?? '#ffffff';\n\tconst minDistance = options.minDistance ?? 0.08;\n\tconst minContrast = options.minContrast ?? 1.5;\n\tconst visions = options.visions ?? (['normal', 'protanopia', 'deuteranopia', 'tritanopia'] as const);\n\tconst parsed = colors.map(parseChartColor);\n\tconst skipped = colors.filter((_, i) => !parsed[i]);\n\tconst issues: string[] = [];\n\tconst closest: ChartColorCheck['closest'] = {};\n\tfor (const vision of visions) {\n\t\tconst seen = parsed.map((c) => (c ? simulateChartVision(c, vision) : null));\n\t\tlet best: ChartColorPair | undefined;\n\t\tfor (let a = 0; a < seen.length; a++) {\n\t\t\tfor (let b = a + 1; b < seen.length; b++) {\n\t\t\t\tif (!seen[a] || !seen[b]) continue;\n\t\t\t\tconst distance = chartColorDistance(seen[a]!, seen[b]!);\n\t\t\t\tif (!best || distance < best.distance) best = { a, b, colors: [colors[a], colors[b]], distance: Math.round(distance * 1000) / 1000 };\n\t\t\t}\n\t\t}\n\t\tif (best) {\n\t\t\tclosest[vision] = best;\n\t\t\tif (best.distance < minDistance) {\n\t\t\t\tconst who = vision === 'normal' ? '' : ` with ${vision}`;\n\t\t\t\tissues.push(`Colours ${best.a + 1} (${best.colors[0]}) and ${best.b + 1} (${best.colors[1]}) are hard to tell apart${who} (distance ${best.distance}, want at least ${minDistance}).`);\n\t\t\t}\n\t\t}\n\t}\n\tconst contrast = colors.map((c) => {\n\t\tconst ratio = chartContrastRatio(c, surface);\n\t\treturn ratio === null ? null : Math.round(ratio * 100) / 100;\n\t});\n\tcontrast.forEach((ratio, i) => {\n\t\tif (ratio !== null && ratio < minContrast) issues.push(`Colour ${i + 1} (${colors[i]}) barely stands out from the background ${surface} (contrast ${ratio}:1, want at least ${minContrast}:1).`);\n\t});\n\treturn { ok: issues.length === 0, closest, contrast, issues, skipped };\n}\n","import type { ChartErrorBars, ChartErrorBarType, ChartValue } from './types.js';\n\nexport const CHART_ERROR_BAR_TYPES: readonly ChartErrorBarType[] = ['fixed', 'percent', 'stddev', 'stderr', 'custom'];\nexport const CHART_ERROR_BAR_DIRECTIONS: readonly NonNullable<ChartErrorBars['direction']>[] = ['both', 'plus', 'minus'];\n\n/** Labels for pickers, shared by the React and Svelte components. */\nexport const CHART_ERROR_BAR_LABELS: Readonly<Record<ChartErrorBarType, string>> = {\n\tfixed: 'Fixed amount',\n\tpercent: 'Percentage',\n\tstddev: 'Standard deviation',\n\tstderr: 'Standard error',\n\tcustom: 'Custom'\n};\n\n/** The default `value` per type (`fixed` 1, `percent` 5, `stddev` 1). */\nexport function defaultChartErrorBarValue(type: ChartErrorBarType): number | undefined {\n\treturn type === 'fixed' ? 1 : type === 'percent' ? 5 : type === 'stddev' ? 1 : undefined;\n}\n\n/** One point's error bar: where it is centred and how far it reaches each way (both 0 or more). */\nexport interface ChartErrorAmount {\n\t/** The point's value, or the series mean for `stddev` (as Excel draws it). */\n\tcenter: number;\n\tplus: number;\n\tminus: number;\n}\n\n/** Mean and sample standard deviation of the finite values (sd 0 with fewer than 2). */\nfunction meanAndSd(values: readonly ChartValue[]): { mean: number; sd: number; n: number } {\n\tconst xs = values.filter((v): v is number => v !== null && Number.isFinite(v));\n\tconst n = xs.length;\n\tif (!n) return { mean: 0, sd: 0, n };\n\tconst mean = xs.reduce((t, v) => t + v, 0) / n;\n\tconst sd = n > 1 ? Math.sqrt(xs.reduce((t, v) => t + (v - mean) ** 2, 0) / (n - 1)) : 0;\n\treturn { mean, sd, n };\n}\n\n/**\n * The error bar at each point of `values` (a series' values, or its x values for x error\n * bars), following Excel's error amount types: `fixed` and `percent` from `value`, `stddev`\n * around the series mean, `stderr` (sample standard deviation / √n) and `custom` amounts from\n * `plus` / `minus`. Gaps (and custom points without an amount) give `null`.\n */\nexport function chartErrorAmounts(bars: ChartErrorBars, values: readonly ChartValue[]): (ChartErrorAmount | null)[] {\n\tconst direction = bars.direction ?? 'both';\n\tconst up = direction !== 'minus';\n\tconst down = direction !== 'plus';\n\tconst stats = bars.type === 'stddev' || bars.type === 'stderr' ? meanAndSd(values) : null;\n\tconst amount = bars.value ?? defaultChartErrorBarValue(bars.type) ?? 0;\n\treturn values.map((v, i) => {\n\t\tif (v === null || !Number.isFinite(v)) return null;\n\t\tlet plus: number;\n\t\tlet minus: number;\n\t\tlet center = v;\n\t\tswitch (bars.type) {\n\t\t\tcase 'fixed':\n\t\t\t\tplus = minus = Math.abs(amount);\n\t\t\t\tbreak;\n\t\t\tcase 'percent':\n\t\t\t\tplus = minus = Math.abs((v * amount) / 100);\n\t\t\t\tbreak;\n\t\t\tcase 'stddev':\n\t\t\t\tcenter = stats!.mean;\n\t\t\t\tplus = minus = Math.abs(amount) * stats!.sd;\n\t\t\t\tbreak;\n\t\t\tcase 'stderr':\n\t\t\t\tplus = minus = stats!.n ? stats!.sd / Math.sqrt(stats!.n) : 0;\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tconst p = bars.plus?.[i] ?? null;\n\t\t\t\tconst m = bars.minus?.[i] ?? (bars.minus ? null : p);\n\t\t\t\tif ((p === null || !Number.isFinite(p)) && (m === null || !Number.isFinite(m))) return null;\n\t\t\t\tplus = p !== null && Number.isFinite(p) ? Math.abs(p) : 0;\n\t\t\t\tminus = m !== null && Number.isFinite(m) ? Math.abs(m) : 0;\n\t\t\t}\n\t\t}\n\t\treturn { center, plus: up ? plus : 0, minus: down ? minus : 0 };\n\t});\n}\n\n/** A one-line description of error bars (\"±5% error bars\", \"±1 standard deviation error bars\"). */\nexport function describeChartErrorBars(bars: ChartErrorBars): string {\n\tconst sign = bars.direction === 'plus' ? '+' : bars.direction === 'minus' ? '−' : '±';\n\tconst value = bars.value ?? defaultChartErrorBarValue(bars.type);\n\tswitch (bars.type) {\n\t\tcase 'fixed':\n\t\t\treturn `${sign}${value} error bars`;\n\t\tcase 'percent':\n\t\t\treturn `${sign}${value}% error bars`;\n\t\tcase 'stddev':\n\t\t\treturn `${sign}${value} standard deviation${value === 1 ? '' : 's'} error bars`;\n\t\tcase 'stderr':\n\t\t\treturn `${sign}standard error bars`;\n\t\tdefault:\n\t\t\treturn 'custom error bars';\n\t}\n}\n\n/**\n * Error bars for a picker change: `null` for none, else bars of `type` that keep the current\n * direction and caps. Switching to `custom` starts from the amounts the current bars (or ±1)\n * draw, so the picture does not jump. Shared by the React and Svelte inspectors.\n */\nexport function chartErrorBarsOfType(type: ChartErrorBarType | '' | null, current: ChartErrorBars | undefined, values: readonly ChartValue[]): ChartErrorBars | null {\n\tif (!type) return null;\n\tconst keep: Partial<ChartErrorBars> = { ...(current?.direction ? { direction: current.direction } : {}), ...(current?.cap === false ? { cap: false } : {}) };\n\tif (type !== 'custom') return { type, ...keep, ...(current?.type === type && current.value !== undefined ? { value: current.value } : {}) };\n\tif (current?.type === 'custom') return current;\n\tconst amounts = chartErrorAmounts({ ...(current ?? { type: 'fixed' }), direction: 'both' }, values);\n\tconst round = (n: number) => Number(n.toPrecision(4));\n\tconst plus = amounts.map((a) => (a ? round(a.plus) : null));\n\tconst minus = amounts.map((a) => (a ? round(a.minus) : null));\n\treturn { type, plus, ...(JSON.stringify(minus) !== JSON.stringify(plus) ? { minus } : {}), ...keep };\n}\n\n/** Custom amounts as text for an input: \"1, 2, -, 0.5\" (`-` is a point without a bar). */\nexport function formatChartAmountList(values: readonly ChartValue[] | undefined): string {\n\treturn (values ?? []).map((v) => (v === null ? '-' : String(v))).join(', ');\n}\n\n/** Reads amounts typed as \"1, 2, -, 0.5\" (commas, semicolons or spaces; `-` or blank for none). */\nexport function parseChartAmountList(text: string): (string | null)[] {\n\treturn text\n\t\t.split(/[;,\\s]+/)\n\t\t.filter((t) => t !== '')\n\t\t.map((t) => (t === '-' ? null : t));\n}\n","import { cyclePaletteColor } from './color.js';\nimport { CHART_ERROR_BAR_DIRECTIONS, CHART_ERROR_BAR_TYPES } from './errorbars.js';\nimport type {\n\tChartAxis,\n\tChartCurve,\n\tChartErrorBars,\n\tChartIssue,\n\tChartLabelPosition,\n\tChartLegend,\n\tChartLegendPosition,\n\tChartMarker,\n\tChartNumberFormat,\n\tChartOrientation,\n\tChartSeries,\n\tChartSeriesType,\n\tChartSpec,\n\tChartStacking,\n\tChartTheme,\n\tChartTrendline,\n\tChartTrendlineType,\n\tChartType,\n\tChartValue\n} from './types.js';\n\nexport const CHART_TYPES: readonly ChartType[] = ['bar', 'line', 'area', 'scatter', 'bubble', 'pie', 'donut', 'radar', 'waterfall', 'histogram', 'box', 'funnel', 'treemap'];\nexport const CHART_MARKERS: readonly ChartMarker[] = ['circle', 'square', 'diamond', 'triangle', 'cross', 'none'];\nexport const CHART_TRENDLINE_TYPES: readonly ChartTrendlineType[] = ['linear', 'exponential', 'logarithmic', 'power', 'polynomial', 'moving-average'];\nexport const CHART_LABEL_POSITIONS: readonly ChartLabelPosition[] = ['auto', 'inside', 'outside', 'center'];\nexport const CHART_AXIS_KINDS: readonly NonNullable<ChartAxis['kind']>[] = ['category', 'date'];\nexport const CHART_AXIS_SCALES: readonly NonNullable<ChartAxis['scale']>[] = ['linear', 'log'];\nexport const CHART_SERIES_TYPES: readonly ChartSeriesType[] = ['bar', 'line', 'area', 'scatter'];\nexport const CHART_STACKINGS: readonly ChartStacking[] = ['none', 'stacked', 'percent'];\nexport const CHART_CURVES: readonly ChartCurve[] = ['linear', 'smooth', 'step'];\nexport const CHART_ORIENTATIONS: readonly ChartOrientation[] = ['vertical', 'horizontal'];\nexport const CHART_LEGEND_POSITIONS: readonly ChartLegendPosition[] = ['top', 'bottom', 'left', 'right'];\nexport const CHART_NUMBER_STYLES: readonly NonNullable<ChartNumberFormat['style']>[] = ['number', 'percent', 'currency', 'compact'];\n\n/** Labels for pickers, shared by the React and Svelte components. */\nexport const CHART_TYPE_LABELS: Readonly<Record<ChartType, string>> = {\n\tbar: 'Bar',\n\tline: 'Line',\n\tarea: 'Area',\n\tscatter: 'Scatter',\n\tbubble: 'Bubble',\n\tpie: 'Pie',\n\tdonut: 'Donut',\n\tradar: 'Radar',\n\twaterfall: 'Waterfall',\n\thistogram: 'Histogram',\n\tbox: 'Box plot',\n\tfunnel: 'Funnel',\n\ttreemap: 'Treemap'\n};\n\n/** How a chart type is laid out. */\nexport type ChartFamily = 'cartesian' | 'xy' | 'pie' | 'radar' | 'waterfall' | 'histogram' | 'box' | 'funnel' | 'treemap';\n\n/** A colour-blind-friendly categorical palette (Okabe–Ito order, tuned for light and dark backgrounds). */\nexport const DEFAULT_CHART_PALETTE: readonly string[] = ['#4269d0', '#efb118', '#ff725c', '#6cc5b0', '#3ca951', '#ff8ab7', '#a463f2', '#97bbf5', '#9c6b4e', '#9498a0'];\n\nexport const DEFAULT_CHART_THEME: ChartTheme = {\n\tbackground: '#ffffff',\n\tsurface: '#ffffff',\n\ttext: '#0f172a',\n\tmutedText: '#64748b',\n\tgrid: '#e2e8f0',\n\taxis: '#94a3b8',\n\tselection: '#2563eb',\n\tpositive: '#3ca951',\n\tnegative: '#e5484d',\n\tfontFamily: 'system-ui, -apple-system, \"Segoe UI\", sans-serif',\n\tfontSize: 11,\n\ttitleSize: 15\n};\n\n/**\n * A theme that reads the page's `--background`, `--foreground`, `--muted-foreground`,\n * `--border` and `--primary` colour variables (full colours, as the other components'\n * inline styles use them), with light fallbacks. The React and Svelte canvases use it.\n */\nexport const CSS_VARIABLE_CHART_THEME: ChartTheme = {\n\t...DEFAULT_CHART_THEME,\n\tbackground: 'transparent',\n\tsurface: 'var(--background, #ffffff)',\n\ttext: 'var(--foreground, #0f172a)',\n\tmutedText: 'var(--muted-foreground, #64748b)',\n\tgrid: 'var(--border, #e2e8f0)',\n\taxis: 'var(--muted-foreground, #94a3b8)',\n\tselection: 'var(--primary, #2563eb)',\n\tfontFamily: 'inherit'\n};\n\n/** Bar, line, area and scatter: categories (or numeric x) against values, series may mix. */\nexport function isCartesianChart(type: ChartType): boolean {\n\treturn type === 'bar' || type === 'line' || type === 'area' || type === 'scatter';\n}\n\n/** Whether the chart plots series against a numeric x axis (bubble charts, and scatter charts with x values). */\nexport function isXyChart(spec: Pick<ChartSpec, 'type' | 'series'>): boolean {\n\tif (spec.type === 'bubble') return true;\n\treturn spec.type === 'scatter' && spec.series.some((s) => !s.hidden && Array.isArray(s.x) && s.x.some((v) => v !== null));\n}\n\n/** How a chart is laid out (see `ChartType`). */\nexport function chartFamily(spec: Pick<ChartSpec, 'type' | 'series'>): ChartFamily {\n\tif (isXyChart(spec)) return 'xy';\n\tswitch (spec.type) {\n\t\tcase 'pie':\n\t\tcase 'donut':\n\t\t\treturn 'pie';\n\t\tcase 'radar':\n\t\tcase 'waterfall':\n\t\tcase 'histogram':\n\t\tcase 'box':\n\t\tcase 'funnel':\n\t\tcase 'treemap':\n\t\t\treturn spec.type;\n\t\tcase 'bubble':\n\t\t\treturn 'xy';\n\t\tdefault:\n\t\t\treturn 'cartesian';\n\t}\n}\n\n/** Chart types whose legend lists categories (one colour per category) rather than series. */\nexport function chartColorsByCategory(type: ChartType): boolean {\n\treturn type === 'pie' || type === 'donut' || type === 'funnel' || type === 'treemap';\n}\n\nexport function defaultChartAxis(value: boolean): ChartAxis {\n\treturn { show: true, title: '', min: null, max: null, step: null, gridlines: value, format: {} };\n}\n\n/** A complete spec with every default filled in. */\nexport function createChartSpec(partial: Partial<ChartSpec> = {}): ChartSpec {\n\treturn normalizeChartSpec(partial).spec;\n}\n\n/** The colour a series is drawn with. */\nexport function chartSeriesColor(spec: Pick<ChartSpec, 'palette' | 'series'>, seriesIndex: number): string {\n\tconst series = spec.series[seriesIndex];\n\tif (series?.color) return series.color;\n\treturn cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, seriesIndex);\n}\n\n/** The colour a pie slice is drawn with (by category). */\nexport function chartSliceColor(spec: Pick<ChartSpec, 'palette'>, index: number): string {\n\treturn cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, index);\n}\n\n/** The colour of one bar or point: its override, else the series colour. */\nexport function chartPointColor(spec: Pick<ChartSpec, 'palette' | 'series'>, seriesIndex: number, index: number): string {\n\treturn spec.series[seriesIndex]?.pointColors?.[index] || chartSeriesColor(spec, seriesIndex);\n}\n\n/** How a series is drawn in a cartesian chart. */\nexport function chartSeriesType(spec: Pick<ChartSpec, 'type'>, series: ChartSeries): ChartSeriesType {\n\tif (series.type) return series.type;\n\tif (spec.type === 'bubble') return 'scatter';\n\treturn isCartesianChart(spec.type) ? (spec.type as ChartSeriesType) : 'bar';\n}\n\n/** An id not used by any series (`series-1`, `series-2`, …). */\nexport function uniqueChartSeriesId(series: readonly Pick<ChartSeries, 'id'>[], base = 'series'): string {\n\tconst used = new Set(series.map((s) => s.id));\n\tfor (let i = series.length + 1; ; i++) {\n\t\tconst id = `${base}-${i}`;\n\t\tif (!used.has(id)) return id;\n\t}\n}\n\n/**\n * Reads a number the way people type it in a data grid: `1,234.5`, `12%` (→ 0.12),\n * `$40`, `(3)` (→ -3). Blank → `null`. Returns `undefined` when it is not a number.\n */\nexport function parseChartValue(input: unknown): ChartValue | undefined {\n\tif (input === null || input === undefined) return null;\n\tif (typeof input === 'number') return Number.isFinite(input) ? input : undefined;\n\tif (typeof input !== 'string') return undefined;\n\tlet text = input.trim();\n\tif (!text || text === '-' || text === '—') return null;\n\tlet negative = false;\n\tif (/^\\(.*\\)$/.test(text)) {\n\t\tnegative = true;\n\t\ttext = text.slice(1, -1).trim();\n\t}\n\tconst percent = text.endsWith('%');\n\tif (percent) text = text.slice(0, -1).trim();\n\ttext = text.replace(/^[$€£¥]/, '').replace(/,/g, '').replace(/\\s+/g, '');\n\tif (!/^[-+]?(\\d+\\.?\\d*|\\.\\d+)(e[-+]?\\d+)?$/i.test(text)) return undefined;\n\tlet value = Number(text);\n\tif (percent) value /= 100;\n\tif (negative) value = -value;\n\treturn Number.isFinite(value) ? value : undefined;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);\n\nfunction pick<T extends string>(value: unknown, options: readonly T[], fallback: T, path: string, issues: ChartIssue[]): T {\n\tif (value === undefined) return fallback;\n\tif (typeof value === 'string' && (options as readonly string[]).includes(value)) return value as T;\n\tissues.push({ path, message: `${path} must be one of ${options.map((o) => `\"${o}\"`).join(', ')}; got ${JSON.stringify(value)}.` });\n\treturn fallback;\n}\n\nfunction text(value: unknown, fallback: string, path: string, issues: ChartIssue[]): string {\n\tif (value === undefined || value === null) return fallback;\n\tif (typeof value === 'string') return value;\n\tif (typeof value === 'number' || typeof value === 'boolean') return String(value);\n\tissues.push({ path, message: `${path} must be text.` });\n\treturn fallback;\n}\n\nfunction flag(value: unknown, fallback: boolean, path: string, issues: ChartIssue[]): boolean {\n\tif (value === undefined) return fallback;\n\tif (typeof value === 'boolean') return value;\n\tissues.push({ path, message: `${path} must be true or false.` });\n\treturn fallback;\n}\n\nfunction bound(value: unknown, path: string, issues: ChartIssue[]): number | null {\n\tif (value === undefined || value === null || value === '') return null;\n\tconst n = typeof value === 'string' ? Number(value) : value;\n\tif (typeof n === 'number' && Number.isFinite(n)) return n;\n\tissues.push({ path, message: `${path} must be a number or null.` });\n\treturn null;\n}\n\nfunction normalizeFormat(value: unknown, path: string, issues: ChartIssue[]): ChartNumberFormat {\n\tif (value === undefined || value === null) return {};\n\tif (!isRecord(value)) {\n\t\tissues.push({ path, message: `${path} must be an object.` });\n\t\treturn {};\n\t}\n\tconst out: ChartNumberFormat = {};\n\tif (value.style !== undefined) out.style = pick(value.style, CHART_NUMBER_STYLES, 'number', `${path}.style`, issues);\n\tif (value.decimals !== undefined) {\n\t\tconst d = Number(value.decimals);\n\t\tif (Number.isInteger(d) && d >= 0 && d <= 10) out.decimals = d;\n\t\telse issues.push({ path: `${path}.decimals`, message: `${path}.decimals must be a whole number from 0 to 10.` });\n\t}\n\tfor (const key of ['currency', 'prefix', 'suffix', 'code'] as const) {\n\t\tif (value[key] !== undefined) out[key] = text(value[key], '', `${path}.${key}`, issues);\n\t}\n\treturn out;\n}\n\nexport function normalizeChartAxis(value: unknown, fallback: ChartAxis, path: string, issues: ChartIssue[] = []): ChartAxis {\n\tif (value === undefined) return { ...fallback, format: { ...fallback.format } };\n\tif (!isRecord(value)) {\n\t\tissues.push({ path, message: `${path} must be an object.` });\n\t\treturn { ...fallback, format: { ...fallback.format } };\n\t}\n\tlet min = 'min' in value ? bound(value.min, `${path}.min`, issues) : fallback.min;\n\tlet max = 'max' in value ? bound(value.max, `${path}.max`, issues) : fallback.max;\n\tif (min !== null && max !== null && min >= max) {\n\t\tissues.push({ path: `${path}.max`, message: `${path}.max (${max}) must be greater than ${path}.min (${min}).` });\n\t\tmin = fallback.min;\n\t\tmax = fallback.max;\n\t}\n\tlet step = 'step' in value ? bound(value.step, `${path}.step`, issues) : fallback.step;\n\tif (step !== null && !(step > 0)) {\n\t\tissues.push({ path: `${path}.step`, message: `${path}.step must be greater than 0 (or null for automatic).` });\n\t\tstep = fallback.step;\n\t}\n\tconst axis: ChartAxis = {\n\t\tshow: flag(value.show, fallback.show, `${path}.show`, issues),\n\t\ttitle: text(value.title, fallback.title, `${path}.title`, issues),\n\t\tmin,\n\t\tmax,\n\t\tstep,\n\t\tgridlines: flag(value.gridlines, fallback.gridlines, `${path}.gridlines`, issues),\n\t\tformat: 'format' in value ? normalizeFormat(value.format, `${path}.format`, issues) : { ...fallback.format }\n\t};\n\tconst kind = 'kind' in value ? (value.kind === null ? undefined : pick(value.kind, CHART_AXIS_KINDS, 'category', `${path}.kind`, issues)) : fallback.kind;\n\tif (kind && kind !== 'category') axis.kind = kind;\n\tconst scale = 'scale' in value ? (value.scale === null ? 'linear' : pick(value.scale, CHART_AXIS_SCALES, 'linear', `${path}.scale`, issues)) : (fallback.scale ?? 'linear');\n\tif (scale === 'log') {\n\t\taxis.scale = 'log';\n\t\tconst base = 'logBase' in value ? value.logBase : fallback.logBase;\n\t\tif (base !== undefined && base !== null) {\n\t\t\tconst b = Number(base);\n\t\t\tif (Number.isFinite(b) && b >= 2 && b <= 1000) {\n\t\t\t\tif (b !== 10) axis.logBase = b;\n\t\t\t} else issues.push({ path: `${path}.logBase`, message: `${path}.logBase must be a number from 2 to 1000 (default 10).` });\n\t\t}\n\t\tfor (const end of ['min', 'max'] as const) {\n\t\t\tif (axis[end] !== null && !(axis[end]! > 0)) {\n\t\t\t\tissues.push({ path: `${path}.${end}`, message: `${path}.${end} must be greater than 0 on a logarithmic axis (or null for automatic); got ${axis[end]}.` });\n\t\t\t\taxis[end] = null;\n\t\t\t}\n\t\t}\n\t}\n\tif ('reverse' in value ? value.reverse !== null && flag(value.reverse, false, `${path}.reverse`, issues) : fallback.reverse) axis.reverse = true;\n\treturn axis;\n}\n\nfunction normalizeLegend(value: unknown, issues: ChartIssue[]): ChartLegend {\n\tconst fallback: ChartLegend = { show: true, position: 'bottom' };\n\tif (value === undefined) return fallback;\n\tif (!isRecord(value)) {\n\t\tissues.push({ path: 'legend', message: 'legend must be an object.' });\n\t\treturn fallback;\n\t}\n\treturn {\n\t\tshow: flag(value.show, fallback.show, 'legend.show', issues),\n\t\tposition: pick(value.position, CHART_LEGEND_POSITIONS, fallback.position, 'legend.position', issues)\n\t};\n}\n\n/** Values as numbers or nulls; bad entries become null and are reported. */\nexport function normalizeChartValues(value: unknown, length: number | undefined, path: string, issues: ChartIssue[] = []): ChartValue[] {\n\tif (value === undefined) return length ? Array(length).fill(null) : [];\n\tif (!Array.isArray(value)) {\n\t\tissues.push({ path, message: `${path} must be an array of numbers.` });\n\t\treturn length ? Array(length).fill(null) : [];\n\t}\n\tconst out = value.map((v, i) => {\n\t\tconst parsed = parseChartValue(v);\n\t\tif (parsed === undefined) {\n\t\t\tissues.push({ path: `${path}[${i}]`, message: `${path}[${i}] is not a number: ${JSON.stringify(v)}.` });\n\t\t\treturn null;\n\t\t}\n\t\treturn parsed;\n\t});\n\tif (length === undefined) return out;\n\tif (out.length > length) return out.slice(0, length);\n\twhile (out.length < length) out.push(null);\n\treturn out;\n}\n\nfunction normalizeSeries(value: unknown, length: number, used: Set<string>, index: number, issues: ChartIssue[]): ChartSeries | null {\n\tconst path = `series[${index}]`;\n\tif (!isRecord(value)) {\n\t\tissues.push({ path, message: `${path} must be an object with a name and values.` });\n\t\treturn null;\n\t}\n\tlet id = typeof value.id === 'string' && value.id.trim() ? value.id.trim() : '';\n\tif (!id || used.has(id)) {\n\t\tif (id) issues.push({ path: `${path}.id`, message: `Series id \"${id}\" is used twice; the second was renamed.` });\n\t\tfor (let n = index + 1; ; n++) {\n\t\t\tid = `series-${n}`;\n\t\t\tif (!used.has(id)) break;\n\t\t}\n\t}\n\tused.add(id);\n\tconst series: ChartSeries = {\n\t\tid,\n\t\tname: text(value.name, `Series ${index + 1}`, `${path}.name`, issues),\n\t\tvalues: normalizeChartValues(value.values, length, `${path}.values`, issues)\n\t};\n\tif (typeof value.color === 'string' && value.color.trim()) series.color = value.color.trim();\n\tif (value.type !== undefined && value.type !== null) series.type = pick(value.type, CHART_SERIES_TYPES, 'bar', `${path}.type`, issues);\n\tif (value.hidden === true) series.hidden = true;\n\tif (value.axis !== undefined && value.axis !== null && pick(value.axis, ['primary', 'secondary'] as const, 'primary', `${path}.axis`, issues) === 'secondary') series.axis = 'secondary';\n\tfor (const key of ['x', 'sizes'] as const) {\n\t\tif (value[key] === undefined || value[key] === null) continue;\n\t\tconst list = normalizeChartValues(value[key], length, `${path}.${key}`, issues);\n\t\tif (list.some((v) => v !== null)) series[key] = list;\n\t}\n\tif (key(value, 'sizes') && series.sizes?.some((v) => v !== null && v < 0)) {\n\t\tissues.push({ path: `${path}.sizes`, message: `${path}.sizes must not be negative.` });\n\t\tseries.sizes = series.sizes.map((v) => (v !== null && v < 0 ? null : v));\n\t}\n\tif (value.pointColors !== undefined && value.pointColors !== null) {\n\t\tif (!Array.isArray(value.pointColors)) issues.push({ path: `${path}.pointColors`, message: `${path}.pointColors must be an array of colours or nulls.` });\n\t\telse {\n\t\t\tconst colors = Array.from({ length }, (_, i) => {\n\t\t\t\tconst c = (value.pointColors as unknown[])[i];\n\t\t\t\treturn typeof c === 'string' && c.trim() ? c.trim() : null;\n\t\t\t});\n\t\t\tif (colors.some((c) => c !== null)) series.pointColors = colors;\n\t\t}\n\t}\n\tif (value.marker !== undefined && value.marker !== null) series.marker = pick(value.marker, CHART_MARKERS, 'circle', `${path}.marker`, issues);\n\tif (value.curve !== undefined && value.curve !== null) series.curve = pick(value.curve, CHART_CURVES, 'linear', `${path}.curve`, issues);\n\tif (value.dataLabels !== undefined && value.dataLabels !== null) series.dataLabels = flag(value.dataLabels, false, `${path}.dataLabels`, issues);\n\tif (value.format !== undefined && value.format !== null) {\n\t\tconst format = normalizeFormat(value.format, `${path}.format`, issues);\n\t\tif (Object.keys(format).length) series.format = format;\n\t}\n\tfor (const name of ['errorBars', 'xErrorBars'] as const) {\n\t\tif (!key(value, name)) continue;\n\t\tconst bars = normalizeChartErrorBars(value[name], length, `${path}.${name}`, issues);\n\t\tif (bars) series[name] = bars;\n\t}\n\tif (value.trendlines !== undefined && value.trendlines !== null) {\n\t\tif (!Array.isArray(value.trendlines)) issues.push({ path: `${path}.trendlines`, message: `${path}.trendlines must be an array.` });\n\t\telse {\n\t\t\tconst lines = value.trendlines.map((t, i) => normalizeChartTrendline(t, `${path}.trendlines[${i}]`, issues)).filter((t): t is ChartTrendline => t !== null);\n\t\t\tif (lines.length) series.trendlines = lines;\n\t\t}\n\t}\n\treturn series;\n}\n\nconst key = (value: Record<string, unknown>, name: string) => value[name] !== undefined && value[name] !== null;\n\n/** Checks one set of error bars; `null` (reported) when it is unusable. Custom amounts are padded to `length`. */\nexport function normalizeChartErrorBars(value: unknown, length: number, path: string, issues: ChartIssue[] = []): ChartErrorBars | null {\n\tif (!isRecord(value)) {\n\t\tissues.push({ path, message: `${path} must be an object with a type (${CHART_ERROR_BAR_TYPES.join(', ')}), or null for none.` });\n\t\treturn null;\n\t}\n\tconst before = issues.length;\n\tconst type = pick(value.type, CHART_ERROR_BAR_TYPES, 'fixed', `${path}.type`, issues);\n\tif (value.type === undefined) issues.push({ path: `${path}.type`, message: `${path}.type is required: one of ${CHART_ERROR_BAR_TYPES.map((t) => `\"${t}\"`).join(', ')}.` });\n\tconst bars: ChartErrorBars = { type };\n\tif (key(value, 'value')) {\n\t\tconst n = Number(value.value);\n\t\tif (type === 'stderr' || type === 'custom') issues.push({ path: `${path}.value`, message: `${type} error bars take no value; ${type === 'custom' ? 'pass plus and minus amounts instead' : 'the amount comes from the data'}.` });\n\t\telse if (Number.isFinite(n) && n >= 0) bars.value = n;\n\t\telse issues.push({ path: `${path}.value`, message: `${path}.value must be a number, 0 or more${type === 'percent' ? ' (a percentage, e.g. 5 for 5%)' : ''}.` });\n\t}\n\tfor (const name of ['plus', 'minus'] as const) {\n\t\tif (!key(value, name)) continue;\n\t\tif (type !== 'custom') {\n\t\t\tissues.push({ path: `${path}.${name}`, message: `${path}.${name} only applies to custom error bars; set type to \"custom\".` });\n\t\t\tcontinue;\n\t\t}\n\t\tconst list = normalizeChartValues(value[name], length, `${path}.${name}`, issues);\n\t\tif (list.some((v) => v !== null && v < 0)) issues.push({ path: `${path}.${name}`, message: `${path}.${name} amounts must be 0 or more (distances from the point).` });\n\t\telse bars[name] = list;\n\t}\n\tif (type === 'custom' && !bars.plus && !bars.minus && issues.length === before) issues.push({ path: `${path}.plus`, message: `Custom error bars need plus and / or minus amounts, one per category.` });\n\tif (key(value, 'direction')) {\n\t\tconst direction = pick(value.direction, CHART_ERROR_BAR_DIRECTIONS, 'both', `${path}.direction`, issues);\n\t\tif (direction !== 'both') bars.direction = direction;\n\t}\n\tif (key(value, 'cap') && !flag(value.cap, true, `${path}.cap`, issues)) bars.cap = false;\n\treturn issues.length > before ? null : bars;\n}\n\n/** Checks one trendline; `null` (reported) when it is unusable. */\nexport function normalizeChartTrendline(value: unknown, path: string, issues: ChartIssue[] = []): ChartTrendline | null {\n\tif (!isRecord(value)) {\n\t\tissues.push({ path, message: `${path} must be an object with a type.` });\n\t\treturn null;\n\t}\n\tconst type = pick(value.type, CHART_TRENDLINE_TYPES, 'linear', `${path}.type`, issues);\n\tconst line: ChartTrendline = { type };\n\tconst whole = (name: 'order' | 'period', min: number, max: number) => {\n\t\tif (!key(value, name)) return;\n\t\tconst n = Number(value[name]);\n\t\tif (Number.isInteger(n) && n >= min && n <= max) line[name] = n;\n\t\telse issues.push({ path: `${path}.${name}`, message: `${path}.${name} must be a whole number from ${min} to ${max}.` });\n\t};\n\tif (type === 'polynomial') whole('order', 2, 6);\n\tif (type === 'moving-average') whole('period', 2, 1000);\n\tfor (const name of ['forward', 'backward'] as const) {\n\t\tif (!key(value, name)) continue;\n\t\tconst n = Number(value[name]);\n\t\tif (Number.isFinite(n) && n >= 0) {\n\t\t\tif (n > 0) line[name] = n;\n\t\t} else issues.push({ path: `${path}.${name}`, message: `${path}.${name} must be a number of x units, 0 or more.` });\n\t}\n\tif (key(value, 'intercept')) {\n\t\tconst n = Number(value.intercept);\n\t\tif (!Number.isFinite(n)) issues.push({ path: `${path}.intercept`, message: `${path}.intercept must be a number or null.` });\n\t\telse if (type === 'linear' || type === 'polynomial' || type === 'exponential') {\n\t\t\tif (type === 'exponential' && n <= 0) issues.push({ path: `${path}.intercept`, message: `${path}.intercept must be greater than 0 for an exponential trendline.` });\n\t\t\telse line.intercept = n;\n\t\t} else issues.push({ path: `${path}.intercept`, message: `A ${type} trendline cannot have a fixed intercept; use linear, polynomial or exponential.` });\n\t}\n\tfor (const name of ['showEquation', 'showR2'] as const) if (key(value, name) && flag(value[name], false, `${path}.${name}`, issues)) line[name] = true;\n\tfor (const name of ['name', 'color'] as const) {\n\t\tif (!key(value, name)) continue;\n\t\tconst t = text(value[name], '', `${path}.${name}`, issues).trim();\n\t\tif (t) line[name] = t;\n\t}\n\treturn line;\n}\n\n/**\n * Turns any input (a partial spec, saved JSON, an agent's arguments) into a complete,\n * valid `ChartSpec`. Every value is checked; problems are reported as sentences in\n * `issues` and replaced by defaults, so the result is always drawable. Series values are\n * padded or trimmed to the number of categories.\n */\nexport function normalizeChartSpec(input: unknown): { spec: ChartSpec; issues: ChartIssue[] } {\n\tconst issues: ChartIssue[] = [];\n\tconst value = isRecord(input) ? input : {};\n\tif (input !== undefined && !isRecord(input)) issues.push({ path: '', message: 'A chart must be an object.' });\n\tconst type = pick(value.type, CHART_TYPES, 'bar', 'type', issues);\n\tconst rawSeries = Array.isArray(value.series) ? value.series : [];\n\tif (value.series !== undefined && !Array.isArray(value.series)) issues.push({ path: 'series', message: 'series must be an array.' });\n\n\tlet categories: string[];\n\tif (Array.isArray(value.categories)) categories = value.categories.map((c, i) => text(c, '', `categories[${i}]`, issues));\n\telse {\n\t\tif (value.categories !== undefined) issues.push({ path: 'categories', message: 'categories must be an array of labels.' });\n\t\tconst longest = rawSeries.reduce<number>((n, s) => Math.max(n, isRecord(s) && Array.isArray(s.values) ? s.values.length : 0), 0);\n\t\tcategories = Array.from({ length: longest }, (_, i) => `${i + 1}`);\n\t}\n\n\tconst used = new Set<string>();\n\tconst series = rawSeries.map((s, i) => normalizeSeries(s, categories.length, used, i, issues)).filter((s): s is ChartSeries => s !== null);\n\n\tlet palette = [...DEFAULT_CHART_PALETTE];\n\tif (Array.isArray(value.palette)) {\n\t\tconst colors = value.palette.filter((c): c is string => typeof c === 'string' && c.trim() !== '');\n\t\tif (colors.length) palette = colors;\n\t\telse issues.push({ path: 'palette', message: 'palette must list at least one colour.' });\n\t} else if (value.palette !== undefined) issues.push({ path: 'palette', message: 'palette must be an array of colours.' });\n\n\tconst fraction = (name: string, fallback: number, min: number, max: number) => {\n\t\tif (value[name] === undefined) return fallback;\n\t\tconst r = Number(value[name]);\n\t\tif (value[name] !== null && Number.isFinite(r) && r >= min && r <= max) return r;\n\t\tissues.push({ path: name, message: `${name} must be a number from ${min} to ${max}.` });\n\t\treturn fallback;\n\t};\n\tconst innerRadius = fraction('innerRadius', 0.55, 0, 0.9);\n\tconst gapWidth = fraction('gapWidth', 0.28, 0, 0.9);\n\tconst overlap = fraction('overlap', -0.12, -1, 1);\n\tlet bins: number | null = null;\n\tif (value.bins !== undefined && value.bins !== null) {\n\t\tconst b = Number(value.bins);\n\t\tif (Number.isInteger(b) && b >= 1 && b <= 500) bins = b;\n\t\telse issues.push({ path: 'bins', message: 'bins must be a whole number from 1 to 500, or null for automatic.' });\n\t}\n\n\tconst spec: ChartSpec = {\n\t\tversion: 1,\n\t\ttype,\n\t\ttitle: text(value.title, '', 'title', issues),\n\t\tsubtitle: text(value.subtitle, '', 'subtitle', issues),\n\t\tcategories,\n\t\tseries,\n\t\txAxis: normalizeChartAxis(value.xAxis, defaultChartAxis(false), 'xAxis', issues),\n\t\tyAxis: normalizeChartAxis(value.yAxis, defaultChartAxis(true), 'yAxis', issues),\n\t\tyAxis2: normalizeChartAxis(value.yAxis2, defaultChartAxis(false), 'yAxis2', issues),\n\t\tlegend: normalizeLegend(value.legend, issues),\n\t\tstacking: pick(value.stacking, CHART_STACKINGS, 'none', 'stacking', issues),\n\t\torientation: pick(value.orientation, CHART_ORIENTATIONS, 'vertical', 'orientation', issues),\n\t\tcurve: pick(value.curve, CHART_CURVES, 'linear', 'curve', issues),\n\t\tpoints: flag(value.points, true, 'points', issues),\n\t\tdataLabels: flag(value.dataLabels, false, 'dataLabels', issues),\n\t\tlabelPosition: pick(value.labelPosition, CHART_LABEL_POSITIONS, 'auto', 'labelPosition', issues),\n\t\tpalette,\n\t\tinnerRadius,\n\t\tgapWidth,\n\t\toverlap,\n\t\tbins,\n\t\tshowTotal: flag(value.showTotal, true, 'showTotal', issues)\n\t};\n\tif (spec.stacking === 'percent')\n\t\tfor (const name of ['yAxis', 'yAxis2'] as const) {\n\t\t\tif (spec[name].scale !== 'log') continue;\n\t\t\tissues.push({ path: `${name}.scale`, message: `A logarithmic ${name} cannot show percent stacking (shares from 0% to 100% include 0); use stacking \"stacked\" or \"none\", or a linear axis.` });\n\t\t\tdelete spec[name].scale;\n\t\t\tdelete spec[name].logBase;\n\t\t}\n\treturn { spec, issues };\n}\n\n/** A deep copy (specs are plain JSON). */\nexport function cloneChartSpec(spec: ChartSpec): ChartSpec {\n\treturn {\n\t\t...spec,\n\t\tcategories: [...spec.categories],\n\t\tseries: spec.series.map(cloneChartSeries),\n\t\txAxis: { ...spec.xAxis, format: { ...spec.xAxis.format } },\n\t\tyAxis: { ...spec.yAxis, format: { ...spec.yAxis.format } },\n\t\tyAxis2: { ...spec.yAxis2, format: { ...spec.yAxis2.format } },\n\t\tlegend: { ...spec.legend },\n\t\tpalette: [...spec.palette]\n\t};\n}\n\nexport function cloneChartSeries(series: ChartSeries): ChartSeries {\n\tconst copy: ChartSeries = { ...series, values: [...series.values] };\n\tif (series.x) copy.x = [...series.x];\n\tif (series.sizes) copy.sizes = [...series.sizes];\n\tif (series.pointColors) copy.pointColors = [...series.pointColors];\n\tif (series.format) copy.format = { ...series.format };\n\tif (series.trendlines) copy.trendlines = series.trendlines.map((t) => ({ ...t }));\n\tfor (const name of ['errorBars', 'xErrorBars'] as const) {\n\t\tconst bars = series[name];\n\t\tif (!bars) continue;\n\t\tcopy[name] = { ...bars, ...(bars.plus ? { plus: [...bars.plus] } : {}), ...(bars.minus ? { minus: [...bars.minus] } : {}) };\n\t}\n\treturn copy;\n}\n\nexport interface ChartTableOptions {\n\t/**\n\t * `columns` (default): the first column holds categories and each other column is a\n\t * series. `rows`: the first row holds categories and each other row is a series.\n\t */\n\tseriesIn?: 'columns' | 'rows';\n\t/**\n\t * The first row (or column for `rows`) holds series names (default `true`). `auto`: only\n\t * when one of its value cells is not a number.\n\t */\n\theader?: boolean | 'auto';\n\t/**\n\t * Read the first column as numeric x values (scatter and bubble charts): every series gets\n\t * them as `x`, and the categories are their labels.\n\t */\n\txFromFirstColumn?: boolean;\n}\n\nexport interface ChartTableData {\n\tcategories: string[];\n\tseries: ChartSeries[];\n\tissues: ChartIssue[];\n}\n\n/**\n * Reads a grid of cells (from CSV, a spreadsheet range or the clipboard) as categories and\n * series. Cells that are not numbers become gaps and are reported.\n */\nexport function chartDataFromTable(rows: ReadonlyArray<ReadonlyArray<unknown>>, options: ChartTableOptions = {}): ChartTableData {\n\tlet grid = rows.map((r) => [...r]).filter((r) => r.some((c) => c !== null && c !== undefined && String(c).trim() !== ''));\n\tif (options.seriesIn === 'rows') {\n\t\tconst width = Math.max(0, ...grid.map((r) => r.length));\n\t\tgrid = Array.from({ length: width }, (_, c) => grid.map((r) => r[c]));\n\t}\n\tconst issues: ChartIssue[] = [];\n\tif (!grid.length) return { categories: [], series: [], issues };\n\tconst width = Math.max(...grid.map((r) => r.length));\n\tconst header = options.header === 'auto' ? grid[0].slice(1).some((c) => c !== null && c !== undefined && String(c).trim() !== '' && parseChartValue(c) === undefined) : (options.header ?? true);\n\tconst names = header ? grid[0] : [];\n\tconst body = header ? grid.slice(1) : grid;\n\tconst categories = body.map((r, i) => {\n\t\tconst c = r[0];\n\t\treturn c === null || c === undefined || String(c).trim() === '' ? `${i + 1}` : String(c).trim();\n\t});\n\tconst series: ChartSeries[] = [];\n\tfor (let col = 1; col < width; col++) {\n\t\tconst name = names[col] !== undefined && String(names[col]).trim() ? String(names[col]).trim() : `Series ${col}`;\n\t\tconst values = body.map((r, i) => {\n\t\t\tconst parsed = parseChartValue(r[col] ?? null);\n\t\t\tif (parsed === undefined) {\n\t\t\t\tissues.push({ path: `${name}[${i}]`, message: `\"${String(r[col])}\" in ${name} (${categories[i]}) is not a number; it was left blank.` });\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn parsed;\n\t\t});\n\t\tseries.push({ id: `series-${col}`, name, values });\n\t}\n\tif (options.xFromFirstColumn) {\n\t\tconst x = body.map((r, i) => {\n\t\t\tconst parsed = parseChartValue(r[0] ?? null);\n\t\t\tif (parsed === undefined) issues.push({ path: `x[${i}]`, message: `\"${String(r[0])}\" in the first column is not a number; that point has no x.` });\n\t\t\treturn parsed ?? null;\n\t\t});\n\t\tfor (const s of series) s.x = [...x];\n\t}\n\treturn { categories, series, issues };\n}\n\n/** The chart's data as a grid: a header row of series names, then one row per category. */\nexport function chartDataToTable(spec: Pick<ChartSpec, 'categories' | 'series'>, options: { categoryHeader?: string } = {}): (string | number | null)[][] {\n\treturn [\n\t\t[options.categoryHeader ?? '', ...spec.series.map((s) => s.name)],\n\t\t...spec.categories.map((category, i) => [category, ...spec.series.map((s) => s.values[i] ?? null)])\n\t];\n}\n\n/** A colour input value (`#rrggbb`) for a CSS colour: `#abc` expands, non-hex colours show as black. */\nexport function chartColorInputValue(color: string): string {\n\tif (/^#[0-9a-f]{6}$/i.test(color)) return color.toLowerCase();\n\tif (/^#[0-9a-f]{3}$/i.test(color)) return `#${[...color.slice(1)].map((c) => c + c).join('')}`.toLowerCase();\n\treturn '#000000';\n}\n"]}
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
var _chunkCKRNELPOcjs = require('./chunk-CKRNELPO.cjs');
|
|
14
17
|
|
|
15
18
|
// src/chart/schemas.ts
|
|
16
19
|
var VALUE = { type: ["number", "string", "null"], description: 'A number, numeric text ("1,200", "12%", "$40", "(3)") or null for a gap.' };
|
|
@@ -22,7 +25,7 @@ var FORMAT = {
|
|
|
22
25
|
type: "object",
|
|
23
26
|
description: "How numbers are written on this axis or series.",
|
|
24
27
|
properties: {
|
|
25
|
-
style: { type: "string", enum: [...
|
|
28
|
+
style: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_NUMBER_STYLES], description: "number (default), percent (0.25 \u2192 25%), currency or compact (1.2K)." },
|
|
26
29
|
decimals: { type: "integer", minimum: 0, maximum: 10, description: "Fixed decimals (default: what the ticks need)." },
|
|
27
30
|
currency: { type: "string", description: 'ISO currency code for style "currency", e.g. "EUR" (default USD).' },
|
|
28
31
|
prefix: { type: "string", description: "Text before every number." },
|
|
@@ -42,12 +45,19 @@ var AXIS = (what) => ({
|
|
|
42
45
|
step: { type: ["number", "null"], exclusiveMinimum: 0, description: "Fixed distance between ticks, or null for automatic." },
|
|
43
46
|
gridlines: { type: "boolean", description: "Grid lines at each tick." },
|
|
44
47
|
format: FORMAT,
|
|
45
|
-
kind: { type: ["string", "null"], enum: [...
|
|
48
|
+
kind: { type: ["string", "null"], enum: [..._chunkCKRNELPOcjs.CHART_AXIS_KINDS, null], description: 'Category axis only: "date" reads categories as dates and labels them by calendar steps.' },
|
|
49
|
+
scale: {
|
|
50
|
+
type: ["string", "null"],
|
|
51
|
+
enum: [..._chunkCKRNELPOcjs.CHART_AXIS_SCALES, null],
|
|
52
|
+
description: 'Value axes and the numeric x axis of scatter / bubble charts: "log" spaces ticks by powers of logBase (values of 0 or less are skipped; min and max must be above 0; not with percent stacking). "linear" or null is the default. Ignored on a category axis.'
|
|
53
|
+
},
|
|
54
|
+
logBase: { type: ["number", "null"], minimum: 2, maximum: 1e3, description: "Base of a log axis, 2 to 1000 (default 10; null resets)." },
|
|
55
|
+
reverse: { type: ["boolean", "null"], description: "Run the axis the other way: values from the top down (or right to left), categories from the far end. Default false." }
|
|
46
56
|
},
|
|
47
57
|
additionalProperties: false
|
|
48
58
|
});
|
|
49
59
|
var TRENDLINE_PROPS = {
|
|
50
|
-
type: { type: "string", enum: [...
|
|
60
|
+
type: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_TRENDLINE_TYPES], description: "Fit: linear, exponential, logarithmic, power, polynomial or moving-average." },
|
|
51
61
|
order: { type: "integer", minimum: 2, maximum: 6, description: "Polynomial order (default 2)." },
|
|
52
62
|
period: { type: "integer", minimum: 2, description: "Moving-average period in points (default 2)." },
|
|
53
63
|
forward: { type: "number", minimum: 0, description: "Extend the line this many x units past the last point (default 0)." },
|
|
@@ -58,23 +68,43 @@ var TRENDLINE_PROPS = {
|
|
|
58
68
|
name: { type: "string", description: 'Legend name (default e.g. "Linear (Sales)").' },
|
|
59
69
|
color: { type: "string", description: "CSS colour (default: the series colour)." }
|
|
60
70
|
};
|
|
71
|
+
var ERROR_BARS = (what) => ({
|
|
72
|
+
type: ["object", "null"],
|
|
73
|
+
description: `${what} null removes them.`,
|
|
74
|
+
properties: {
|
|
75
|
+
type: {
|
|
76
|
+
type: "string",
|
|
77
|
+
enum: [..._chunkCKRNELPOcjs.CHART_ERROR_BAR_TYPES],
|
|
78
|
+
description: "fixed: the same amount at every point; percent: a percentage of each value; stddev: value standard deviations of the series, drawn around the series mean (as Excel does); stderr: the standard error of the series at every point; custom: per-point plus / minus amounts."
|
|
79
|
+
},
|
|
80
|
+
value: { type: "number", minimum: 0, description: "Amount in data units for fixed (default 1), percent of each value for percent (default 5), number of standard deviations for stddev (default 1). Not for stderr or custom." },
|
|
81
|
+
plus: { type: "array", items: VALUE, description: "custom only: amount above each point, one per category, in data units (0 or more; null for none)." },
|
|
82
|
+
minus: { type: "array", items: VALUE, description: "custom only: amount below each point, one per category (default: the plus amounts)." },
|
|
83
|
+
direction: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_ERROR_BAR_DIRECTIONS], description: "both (default), plus (only above) or minus (only below)." },
|
|
84
|
+
cap: { type: "boolean", description: "Draw end caps (default true)." }
|
|
85
|
+
},
|
|
86
|
+
required: ["type"],
|
|
87
|
+
additionalProperties: false
|
|
88
|
+
});
|
|
61
89
|
var SERIES_PROPS = {
|
|
62
90
|
name: { type: "string", description: "Series name (legend and data grid header)." },
|
|
63
91
|
values: { type: "array", items: VALUE, description: "One value per category, in category order (padded with gaps)." },
|
|
64
92
|
color: { type: ["string", "null"], description: "CSS colour, or null for the palette colour." },
|
|
65
|
-
type: { type: ["string", "null"], enum: [...
|
|
93
|
+
type: { type: ["string", "null"], enum: [..._chunkCKRNELPOcjs.CHART_SERIES_TYPES, null], description: "Draw this series as bar, line, area or scatter (a combo chart); null follows the chart type." },
|
|
66
94
|
hidden: { type: "boolean", description: "Hide the series (its data is kept)." },
|
|
67
95
|
axis: { type: ["string", "null"], enum: ["primary", "secondary", null], description: "Value axis: secondary is drawn on the right with its own scale." },
|
|
68
96
|
x: { type: ["array", "null"], items: VALUE, description: "Numeric x per category, for scatter and bubble charts." },
|
|
69
97
|
sizes: { type: ["array", "null"], items: VALUE, description: "Bubble sizes per category (area is proportional to size)." },
|
|
70
98
|
pointColors: { type: ["array", "null"], items: { type: ["string", "null"] }, description: "Colour per category (null keeps the series colour)." },
|
|
71
|
-
marker: { type: ["string", "null"], enum: [...
|
|
72
|
-
curve: { type: ["string", "null"], enum: [...
|
|
99
|
+
marker: { type: ["string", "null"], enum: [..._chunkCKRNELPOcjs.CHART_MARKERS, null], description: "Point marker shape for line, area and scatter series." },
|
|
100
|
+
curve: { type: ["string", "null"], enum: [..._chunkCKRNELPOcjs.CHART_CURVES, null], description: "Line shape for this series: linear, smooth or step." },
|
|
73
101
|
dataLabels: { type: ["boolean", "null"], description: "Value labels for this series (null follows the chart)." },
|
|
74
|
-
format: { ...FORMAT, type: ["object", "null"], description: "How this series' labels are written (null follows the value axis)." }
|
|
102
|
+
format: { ...FORMAT, type: ["object", "null"], description: "How this series' labels are written (null follows the value axis)." },
|
|
103
|
+
errorBars: ERROR_BARS("Error bars along the value axis (bar, line, area and scatter series; on stacked charts they sit on the stack top)."),
|
|
104
|
+
xErrorBars: ERROR_BARS("Error bars along the x axis (scatter and bubble charts with numeric x values; amounts in x units).")
|
|
75
105
|
};
|
|
76
106
|
var CHART_UPDATE_PROPERTIES = {
|
|
77
|
-
type: { type: "string", enum: [...
|
|
107
|
+
type: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_TYPES], description: "Chart type." },
|
|
78
108
|
title: { type: "string", description: 'Title ("" for none).' },
|
|
79
109
|
subtitle: { type: "string", description: 'Subtitle ("" for none).' },
|
|
80
110
|
xAxis: AXIS("Category axis (or numeric x axis of scatter / bubble charts)."),
|
|
@@ -83,15 +113,15 @@ var CHART_UPDATE_PROPERTIES = {
|
|
|
83
113
|
legend: {
|
|
84
114
|
type: "object",
|
|
85
115
|
description: "Legend.",
|
|
86
|
-
properties: { show: { type: "boolean", description: "Show the legend." }, position: { type: "string", enum: [...
|
|
116
|
+
properties: { show: { type: "boolean", description: "Show the legend." }, position: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_LEGEND_POSITIONS], description: "Where the legend goes." } },
|
|
87
117
|
additionalProperties: false
|
|
88
118
|
},
|
|
89
|
-
stacking: { type: "string", enum: [...
|
|
90
|
-
orientation: { type: "string", enum: [...
|
|
91
|
-
curve: { type: "string", enum: [...
|
|
119
|
+
stacking: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_STACKINGS], description: "none, stacked, or percent (each category scaled to 100%)." },
|
|
120
|
+
orientation: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_ORIENTATIONS], description: "horizontal draws bars sideways." },
|
|
121
|
+
curve: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_CURVES], description: "Line shape: linear, smooth or step." },
|
|
92
122
|
points: { type: "boolean", description: "Dots on line and area series." },
|
|
93
123
|
dataLabels: { type: "boolean", description: "Value labels on bars, points and slices." },
|
|
94
|
-
labelPosition: { type: "string", enum: [...
|
|
124
|
+
labelPosition: { type: "string", enum: [..._chunkCKRNELPOcjs.CHART_LABEL_POSITIONS], description: "Bar label position; auto drops labels that do not fit." },
|
|
95
125
|
palette: { type: "array", items: { type: "string" }, minItems: 1, description: "Series colours in order (CSS colours)." },
|
|
96
126
|
innerRadius: { type: "number", minimum: 0, maximum: 0.9, description: "Donut hole as a fraction of the radius." },
|
|
97
127
|
gapWidth: { type: "number", minimum: 0, maximum: 0.9, description: "Space between bar groups as a fraction of the category (default 0.28)." },
|
|
@@ -110,4 +140,4 @@ var CHART_UPDATE_PROPERTIES = {
|
|
|
110
140
|
|
|
111
141
|
|
|
112
142
|
exports.VALUE = VALUE; exports.SERIES_REF = SERIES_REF; exports.CATEGORY_REF = CATEGORY_REF; exports.WIDTH = WIDTH; exports.HEIGHT = HEIGHT; exports.TRENDLINE_PROPS = TRENDLINE_PROPS; exports.SERIES_PROPS = SERIES_PROPS; exports.CHART_UPDATE_PROPERTIES = CHART_UPDATE_PROPERTIES;
|
|
113
|
-
//# sourceMappingURL=chunk-
|
|
143
|
+
//# sourceMappingURL=chunk-DK6QBGCS.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-DK6QBGCS.cjs","../src/chart/schemas.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-DK6QBGCS.cjs","sourcesContent":[null,"import type { JsonSchema } from '../tools/schema.js';\nimport { CHART_ERROR_BAR_DIRECTIONS, CHART_ERROR_BAR_TYPES } from './errorbars.js';\nimport {\n\tCHART_AXIS_KINDS,\n\tCHART_AXIS_SCALES,\n\tCHART_CURVES,\n\tCHART_LABEL_POSITIONS,\n\tCHART_LEGEND_POSITIONS,\n\tCHART_MARKERS,\n\tCHART_NUMBER_STYLES,\n\tCHART_ORIENTATIONS,\n\tCHART_SERIES_TYPES,\n\tCHART_STACKINGS,\n\tCHART_TRENDLINE_TYPES,\n\tCHART_TYPES\n} from './spec.js';\n\n// JSON Schema fragments shared by the chart commands and the chart agent tools.\n\nexport const VALUE: JsonSchema = { type: ['number', 'string', 'null'], description: 'A number, numeric text (\"1,200\", \"12%\", \"$40\", \"(3)\") or null for a gap.' };\nexport const SERIES_REF: JsonSchema = { type: 'string', description: 'Series id (from get_chart) or exact series name.' };\nexport const CATEGORY_REF: JsonSchema = { type: ['string', 'integer'], description: 'Category index (0-based) or exact category label.' };\nexport const WIDTH: JsonSchema = { type: 'number', minimum: 50, maximum: 4096, description: 'Width in pixels (default 640).' };\nexport const HEIGHT: JsonSchema = { type: 'number', minimum: 50, maximum: 4096, description: 'Height in pixels (default 400).' };\n\nexport const FORMAT: JsonSchema = {\n\ttype: 'object',\n\tdescription: 'How numbers are written on this axis or series.',\n\tproperties: {\n\t\tstyle: { type: 'string', enum: [...CHART_NUMBER_STYLES], description: 'number (default), percent (0.25 → 25%), currency or compact (1.2K).' },\n\t\tdecimals: { type: 'integer', minimum: 0, maximum: 10, description: 'Fixed decimals (default: what the ticks need).' },\n\t\tcurrency: { type: 'string', description: 'ISO currency code for style \"currency\", e.g. \"EUR\" (default USD).' },\n\t\tprefix: { type: 'string', description: 'Text before every number.' },\n\t\tsuffix: { type: 'string', description: 'Text after every number.' },\n\t\tcode: { type: 'string', description: 'Spreadsheet format code such as \"#,##0.0,,\\\\\"M\\\\\"\" or \"0.0%\"; wins over the other fields.' }\n\t},\n\tadditionalProperties: false\n};\n\nexport const AXIS = (what: string): JsonSchema => ({\n\ttype: 'object',\n\tdescription: what,\n\tproperties: {\n\t\tshow: { type: 'boolean', description: 'Draw the axis labels (default true).' },\n\t\ttitle: { type: 'string', description: 'Axis title (\"\" for none).' },\n\t\tmin: { type: ['number', 'null'], description: 'Fixed lower bound, or null for automatic.' },\n\t\tmax: { type: ['number', 'null'], description: 'Fixed upper bound, or null for automatic.' },\n\t\tstep: { type: ['number', 'null'], exclusiveMinimum: 0, description: 'Fixed distance between ticks, or null for automatic.' },\n\t\tgridlines: { type: 'boolean', description: 'Grid lines at each tick.' },\n\t\tformat: FORMAT,\n\t\tkind: { type: ['string', 'null'], enum: [...CHART_AXIS_KINDS, null], description: 'Category axis only: \"date\" reads categories as dates and labels them by calendar steps.' },\n\t\tscale: {\n\t\t\ttype: ['string', 'null'],\n\t\t\tenum: [...CHART_AXIS_SCALES, null],\n\t\t\tdescription:\n\t\t\t\t'Value axes and the numeric x axis of scatter / bubble charts: \"log\" spaces ticks by powers of logBase (values of 0 or less are skipped; min and max must be above 0; not with percent stacking). \"linear\" or null is the default. Ignored on a category axis.'\n\t\t},\n\t\tlogBase: { type: ['number', 'null'], minimum: 2, maximum: 1000, description: 'Base of a log axis, 2 to 1000 (default 10; null resets).' },\n\t\treverse: { type: ['boolean', 'null'], description: 'Run the axis the other way: values from the top down (or right to left), categories from the far end. Default false.' }\n\t},\n\tadditionalProperties: false\n});\n\nexport const TRENDLINE_PROPS: Record<string, JsonSchema> = {\n\ttype: { type: 'string', enum: [...CHART_TRENDLINE_TYPES], description: 'Fit: linear, exponential, logarithmic, power, polynomial or moving-average.' },\n\torder: { type: 'integer', minimum: 2, maximum: 6, description: 'Polynomial order (default 2).' },\n\tperiod: { type: 'integer', minimum: 2, description: 'Moving-average period in points (default 2).' },\n\tforward: { type: 'number', minimum: 0, description: 'Extend the line this many x units past the last point (default 0).' },\n\tbackward: { type: 'number', minimum: 0, description: 'Extend the line this many x units before the first point (default 0).' },\n\tintercept: { type: ['number', 'null'], description: 'Force the fit through this y at x = 0 (linear, polynomial, exponential).' },\n\tshowEquation: { type: 'boolean', description: 'Write the fitted equation on the chart.' },\n\tshowR2: { type: 'boolean', description: 'Write R² on the chart.' },\n\tname: { type: 'string', description: 'Legend name (default e.g. \"Linear (Sales)\").' },\n\tcolor: { type: 'string', description: 'CSS colour (default: the series colour).' }\n};\n\nexport const ERROR_BARS = (what: string): JsonSchema => ({\n\ttype: ['object', 'null'],\n\tdescription: `${what} null removes them.`,\n\tproperties: {\n\t\ttype: {\n\t\t\ttype: 'string',\n\t\t\tenum: [...CHART_ERROR_BAR_TYPES],\n\t\t\tdescription: 'fixed: the same amount at every point; percent: a percentage of each value; stddev: value standard deviations of the series, drawn around the series mean (as Excel does); stderr: the standard error of the series at every point; custom: per-point plus / minus amounts.'\n\t\t},\n\t\tvalue: { type: 'number', minimum: 0, description: 'Amount in data units for fixed (default 1), percent of each value for percent (default 5), number of standard deviations for stddev (default 1). Not for stderr or custom.' },\n\t\tplus: { type: 'array', items: VALUE, description: 'custom only: amount above each point, one per category, in data units (0 or more; null for none).' },\n\t\tminus: { type: 'array', items: VALUE, description: 'custom only: amount below each point, one per category (default: the plus amounts).' },\n\t\tdirection: { type: 'string', enum: [...CHART_ERROR_BAR_DIRECTIONS], description: 'both (default), plus (only above) or minus (only below).' },\n\t\tcap: { type: 'boolean', description: 'Draw end caps (default true).' }\n\t},\n\trequired: ['type'],\n\tadditionalProperties: false\n});\n\nexport const SERIES_PROPS: Record<string, JsonSchema> = {\n\tname: { type: 'string', description: 'Series name (legend and data grid header).' },\n\tvalues: { type: 'array', items: VALUE, description: 'One value per category, in category order (padded with gaps).' },\n\tcolor: { type: ['string', 'null'], description: 'CSS colour, or null for the palette colour.' },\n\ttype: { type: ['string', 'null'], enum: [...CHART_SERIES_TYPES, null], description: 'Draw this series as bar, line, area or scatter (a combo chart); null follows the chart type.' },\n\thidden: { type: 'boolean', description: 'Hide the series (its data is kept).' },\n\taxis: { type: ['string', 'null'], enum: ['primary', 'secondary', null], description: 'Value axis: secondary is drawn on the right with its own scale.' },\n\tx: { type: ['array', 'null'], items: VALUE, description: 'Numeric x per category, for scatter and bubble charts.' },\n\tsizes: { type: ['array', 'null'], items: VALUE, description: 'Bubble sizes per category (area is proportional to size).' },\n\tpointColors: { type: ['array', 'null'], items: { type: ['string', 'null'] }, description: 'Colour per category (null keeps the series colour).' },\n\tmarker: { type: ['string', 'null'], enum: [...CHART_MARKERS, null], description: 'Point marker shape for line, area and scatter series.' },\n\tcurve: { type: ['string', 'null'], enum: [...CHART_CURVES, null], description: 'Line shape for this series: linear, smooth or step.' },\n\tdataLabels: { type: ['boolean', 'null'], description: 'Value labels for this series (null follows the chart).' },\n\tformat: { ...FORMAT, type: ['object', 'null'], description: 'How this series\\' labels are written (null follows the value axis).' },\n\terrorBars: ERROR_BARS('Error bars along the value axis (bar, line, area and scatter series; on stacked charts they sit on the stack top).'),\n\txErrorBars: ERROR_BARS('Error bars along the x axis (scatter and bubble charts with numeric x values; amounts in x units).')\n};\n\n\nexport const CHART_UPDATE_PROPERTIES: Record<string, JsonSchema> = {\n\t\t\t\ttype: { type: 'string', enum: [...CHART_TYPES], description: 'Chart type.' },\n\t\t\t\ttitle: { type: 'string', description: 'Title (\"\" for none).' },\n\t\t\t\tsubtitle: { type: 'string', description: 'Subtitle (\"\" for none).' },\n\t\t\t\txAxis: AXIS('Category axis (or numeric x axis of scatter / bubble charts).'),\n\t\t\t\tyAxis: AXIS('Value axis.'),\n\t\t\t\tyAxis2: AXIS('Secondary value axis (for series with axis \"secondary\").'),\n\t\t\t\tlegend: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tdescription: 'Legend.',\n\t\t\t\t\tproperties: { show: { type: 'boolean', description: 'Show the legend.' }, position: { type: 'string', enum: [...CHART_LEGEND_POSITIONS], description: 'Where the legend goes.' } },\n\t\t\t\t\tadditionalProperties: false\n\t\t\t\t},\n\t\t\t\tstacking: { type: 'string', enum: [...CHART_STACKINGS], description: 'none, stacked, or percent (each category scaled to 100%).' },\n\t\t\t\torientation: { type: 'string', enum: [...CHART_ORIENTATIONS], description: 'horizontal draws bars sideways.' },\n\t\t\t\tcurve: { type: 'string', enum: [...CHART_CURVES], description: 'Line shape: linear, smooth or step.' },\n\t\t\t\tpoints: { type: 'boolean', description: 'Dots on line and area series.' },\n\t\t\t\tdataLabels: { type: 'boolean', description: 'Value labels on bars, points and slices.' },\n\t\t\t\tlabelPosition: { type: 'string', enum: [...CHART_LABEL_POSITIONS], description: 'Bar label position; auto drops labels that do not fit.' },\n\t\t\t\tpalette: { type: 'array', items: { type: 'string' }, minItems: 1, description: 'Series colours in order (CSS colours).' },\n\t\t\t\tinnerRadius: { type: 'number', minimum: 0, maximum: 0.9, description: 'Donut hole as a fraction of the radius.' },\n\t\t\t\tgapWidth: { type: 'number', minimum: 0, maximum: 0.9, description: 'Space between bar groups as a fraction of the category (default 0.28).' },\n\t\t\t\toverlap: { type: 'number', minimum: -1, maximum: 1, description: 'Bar overlap within a group as a fraction of a bar (negative: a gap; default -0.12).' },\n\t\t\t\tbins: { type: ['integer', 'null'], minimum: 1, maximum: 500, description: 'Histogram bin count, or null for √n.' },\n\t\t\t\tshowTotal: { type: 'boolean', description: 'Waterfall: append a total bar.' }\n\t\t\t};\n"]}
|