@pixerate/editor 0.47.0 → 0.49.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.
Files changed (91) hide show
  1. package/dist/agent/index.cjs +248 -29
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +18 -6
  4. package/dist/agent/index.d.ts +18 -6
  5. package/dist/agent/index.js +228 -9
  6. package/dist/agent/index.js.map +1 -1
  7. package/dist/{builtins-xs7rK6ys.d.cts → builtins-1kqwLUnb.d.cts} +1 -1
  8. package/dist/{builtins-D2nMtw2W.d.ts → builtins-BKYlHH1s.d.ts} +1 -1
  9. package/dist/chart/index.cjs +216 -3541
  10. package/dist/chart/index.cjs.map +1 -1
  11. package/dist/chart/index.d.cts +4 -494
  12. package/dist/chart/index.d.ts +4 -494
  13. package/dist/chart/index.js +155 -3480
  14. package/dist/chart/index.js.map +1 -1
  15. package/dist/{chunk-5VXI5GED.js → chunk-2CJ3LPYQ.js} +3 -3
  16. package/dist/{chunk-TXXNBDQX.cjs → chunk-2Q46FKZK.cjs} +113 -34
  17. package/dist/chunk-2Q46FKZK.cjs.map +1 -0
  18. package/dist/chunk-3JNRQVTS.cjs +521 -0
  19. package/dist/chunk-3JNRQVTS.cjs.map +1 -0
  20. package/dist/chunk-5TWIN7ZJ.js +113 -0
  21. package/dist/chunk-5TWIN7ZJ.js.map +1 -0
  22. package/dist/{chunk-PQFAHT5O.js → chunk-DQPBQXKG.js} +27 -94
  23. package/dist/chunk-DQPBQXKG.js.map +1 -0
  24. package/dist/{chunk-ZFBBVGCI.js → chunk-EKYHKQPG.js} +243 -243
  25. package/dist/{chunk-ZFBBVGCI.js.map → chunk-EKYHKQPG.js.map} +1 -1
  26. package/dist/{chunk-J3R2OWOE.cjs → chunk-FEMIVHN3.cjs} +610 -15
  27. package/dist/chunk-FEMIVHN3.cjs.map +1 -0
  28. package/dist/{chunk-C3NWJE3K.js → chunk-GJBIVWB2.js} +11 -672
  29. package/dist/chunk-GJBIVWB2.js.map +1 -0
  30. package/dist/chunk-GTZXF4BI.cjs +3424 -0
  31. package/dist/chunk-GTZXF4BI.cjs.map +1 -0
  32. package/dist/chunk-JOX6MJW4.cjs +674 -0
  33. package/dist/chunk-JOX6MJW4.cjs.map +1 -0
  34. package/dist/{chunk-REAGGLXS.js → chunk-JQ3BB3E6.js} +2 -2
  35. package/dist/{chunk-H4PICYNL.cjs → chunk-LNKZPIQD.cjs} +113 -180
  36. package/dist/chunk-LNKZPIQD.cjs.map +1 -0
  37. package/dist/chunk-OV7UAKIY.js +674 -0
  38. package/dist/chunk-OV7UAKIY.js.map +1 -0
  39. package/dist/{chunk-TK2XZK6Z.js → chunk-QFTVLEVN.js} +596 -1
  40. package/dist/chunk-QFTVLEVN.js.map +1 -0
  41. package/dist/{chunk-KRGXUQ2Y.js → chunk-T6XU4B54.js} +82 -3
  42. package/dist/chunk-T6XU4B54.js.map +1 -0
  43. package/dist/chunk-TGBCBQFV.cjs +113 -0
  44. package/dist/chunk-TGBCBQFV.cjs.map +1 -0
  45. package/dist/{chunk-SQC26VQV.cjs → chunk-UN33YOXW.cjs} +191 -191
  46. package/dist/{chunk-SQC26VQV.cjs.map → chunk-UN33YOXW.cjs.map} +1 -1
  47. package/dist/chunk-WBOAXDKD.js +3424 -0
  48. package/dist/chunk-WBOAXDKD.js.map +1 -0
  49. package/dist/{chunk-LYGEEDNR.cjs → chunk-XP5IUZUO.cjs} +242 -242
  50. package/dist/chunk-XP5IUZUO.cjs.map +1 -0
  51. package/dist/{chunk-BBRK6MOI.cjs → chunk-YU4WQE5M.cjs} +100 -100
  52. package/dist/{chunk-BBRK6MOI.cjs.map → chunk-YU4WQE5M.cjs.map} +1 -1
  53. package/dist/commands/index.d.cts +1 -1
  54. package/dist/commands/index.d.ts +1 -1
  55. package/dist/controller-ChjCCMLl.d.cts +822 -0
  56. package/dist/controller-DtbEo3om.d.ts +822 -0
  57. package/dist/export/index.cjs +4 -2
  58. package/dist/export/index.cjs.map +1 -1
  59. package/dist/export/index.d.cts +5 -1
  60. package/dist/export/index.d.ts +5 -1
  61. package/dist/export/index.js +3 -1
  62. package/dist/extensions/index.cjs +33 -4
  63. package/dist/extensions/index.cjs.map +1 -1
  64. package/dist/extensions/index.d.cts +4 -2
  65. package/dist/extensions/index.d.ts +4 -2
  66. package/dist/extensions/index.js +32 -3
  67. package/dist/{index-QrqMmZ75.d.cts → index-DoHqT1mq.d.cts} +203 -7
  68. package/dist/{index-CSUCQYAH.d.ts → index-YLZ0fKqE.d.ts} +203 -7
  69. package/dist/index.cjs +39 -13
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +9 -7
  72. package/dist/index.d.ts +9 -7
  73. package/dist/index.js +33 -7
  74. package/dist/index.js.map +1 -1
  75. package/dist/spreadsheet/index.cjs +4 -4
  76. package/dist/spreadsheet/index.js +3 -3
  77. package/package.json +1 -1
  78. package/dist/chunk-C3NWJE3K.js.map +0 -1
  79. package/dist/chunk-H4PICYNL.cjs.map +0 -1
  80. package/dist/chunk-J3R2OWOE.cjs.map +0 -1
  81. package/dist/chunk-KRGXUQ2Y.js.map +0 -1
  82. package/dist/chunk-LYGEEDNR.cjs.map +0 -1
  83. package/dist/chunk-NEOO6QJD.cjs +0 -1182
  84. package/dist/chunk-NEOO6QJD.cjs.map +0 -1
  85. package/dist/chunk-PQFAHT5O.js.map +0 -1
  86. package/dist/chunk-TK2XZK6Z.js.map +0 -1
  87. package/dist/chunk-TXXNBDQX.cjs.map +0 -1
  88. package/dist/types-BVqWm3d1.d.cts +0 -320
  89. package/dist/types-BVqWm3d1.d.ts +0 -320
  90. /package/dist/{chunk-5VXI5GED.js.map → chunk-2CJ3LPYQ.js.map} +0 -0
  91. /package/dist/{chunk-REAGGLXS.js.map → chunk-JQ3BB3E6.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3;
2
2
 
3
3
 
4
4
 
@@ -7,6 +7,7 @@
7
7
 
8
8
 
9
9
 
10
+ var _chunkTGBCBQFVcjs = require('../chunk-TGBCBQFV.cjs');
10
11
 
11
12
 
12
13
 
@@ -14,6 +15,7 @@
14
15
 
15
16
 
16
17
 
18
+ var _chunk3JNRQVTScjs = require('../chunk-3JNRQVTS.cjs');
17
19
 
18
20
 
19
21
 
@@ -53,2233 +55,87 @@
53
55
 
54
56
 
55
57
 
56
- var _chunkNEOO6QJDcjs = require('../chunk-NEOO6QJD.cjs');
57
58
 
58
59
 
59
- var _chunkLYGEEDNRcjs = require('../chunk-LYGEEDNR.cjs');
60
60
 
61
61
 
62
62
 
63
- var _chunkTNNJXF46cjs = require('../chunk-TNNJXF46.cjs');
64
63
 
65
64
 
66
- var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
67
65
 
68
- // src/chart/numfmt.ts
69
- function compileChartFormatCode(code) {
70
- const fmt = _chunkLYGEEDNRcjs.NumberFormat.parseCached(code);
71
- return {
72
- isDate: fmt.isDate(),
73
- isPercent: fmt.isPercent(),
74
- format: (value) => Number.isFinite(value) ? fmt.formatNumber(value).text : ""
75
- };
76
- }
77
- function formatChartValueWithCode(value, code) {
78
- return compileChartFormatCode(code).format(value);
79
- }
80
- function chartSerialToDate(serial) {
81
- const origin = serial < 61 ? Date.UTC(1899, 11, 31) : Date.UTC(1899, 11, 30);
82
- return new Date(origin + Math.round(serial * 864e5));
83
- }
84
- function chartDateToSerial(date) {
85
- const serial = (date.getTime() - Date.UTC(1899, 11, 30)) / 864e5;
86
- return serial < 61 ? serial - 1 : serial;
87
- }
88
66
 
89
- // src/chart/scale.ts
90
- function niceStep(span, count) {
91
- if (!(span > 0) || !(count > 0)) return 1;
92
- const raw = span / count;
93
- const power = Math.pow(10, Math.floor(Math.log10(raw)));
94
- const fraction = raw / power;
95
- const nice = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 2.5 ? 2.5 : fraction <= 5 ? 5 : 10;
96
- return nice * power;
97
- }
98
- var clean = (n) => Math.abs(n) < 1e-12 ? 0 : Number(n.toPrecision(12));
99
- function niceScale(min, max, count = 5, fixedMin = null, fixedMax = null) {
100
- if (fixedMin !== null && !Number.isFinite(fixedMin)) fixedMin = null;
101
- if (fixedMax !== null && !Number.isFinite(fixedMax)) fixedMax = null;
102
- let lo = _nullishCoalesce(fixedMin, () => ( min));
103
- let hi = _nullishCoalesce(fixedMax, () => ( max));
104
- if (!Number.isFinite(lo) || !Number.isFinite(hi)) {
105
- fixedMin = fixedMax = null;
106
- lo = 0;
107
- hi = 1;
108
- }
109
- if (lo > hi) [lo, hi] = [hi, lo];
110
- if (lo === hi) {
111
- const pad = lo === 0 ? 1 : Math.abs(lo) * 0.1;
112
- if (fixedMin === null && lo !== 0) lo -= pad;
113
- if (fixedMax === null || lo === hi) hi += pad;
114
- }
115
- const span = hi - lo;
116
- const step = Number.isFinite(span) ? niceStep(span, count) : niceStep(hi / 2 - lo / 2, count) * 2;
117
- const finiteOr = (n2, fallback) => Number.isFinite(n2) ? n2 : fallback;
118
- const niceMin = _nullishCoalesce(fixedMin, () => ( finiteOr(snap(Math.floor(lo / step + 1e-9) * step, step), lo)));
119
- const niceMax = _nullishCoalesce(fixedMax, () => ( finiteOr(snap(Math.ceil(hi / step - 1e-9) * step, step), hi)));
120
- const firstIndex = Math.ceil(niceMin / step - 1e-9);
121
- const lastIndex = Math.floor(niceMax / step + 1e-9);
122
- const n = Math.min(999, Math.max(-1, lastIndex - firstIndex));
123
- const ticks = [];
124
- for (let i = 0; i <= n; i++) {
125
- const t = snap((firstIndex + i) * step, step);
126
- if (Number.isFinite(t) && t !== ticks[ticks.length - 1]) ticks.push(t);
127
- }
128
- return { min: niceMin, max: niceMax, step, ticks };
129
- }
130
- function snap(n, step) {
131
- const c = clean(n);
132
- return Math.abs(c - n) <= step * 1e-6 ? c : n;
133
- }
134
- function stepDecimals(step) {
135
- if (!(step > 0) || !Number.isFinite(step)) return 0;
136
- for (let d = 0; d < 6; d++) {
137
- const scaled = step * Math.pow(10, d);
138
- if (Math.abs(scaled - Math.round(scaled)) < 1e-9) return d;
139
- }
140
- return 6;
141
- }
142
- function magnitudeDecimals(value) {
143
- if (!(value > 0) || value >= 1) return 0;
144
- return Math.min(6, Math.max(0, Math.ceil(-Math.log10(value) - 1e-9)));
145
- }
146
- var COMPACT = [
147
- { value: 1e12, suffix: "T" },
148
- { value: 1e9, suffix: "B" },
149
- { value: 1e6, suffix: "M" },
150
- { value: 1e3, suffix: "K" }
151
- ];
152
- function grouped(value, decimals) {
153
- const fixed = Math.abs(value).toFixed(decimals);
154
- const [int, frac] = fixed.split(".");
155
- const withCommas = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
156
- return `${value < 0 && Number(fixed) !== 0 ? "-" : ""}${withCommas}${frac ? `.${frac}` : ""}`;
157
- }
158
- var CURRENCY_SYMBOLS = { USD: "$", EUR: "\u20AC", GBP: "\xA3", JPY: "\xA5", CNY: "\xA5", INR: "\u20B9", AUD: "A$", CAD: "C$" };
159
- function formatChartNumber(value, format = {}, fallbackDecimals) {
160
- if (value === null || value === void 0 || !Number.isFinite(value)) return "";
161
- if (format.code) return `${_nullishCoalesce(format.prefix, () => ( ""))}${formatChartValueWithCode(value, format.code)}${_nullishCoalesce(format.suffix, () => ( ""))}`;
162
- const style = _nullishCoalesce(format.style, () => ( "number"));
163
- let body;
164
- const decimalsFor = (v) => {
165
- if (format.decimals !== void 0) return format.decimals;
166
- if (fallbackDecimals !== void 0) return fallbackDecimals;
167
- return Number.isInteger(v) ? 0 : Math.abs(v) < 1 ? Math.min(4, Math.max(2, magnitudeDecimals(Math.abs(v)) + 1)) : 2;
168
- };
169
- const trim = (s) => format.decimals === void 0 && fallbackDecimals === void 0 && s.includes(".") ? s.replace(/\.?0+$/, "") : s;
170
- if (style === "percent") {
171
- const v = value * 100;
172
- const d = _nullishCoalesce(format.decimals, () => ( (fallbackDecimals !== void 0 ? Math.max(0, fallbackDecimals - 2) : Number.isInteger(clean(v)) ? 0 : 1)));
173
- body = `${grouped(clean(v), d)}%`;
174
- } else if (style === "compact") {
175
- const unit = COMPACT.find((u) => Math.abs(value) >= u.value);
176
- if (unit) {
177
- const v = value / unit.value;
178
- const d = _nullishCoalesce(format.decimals, () => ( (Math.abs(v) >= 100 || Number.isInteger(clean(v)) ? 0 : 1)));
179
- body = `${trim(grouped(v, d))}${unit.suffix}`;
180
- } else body = trim(grouped(value, decimalsFor(value)));
181
- } else if (style === "currency") {
182
- const code = (format.currency || "USD").toUpperCase();
183
- const symbol = _nullishCoalesce(CURRENCY_SYMBOLS[code], () => ( `${code} `));
184
- const d = _nullishCoalesce(format.decimals, () => ( (fallbackDecimals !== void 0 ? fallbackDecimals : Number.isInteger(value) ? 0 : 2)));
185
- const s = grouped(Math.abs(value), d);
186
- body = `${value < 0 ? "-" : ""}${symbol}${s}`;
187
- } else body = trim(grouped(value, decimalsFor(value)));
188
- return `${_nullishCoalesce(format.prefix, () => ( ""))}${body}${_nullishCoalesce(format.suffix, () => ( ""))}`;
189
- }
190
- function linearMap(value, domain, range) {
191
- const [d0, d1] = domain;
192
- const [r0, r1] = range;
193
- if (d1 === d0) return (r0 + r1) / 2;
194
- return r0 + (value - d0) / (d1 - d0) * (r1 - r0);
195
- }
196
67
 
197
- // src/chart/date.ts
198
- var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
199
- function parseChartDate(label) {
200
- const text = label.trim();
201
- let m = /^(\d{4})$/.exec(text);
202
- if (m) return Date.UTC(Number(m[1]), 0, 1);
203
- m = /^(\d{4})[-/](\d{1,2})$/.exec(text);
204
- if (m) return valid(Number(m[1]), Number(m[2]) - 1, 1);
205
- m = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/.exec(text);
206
- if (m) {
207
- if (m[4] !== void 0) {
208
- const t = Date.parse(text.replace(" ", "T").replace(/\//g, "-") + (m[7] ? "" : "Z"));
209
- return Number.isFinite(t) ? t : null;
210
- }
211
- return valid(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
212
- }
213
- m = /^(?:(\d{1,2})\s+)?([A-Za-z]{3})[a-z]*\.?,?\s+(\d{4})$/.exec(text);
214
- if (m) {
215
- const month = MONTHS.findIndex((x) => x.toLowerCase() === m[2].toLowerCase());
216
- if (month >= 0) return valid(Number(m[3]), month, m[1] ? Number(m[1]) : 1);
217
- }
218
- return null;
219
- }
220
- function valid(y, mo, d) {
221
- const t = Date.UTC(y, mo, d);
222
- const date = new Date(t);
223
- return date.getUTCFullYear() === y && date.getUTCMonth() === mo && date.getUTCDate() === d ? t : null;
224
- }
225
- var CHART_DATE_STEPS = [
226
- { unit: "day", count: 1 },
227
- { unit: "day", count: 2 },
228
- { unit: "week", count: 1 },
229
- { unit: "week", count: 2 },
230
- { unit: "month", count: 1 },
231
- { unit: "month", count: 3 },
232
- { unit: "month", count: 6 },
233
- { unit: "year", count: 1 },
234
- { unit: "year", count: 2 },
235
- { unit: "year", count: 5 },
236
- { unit: "year", count: 10 },
237
- { unit: "year", count: 25 },
238
- { unit: "year", count: 50 },
239
- { unit: "year", count: 100 }
240
- ];
241
- function bucket(t, step) {
242
- const d = new Date(t);
243
- const y = d.getUTCFullYear();
244
- switch (step.unit) {
245
- case "day":
246
- return Math.floor(Math.floor(t / 864e5) / step.count);
247
- case "week":
248
- return Math.floor(Math.floor((t / 864e5 - 4) / 7) / step.count);
249
- case "month":
250
- return Math.floor((y * 12 + d.getUTCMonth()) / step.count);
251
- case "year":
252
- return Math.floor(y / step.count);
253
- }
254
- }
255
- function formatChartDate(t, step, previous = null) {
256
- const d = new Date(t);
257
- const y = d.getUTCFullYear();
258
- const mo = MONTHS[d.getUTCMonth()];
259
- const sameYear = previous !== null && new Date(previous).getUTCFullYear() === y;
260
- if (step.unit === "year") return String(y);
261
- if (step.unit === "month") return sameYear ? mo : `${mo} ${y}`;
262
- return sameYear ? `${d.getUTCDate()} ${mo}` : `${d.getUTCDate()} ${mo} ${y}`;
263
- }
264
- function chartDateLabels(categories, band, measure, gap = 10) {
265
- const times = categories.map(parseChartDate);
266
- if (times.filter((t) => t !== null).length < Math.max(1, categories.length / 2)) return null;
267
- const present = times.filter((t) => t !== null).sort((x, y) => x - y);
268
- const gaps = present.slice(1).map((t, i) => t - present[i]).filter((g) => g > 0).sort((x, y) => x - y);
269
- const spacing = gaps.length ? gaps[Math.floor(gaps.length / 2)] : 0;
270
- const DAY = 864e5;
271
- const length = (step) => step.count * (step.unit === "day" ? DAY : step.unit === "week" ? 7 * DAY : step.unit === "month" ? 30 * DAY : 365 * DAY);
272
- for (const step of CHART_DATE_STEPS) {
273
- if (length(step) < spacing * 0.5 && step !== CHART_DATE_STEPS[CHART_DATE_STEPS.length - 1]) continue;
274
- const indexes = [];
275
- const labels = /* @__PURE__ */ new Map();
276
- let last = null;
277
- let lastTime = null;
278
- times.forEach((t, i) => {
279
- if (t === null) return;
280
- const b = bucket(t, step);
281
- if (b === last) return;
282
- last = b;
283
- indexes.push(i);
284
- labels.set(i, formatChartDate(t, step, lastTime));
285
- lastTime = t;
286
- });
287
- let fits = true;
288
- for (let k = 1; k < indexes.length && fits; k++) {
289
- const a = labels.get(indexes[k - 1]);
290
- const b = labels.get(indexes[k]);
291
- if ((indexes[k] - indexes[k - 1]) * band < (measure(a) + measure(b)) / 2 + gap) fits = false;
292
- }
293
- if (fits || step === CHART_DATE_STEPS[CHART_DATE_STEPS.length - 1]) return { step, indexes, labels };
294
- }
295
- return null;
296
- }
297
68
 
298
- // src/chart/stats.ts
299
- function chartHistogram(values, bins = null) {
300
- const vals = values.filter((v) => v !== null && Number.isFinite(v));
301
- if (!vals.length) return [];
302
- let lo = Infinity;
303
- let hi = -Infinity;
304
- for (const v of vals) {
305
- lo = Math.min(lo, v);
306
- hi = Math.max(hi, v);
307
- }
308
- const span = hi - lo;
309
- let count = _nullishCoalesce(bins, () => ( Math.max(1, Math.min(100, Math.ceil(Math.sqrt(vals.length))))));
310
- if (!(span > 0)) count = 1;
311
- const width = count === 1 && !(span > 0) ? 1 : span / count;
312
- const edges = Array.from({ length: count }, (_, b) => b + 1 === count ? Math.max(hi, lo + b * width) : lo + (b + 1) * width);
313
- const counts = Array(count).fill(0);
314
- for (const v of vals) {
315
- let a = 0;
316
- let z = count;
317
- while (a < z) {
318
- const mid = a + z >> 1;
319
- if (edges[mid] < v) a = mid + 1;
320
- else z = mid;
321
- }
322
- counts[Math.min(a, count - 1)]++;
323
- }
324
- return counts.map((c, b) => ({ from: clean2(lo + b * width), to: clean2(edges[b]), count: c }));
325
- }
326
- var clean2 = (n) => Math.abs(n) < 1e-12 ? 0 : Number(n.toPrecision(12));
327
- function chartQuantile(sorted, q) {
328
- const n = sorted.length;
329
- if (!n) return 0;
330
- const pos = q * (n - 1);
331
- const i = Math.floor(pos);
332
- const a = sorted[i];
333
- const b = _nullishCoalesce(sorted[i + 1], () => ( a));
334
- return a + (b - a) * (pos - i);
335
- }
336
- function chartBoxStats(values) {
337
- const v = values.filter((x) => x !== null && Number.isFinite(x)).sort((a, b) => a - b);
338
- if (!v.length) return null;
339
- const q1 = chartQuantile(v, 0.25);
340
- const median = chartQuantile(v, 0.5);
341
- const q3 = chartQuantile(v, 0.75);
342
- const iqr = q3 - q1;
343
- const lo = q1 - 1.5 * iqr;
344
- const hi = q3 + 1.5 * iqr;
345
- return {
346
- min: v[0],
347
- max: v[v.length - 1],
348
- q1,
349
- median,
350
- q3,
351
- mean: v.reduce((t, x) => t + x, 0) / v.length,
352
- lowerWhisker: _nullishCoalesce(v.find((x) => x >= lo), () => ( q1)),
353
- upperWhisker: _nullishCoalesce([...v].reverse().find((x) => x <= hi), () => ( q3)),
354
- outliers: v.filter((x) => x < lo || x > hi),
355
- count: v.length
356
- };
357
- }
358
- function chartSquarify(values, rect) {
359
- const out = values.map(() => ({ x: rect.x, y: rect.y, width: 0, height: 0 }));
360
- const items = values.map((v, i2) => [i2, v]).filter(([, v]) => v > 0 && Number.isFinite(v)).sort((a, b) => b[1] - a[1]);
361
- const total = items.reduce((t, [, v]) => t + v, 0);
362
- const area = rect.width * rect.height;
363
- if (!(total > 0 && area > 0)) return out;
364
- const scale = area / total;
365
- const rem = { ...rect };
366
- let row = [];
367
- const worst = (r, side) => {
368
- const s = r.reduce((t, v) => t + v, 0);
369
- if (s <= 0 || side <= 0) return Infinity;
370
- const mn = Math.min(...r);
371
- const mx = Math.max(...r);
372
- return Math.max(side * side * mx / (s * s), s * s / (side * side * mn));
373
- };
374
- const layoutRow = (r) => {
375
- const s = r.reduce((t, [, a]) => t + a, 0);
376
- if (s <= 0) return;
377
- if (rem.width >= rem.height) {
378
- const cw = s / Math.max(1e-6, rem.height);
379
- let y = rem.y;
380
- for (const [j, a] of r) {
381
- const h = a / Math.max(1e-6, cw);
382
- out[j] = { x: rem.x, y, width: cw, height: h };
383
- y += h;
384
- }
385
- rem.x += cw;
386
- rem.width = Math.max(0, rem.width - cw);
387
- } else {
388
- const rh = s / Math.max(1e-6, rem.width);
389
- let x = rem.x;
390
- for (const [j, a] of r) {
391
- const w = a / Math.max(1e-6, rh);
392
- out[j] = { x, y: rem.y, width: w, height: rh };
393
- x += w;
394
- }
395
- rem.y += rh;
396
- rem.height = Math.max(0, rem.height - rh);
397
- }
398
- };
399
- let i = 0;
400
- while (i < items.length) {
401
- const [j, v] = items[i];
402
- const a = v * scale;
403
- const side = Math.min(rem.width, rem.height);
404
- const cur = row.map(([, x]) => x);
405
- if (!row.length || worst([...cur, a], side) <= worst(cur, side)) {
406
- row.push([j, a]);
407
- i++;
408
- } else {
409
- layoutRow(row);
410
- row = [];
411
- }
412
- }
413
- if (row.length) layoutRow(row);
414
- return out;
415
- }
416
- function decimateChartPoints(points, max = 2e3) {
417
- if (points.length <= max) return [...points];
418
- const out = [];
419
- let i = 0;
420
- while (i < points.length) {
421
- const col = Math.floor(points[i].x);
422
- const start = i;
423
- let mn = i;
424
- let mx = i;
425
- let k = i + 1;
426
- while (k < points.length && Math.floor(points[k].x) === col) {
427
- if (points[k].y < points[mn].y) mn = k;
428
- if (points[k].y > points[mx].y) mx = k;
429
- k++;
430
- }
431
- const end = k - 1;
432
- for (const idx of [.../* @__PURE__ */ new Set([start, mn, mx, end])].sort((a, b) => a - b)) out.push(points[idx]);
433
- i = k;
434
- }
435
- return out;
436
- }
437
- var round = (n) => Number(n.toPrecision(6));
438
- function summarizeChartSeries(series, categories) {
439
- const present = series.values.map((v, i) => [i, v]).filter((p) => p[1] !== null && Number.isFinite(p[1]));
440
- const base = { id: series.id, name: series.name, count: present.length, gaps: series.values.length - present.length, min: null, max: null, mean: null, sum: null, minAt: null, maxAt: null, trend: null, change: null };
441
- if (!present.length) return base;
442
- let lo = present[0];
443
- let hi = present[0];
444
- let sum = 0;
445
- for (const p of present) {
446
- if (p[1] < lo[1]) lo = p;
447
- if (p[1] > hi[1]) hi = p;
448
- sum += p[1];
449
- }
450
- const mean = sum / present.length;
451
- let trend = null;
452
- if (present.length >= 2) {
453
- const mx = present.reduce((t, p) => t + p[0], 0) / present.length;
454
- let sxy = 0;
455
- let sxx = 0;
456
- for (const [i, v] of present) {
457
- sxy += (i - mx) * (v - mean);
458
- sxx += (i - mx) ** 2;
459
- }
460
- const slope = sxx ? sxy / sxx : 0;
461
- const spread = hi[1] - lo[1];
462
- const travel = Math.abs(slope * (present[present.length - 1][0] - present[0][0]));
463
- trend = !spread || travel < spread * 0.05 ? "flat" : slope > 0 ? "rising" : "falling";
464
- }
465
- const first = present[0][1];
466
- const last = present[present.length - 1][1];
467
- return {
468
- ...base,
469
- min: round(lo[1]),
470
- max: round(hi[1]),
471
- mean: round(mean),
472
- sum: round(sum),
473
- minAt: _nullishCoalesce(categories[lo[0]], () => ( String(lo[0]))),
474
- maxAt: _nullishCoalesce(categories[hi[0]], () => ( String(hi[0]))),
475
- trend,
476
- change: present.length >= 2 && first !== 0 ? round((last - first) / Math.abs(first)) : null
477
- };
478
- }
479
69
 
480
- // src/chart/trend.ts
481
- var degree = (t) => t.type === "polynomial" ? Math.max(2, Math.min(6, _nullishCoalesce(t.order, () => ( 2)))) : 1;
482
- var logX = (type) => type === "logarithmic" || type === "power";
483
- var logY = (type) => type === "exponential" || type === "power";
484
- function fitChartTrendline(trendline, points) {
485
- const type = trendline.type;
486
- if (type === "moving-average") return null;
487
- const d = degree(trendline);
488
- const data = points.filter(([x, y]) => Number.isFinite(x) && Number.isFinite(y) && (!logX(type) || x > 0) && (!logY(type) || y > 0)).map(([x, y]) => [logX(type) ? Math.log(x) : x, logY(type) ? Math.log(y) : y]);
489
- if (data.length < 2 || data.length <= d) return null;
490
- let fixed = null;
491
- const b = trendline.intercept;
492
- if (b !== void 0 && b !== null && Number.isFinite(b)) {
493
- if (type === "linear" || type === "polynomial") fixed = b;
494
- else if (type === "exponential" && b > 0) fixed = Math.log(b);
495
- }
496
- const n = data.length;
497
- const center = fixed !== null ? 0 : data.reduce((t, p) => t + p[0], 0) / n;
498
- const scale = data.reduce((m2, p) => Math.max(m2, Math.abs(p[0] - center)), 0);
499
- if (!(Number.isFinite(scale) && scale > 0)) return null;
500
- const first = fixed !== null ? 1 : 0;
501
- const b0 = _nullishCoalesce(fixed, () => ( 0));
502
- const m = d + 1 - first;
503
- const ata = Array.from({ length: m }, () => Array(m).fill(0));
504
- const aty = Array(m).fill(0);
505
- for (const [x, y] of data) {
506
- const u = (x - center) / scale;
507
- const pows = Array.from({ length: m }, (_, k) => Math.pow(u, k + first));
508
- for (let i = 0; i < m; i++) {
509
- aty[i] += pows[i] * (y - b0);
510
- for (let j = 0; j < m; j++) ata[i][j] += pows[i] * pows[j];
511
- }
512
- }
513
- const sol = solve(ata, aty);
514
- if (!sol) return null;
515
- const a = Array(d + 1).fill(b0);
516
- sol.forEach((v, k) => a[k + first] = v);
517
- const coefficients = expand(a, center, scale);
518
- if (!coefficients) return null;
519
- const poly = (x) => {
520
- const u = (x - center) / scale;
521
- return a.reduceRight((acc, c) => acc * u + c, 0);
522
- };
523
- const mean = data.reduce((t, p) => t + p[1], 0) / n;
524
- let ssRes = 0;
525
- let ssTot = 0;
526
- for (const [x, y] of data) {
527
- ssRes += (y - poly(x)) ** 2;
528
- ssTot += fixed !== null ? (y - b0) ** 2 : (y - mean) ** 2;
529
- }
530
- const r22 = ssTot > 0 && Number.isFinite(ssTot) && Number.isFinite(ssRes) ? 1 - ssRes / ssTot : null;
531
- return {
532
- type,
533
- coefficients,
534
- r2: r22,
535
- equation: equationText(type, coefficients),
536
- points: n,
537
- evaluate(x) {
538
- let xx = x;
539
- if (logX(type)) {
540
- if (!(x > 0)) return null;
541
- xx = Math.log(x);
542
- }
543
- const p = poly(xx);
544
- const y = logY(type) ? Math.exp(p) : p;
545
- return Number.isFinite(y) ? y : null;
546
- }
547
- };
548
- }
549
- function solve(a, b) {
550
- const n = b.length;
551
- const big = a.flat().reduce((m, v) => Math.max(m, Math.abs(v)), 0);
552
- if (!(Number.isFinite(big) && big > 0)) return null;
553
- for (let col = 0; col < n; col++) {
554
- let piv = col;
555
- for (let r = col + 1; r < n; r++) if (Math.abs(a[r][col]) > Math.abs(a[piv][col])) piv = r;
556
- [a[col], a[piv]] = [a[piv], a[col]];
557
- [b[col], b[piv]] = [b[piv], b[col]];
558
- const p = a[col][col];
559
- if (!Number.isFinite(p) || Math.abs(p) <= big * 1e-13) return null;
560
- for (let r = col + 1; r < n; r++) {
561
- const f = a[r][col] / p;
562
- for (let c = col; c < n; c++) a[r][c] -= f * a[col][c];
563
- b[r] -= f * b[col];
564
- }
565
- }
566
- const x = Array(n).fill(0);
567
- for (let r = n - 1; r >= 0; r--) {
568
- let s = 0;
569
- for (let c = r + 1; c < n; c++) s += a[r][c] * x[c];
570
- x[r] = (b[r] - s) / a[r][r];
571
- }
572
- return x.every(Number.isFinite) ? x : null;
573
- }
574
- function expand(a, c, s) {
575
- const out = Array(a.length).fill(0);
576
- a.forEach((ak, k) => {
577
- const lead = ak / Math.pow(s, k);
578
- let binom = 1;
579
- for (let j = 0; j <= k; j++) {
580
- out[j] += lead * binom * Math.pow(-c, k - j);
581
- binom = binom * (k - j) / (j + 1);
582
- }
583
- });
584
- return out.every(Number.isFinite) ? out : null;
585
- }
586
- var POWERS = ["", "x", "x\xB2", "x\xB3", "x\u2074", "x\u2075", "x\u2076"];
587
- function equationText(type, coef) {
588
- const c0 = _nullishCoalesce(coef[0], () => ( 0));
589
- const c1 = _nullishCoalesce(coef[1], () => ( 0));
590
- if (type === "exponential") return `y = ${trendNumberText(Math.exp(c0))}e^(${trendNumberText(c1)}x)`;
591
- if (type === "power") return `y = ${trendNumberText(Math.exp(c0))}x^${trendNumberText(c1)}`;
592
- if (type === "logarithmic") return terms([[c1, "ln(x)"], [c0, ""]]);
593
- return terms(coef.map((c, k) => [c, _nullishCoalesce(POWERS[k], () => ( "x"))]).reverse());
594
- }
595
- function terms(parts) {
596
- let s = "y = ";
597
- let first = true;
598
- for (const [c, t] of parts) {
599
- const txt = trendNumberText(Math.abs(c));
600
- if (txt === "0") continue;
601
- const neg = c < 0;
602
- if (first) s += neg ? "-" : "";
603
- else s += neg ? " - " : " + ";
604
- if (txt !== "1" || !t) s += txt;
605
- s += t;
606
- first = false;
607
- }
608
- return first ? `${s}0` : s;
609
- }
610
- function trendNumberText(v) {
611
- if (!Number.isFinite(v)) return "#NUM!";
612
- const a = Math.abs(v);
613
- if (a === 0) return "0";
614
- if (a < 1e-4 || a >= 1e11) {
615
- const [mant, exp] = v.toExponential(4).split("e");
616
- const e = Number(exp);
617
- return `${trimZeros(mant)}E${e < 0 ? "-" : "+"}${String(Math.abs(e)).padStart(2, "0")}`;
618
- }
619
- const s = trimZeros(v.toFixed(4));
620
- return s === "-0" ? "0" : s;
621
- }
622
- var trimZeros = (s) => s.includes(".") ? s.replace(/0+$/, "").replace(/\.$/, "") : s;
623
- function chartMovingAverage(points, period) {
624
- const p = Math.max(2, Math.min(1e3, Math.round(period) || 2));
625
- const pts = points.filter(([x, y]) => Number.isFinite(x) && Number.isFinite(y));
626
- const out = [];
627
- let sum = 0;
628
- pts.forEach(([x, y], i) => {
629
- sum += y;
630
- if (i >= p) sum -= pts[i - p][1];
631
- if (i >= p - 1) out.push([x, sum / p]);
632
- });
633
- return out;
634
- }
635
- function chartTrendlineName(trendline, seriesName) {
636
- if (trendline.name) return trendline.name;
637
- const kind = {
638
- linear: "Linear",
639
- exponential: "Expon.",
640
- logarithmic: "Log.",
641
- polynomial: "Poly.",
642
- power: "Power",
643
- "moving-average": `${Math.max(2, _nullishCoalesce(trendline.period, () => ( 2)))} per. Mov. Avg.`
644
- };
645
- return `${kind[trendline.type]} (${seriesName})`;
646
- }
647
- function chartSupportsTrendlines(type, stacking) {
648
- return (type === "bar" || type === "line" || type === "area" || type === "scatter" || type === "bubble") && stacking === "none";
649
- }
650
70
 
651
- // src/chart/layout-shared.ts
652
- var estimateChartTextWidth = (text, size, weight = 400) => text.length * size * (weight >= 600 ? 0.6 : 0.56);
653
- function sameChartSelection(a, b) {
654
- if (!a || !b || a.kind !== b.kind) return false;
655
- switch (a.kind) {
656
- case "axis":
657
- return a.axis === b.axis;
658
- case "series":
659
- return a.seriesId === b.seriesId;
660
- case "point":
661
- case "trendline":
662
- return a.seriesId === b.seriesId && a.index === b.index;
663
- case "category":
664
- return a.index === b.index;
665
- default:
666
- return true;
667
- }
668
- }
669
- function contrastingTextColor(fill) {
670
- let rgb = null;
671
- const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(fill.trim());
672
- if (hex) {
673
- const h = hex[1].length === 3 ? [...hex[1]].map((c) => c + c).join("") : hex[1];
674
- rgb = [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
675
- } else {
676
- const fn = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i.exec(fill.trim());
677
- if (fn) rgb = fn.slice(1, 4).map(Number);
678
- }
679
- if (!rgb) return "#ffffff";
680
- const luminance = (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255;
681
- return luminance > 0.5 ? "#0f172a" : "#ffffff";
682
- }
683
- var r2 = (n) => Math.round(n * 100) / 100;
684
- function curvePath(points, curve, map, moveFirst = true) {
685
- if (!points.length) return "";
686
- const xy = points.map(map);
687
- let d = `${moveFirst ? "M" : "L"}${r2(xy[0][0])},${r2(xy[0][1])}`;
688
- if (points.length === 1) return d;
689
- if (curve === "step") {
690
- for (let i = 1; i < points.length; i++) {
691
- const mid = (points[i - 1].c + points[i].c) / 2;
692
- const a = map({ c: mid, v: points[i - 1].v });
693
- const b = map({ c: mid, v: points[i].v });
694
- d += `L${r2(a[0])},${r2(a[1])}L${r2(b[0])},${r2(b[1])}L${r2(xy[i][0])},${r2(xy[i][1])}`;
695
- }
696
- return d;
697
- }
698
- if (curve === "smooth" && points.length > 2) {
699
- const n = points.length;
700
- const dc = points.slice(1).map((p, i) => p.c - points[i].c);
701
- const slope = points.slice(1).map((p, i) => dc[i] === 0 ? 0 : (p.v - points[i].v) / dc[i]);
702
- const tangent = points.map((_, i) => {
703
- if (i === 0) return slope[0];
704
- if (i === n - 1) return slope[n - 2];
705
- const a = slope[i - 1];
706
- const b = slope[i];
707
- if (a * b <= 0) return 0;
708
- const wa = 2 * dc[i] + dc[i - 1];
709
- const wb = dc[i] + 2 * dc[i - 1];
710
- return (wa + wb) / (wa / a + wb / b);
711
- });
712
- for (let i = 1; i < n; i++) {
713
- const h = dc[i - 1] / 3;
714
- const p0 = points[i - 1];
715
- const p1 = points[i];
716
- const a = map({ c: p0.c + h, v: p0.v + tangent[i - 1] * h });
717
- const b = map({ c: p1.c - h, v: p1.v - tangent[i] * h });
718
- d += `C${r2(a[0])},${r2(a[1])} ${r2(b[0])},${r2(b[1])} ${r2(xy[i][0])},${r2(xy[i][1])}`;
719
- }
720
- return d;
721
- }
722
- for (let i = 1; i < xy.length; i++) d += `L${r2(xy[i][0])},${r2(xy[i][1])}`;
723
- return d;
724
- }
725
- function arcPath(cx, cy, outer, inner, start, end) {
726
- const full = end - start >= Math.PI * 2 - 1e-9;
727
- if (full) end = start + Math.PI * 2 - 1e-4;
728
- const p = (r, a) => `${r2(cx + r * Math.sin(a))},${r2(cy - r * Math.cos(a))}`;
729
- const large = end - start > Math.PI ? 1 : 0;
730
- let d = `M${p(outer, start)}A${r2(outer)},${r2(outer)} 0 ${large} 1 ${p(outer, end)}`;
731
- if (inner > 0) d += `L${p(inner, end)}A${r2(inner)},${r2(inner)} 0 ${large} 0 ${p(inner, start)}Z`;
732
- else d += `L${r2(cx)},${r2(cy)}Z`;
733
- return d;
734
- }
735
- function truncate(text, maxWidth, size, measure) {
736
- if (measure(text, size) <= maxWidth) return text;
737
- let out = text;
738
- while (out.length > 1 && measure(`${out}\u2026`, size) > maxWidth) out = out.slice(0, -1);
739
- return `${out}\u2026`;
740
- }
741
- function markerPath(shape, cx, cy, r) {
742
- switch (shape) {
743
- case "square":
744
- return `M${r2(cx - r)},${r2(cy - r)}H${r2(cx + r)}V${r2(cy + r)}H${r2(cx - r)}Z`;
745
- case "diamond": {
746
- const d = r * 1.3;
747
- return `M${r2(cx)},${r2(cy - d)}L${r2(cx + d)},${r2(cy)}L${r2(cx)},${r2(cy + d)}L${r2(cx - d)},${r2(cy)}Z`;
748
- }
749
- case "triangle": {
750
- const d = r * 1.3;
751
- return `M${r2(cx)},${r2(cy - d)}L${r2(cx + d * 0.87)},${r2(cy + d * 0.5)}L${r2(cx - d * 0.87)},${r2(cy + d * 0.5)}Z`;
752
- }
753
- case "cross": {
754
- const d = r;
755
- return `M${r2(cx - d)},${r2(cy - d)}L${r2(cx + d)},${r2(cy + d)}M${r2(cx - d)},${r2(cy + d)}L${r2(cx + d)},${r2(cy - d)}`;
756
- }
757
- }
758
- }
759
- var tickCount = (length) => Math.max(2, Math.min(10, Math.round(length / 56)));
760
- function axisScale(lo, hi, length, axis, frozen, headroom = false) {
761
- const fixedMin = frozen && Number.isFinite(frozen.min) ? frozen.min : axis.min;
762
- const fixedMax = frozen && Number.isFinite(frozen.max) ? frozen.max : axis.max;
763
- const step = axis.step;
764
- if (step && step > 0 && Number.isFinite(lo) && Number.isFinite(hi)) {
765
- let min = _nullishCoalesce(fixedMin, () => ( Math.floor(lo / step + 1e-9) * step));
766
- let max = _nullishCoalesce(fixedMax, () => ( Math.ceil(hi / step - 1e-9) * step));
767
- if (!(max > min)) max = min + step;
768
- const first = Math.ceil(min / step - 1e-9);
769
- const last = Math.floor(max / step + 1e-9);
770
- if (last - first <= 200) {
771
- const clean3 = (n) => Math.abs(n) < 1e-12 ? 0 : Number(n.toPrecision(12));
772
- min = clean3(min);
773
- max = clean3(max);
774
- const ticks = [];
775
- for (let i = first; i <= last; i++) ticks.push(clean3(i * step));
776
- return { min, max, step, ticks };
777
- }
778
- }
779
- let scale = niceScale(lo, hi, tickCount(length), fixedMin, fixedMax);
780
- const roomy = hi + (hi - lo) * 0.05;
781
- if (headroom && fixedMax === null && hi !== 0 && hi > lo && scale.max === hi && Number.isFinite(roomy)) scale = niceScale(lo, roomy, tickCount(length), fixedMin, fixedMax);
782
- return scale;
783
- }
784
- function clipSegment(a, b, rect) {
785
- let t0 = 0;
786
- let t1 = 1;
787
- const dx = b[0] - a[0];
788
- const dy = b[1] - a[1];
789
- const checks = [
790
- [-dx, a[0] - rect.x],
791
- [dx, rect.x + rect.width - a[0]],
792
- [-dy, a[1] - rect.y],
793
- [dy, rect.y + rect.height - a[1]]
794
- ];
795
- for (const [p, q] of checks) {
796
- if (p === 0) {
797
- if (q < 0) return null;
798
- continue;
799
- }
800
- const r = q / p;
801
- if (p < 0) {
802
- if (r > t1) return null;
803
- if (r > t0) t0 = r;
804
- } else {
805
- if (r < t0) return null;
806
- if (r < t1) t1 = r;
807
- }
808
- }
809
- return [
810
- [a[0] + t0 * dx, a[1] + t0 * dy],
811
- [a[0] + t1 * dx, a[1] + t1 * dy]
812
- ];
813
- }
814
- function clippedPolyline(points, rect) {
815
- let d = "";
816
- let open = false;
817
- let last = null;
818
- for (let i = 1; i < points.length; i++) {
819
- const seg = clipSegment(points[i - 1], points[i], rect);
820
- if (!seg) {
821
- open = false;
822
- continue;
823
- }
824
- const [p, q] = seg;
825
- if (!open || !last || Math.abs(last[0] - p[0]) > 0.01 || Math.abs(last[1] - p[1]) > 0.01) d += `M${r2(p[0])},${r2(p[1])}`;
826
- d += `L${r2(q[0])},${r2(q[1])}`;
827
- last = q;
828
- open = true;
829
- }
830
- return d;
831
- }
832
71
 
833
- // src/chart/layout-cartesian.ts
834
- var MAX_CHART_DATA_LABELS = 200;
835
- var MAX_CHART_LINE_POINTS = 2e3;
836
- var MAX_CHART_MARKERS = 1e3;
837
- function scaleInfo(scale, range, format) {
838
- const domain = [scale.min, scale.max];
839
- const raw = (v) => linearMap(v, domain, range);
840
- const px = (v) => raw(Math.min(scale.max, Math.max(scale.min, v)));
841
- return { scale, range, px, raw, zero: px(0), format, tickText: (t) => formatChartNumber(t, format, _nullishCoalesce(format.decimals, () => ( stepDecimals(scale.step)))) };
842
- }
843
- function categoryFrame(ctx, area, input) {
844
- const { spec, theme, measure, fs, marks } = ctx;
845
- const { labels, horizontal, primary, secondary } = input;
846
- const xAxis = _nullishCoalesce(input.categoryAxis, () => ( spec.xAxis));
847
- const n = Math.max(1, labels.length);
848
- const titleBand = fs * 1.3 + 6;
849
- const labelTarget = _nullishCoalesce(input.labelTarget, () => ( ((i) => ({ kind: "category", index: i }))));
850
- const estimate = (v, length) => {
851
- const s = axisScale(v.lo, v.hi, length, v.axis, v.frozen, v.headroom);
852
- const info = scaleInfo(s, [0, 1], v.format);
853
- return Math.max(0, ...s.ticks.map((t) => measure(info.tickText(t), fs)));
854
- };
855
- const valueLen0 = horizontal ? area.width : area.height;
856
- const valueLabelWidth = primary.axis.show ? estimate(primary, valueLen0) : 0;
857
- const valueLabelWidth2 = _optionalChain([secondary, 'optionalAccess', _2 => _2.axis, 'access', _3 => _3.show]) ? estimate(secondary, valueLen0) : 0;
858
- const catLabelWidth = Math.max(0, ...labels.map((c) => measure(c, fs)));
859
- let left;
860
- let bottom;
861
- let right = 8;
862
- let top = horizontal ? 4 : fs / 2 + 2;
863
- let rotate = 0;
864
- let dateLabels = null;
865
- let rotatedMax = 0;
866
- if (horizontal) {
867
- left = (xAxis.show ? Math.min(catLabelWidth, area.width * 0.35) + 8 : 2) + (xAxis.title ? titleBand : 0);
868
- bottom = (primary.axis.show ? fs * 1.6 : 2) + (primary.axis.title ? titleBand : 0);
869
- right = Math.max(8, valueLabelWidth / 2);
870
- if (secondary) top = (secondary.axis.show ? fs * 1.6 : 4) + (secondary.axis.title ? titleBand : 0);
871
- } else {
872
- left = (primary.axis.show ? valueLabelWidth + 8 : 2) + (primary.axis.title ? titleBand : 0);
873
- if (secondary) right = (secondary.axis.show ? valueLabelWidth2 + 8 : 8) + (secondary.axis.title ? titleBand : 0);
874
- const band2 = (area.width - left - right) / n;
875
- if (xAxis.show && xAxis.kind === "date") dateLabels = chartDateLabels(labels, band2, (t) => measure(t, fs));
876
- if (xAxis.show && !dateLabels && catLabelWidth > band2 * 0.92) rotate = -40;
877
- const sin = Math.sin(Math.PI / 4.5);
878
- const catHeight = rotate ? Math.min(catLabelWidth * sin + fs, area.height * 0.4) : fs * 1.6;
879
- if (rotate) rotatedMax = (catHeight - fs) / sin;
880
- bottom = (xAxis.show ? catHeight : 2) + (xAxis.title ? titleBand : 0);
881
- }
882
- const plot = {
883
- x: area.x + left,
884
- y: area.y + top,
885
- width: Math.max(1, area.width - left - right),
886
- height: Math.max(1, area.height - bottom - top)
887
- };
888
- const valueLen = horizontal ? plot.width : plot.height;
889
- const range = horizontal ? [plot.x, plot.x + plot.width] : [plot.y + plot.height, plot.y];
890
- const value = scaleInfo(axisScale(primary.lo, primary.hi, valueLen, primary.axis, primary.frozen, primary.headroom), range, primary.format);
891
- const value2 = secondary ? scaleInfo(axisScale(secondary.lo, secondary.hi, valueLen, secondary.axis, secondary.frozen, secondary.headroom), range, secondary.format) : void 0;
892
- const catStart = horizontal ? plot.y : plot.x;
893
- const catLen = horizontal ? plot.height : plot.width;
894
- const band = catLen / n;
895
- const catCenter = (i) => catStart + band * (i + 0.5);
896
- const map = (p) => horizontal ? [p.v, p.c] : [p.c, p.v];
897
- const gridAt = (info, key) => info.scale.ticks.forEach((t, i) => {
898
- const p = info.px(t);
899
- const [x1, y1] = map({ c: catStart, v: p });
900
- const [x2, y2] = map({ c: catStart + catLen, v: p });
901
- marks.push({ kind: "line", key: `grid-${key}-${i}`, role: "grid", x1, y1, x2, y2, stroke: theme.grid, strokeWidth: 1 });
902
- });
903
- if (primary.axis.gridlines) gridAt(value, "y");
904
- if (value2 && secondary.axis.gridlines) gridAt(value2, "y2");
905
- if (xAxis.gridlines) {
906
- for (let i = 1; i < n; i++) {
907
- const c = catStart + band * i;
908
- const [x1, y1] = map({ c, v: range[0] });
909
- const [x2, y2] = map({ c, v: range[1] });
910
- marks.push({ kind: "line", key: `grid-x-${i}`, role: "grid", x1, y1, x2, y2, stroke: theme.grid, strokeWidth: 1 });
911
- }
912
- }
913
- const ticksFor = (info, v, far) => {
914
- if (!v.axis.show) return;
915
- const target = { kind: "axis", axis: v.key };
916
- info.scale.ticks.forEach((t, i) => {
917
- const p = info.px(t);
918
- const label = info.tickText(t);
919
- const key = `tick-${v.key}-${i}`;
920
- if (horizontal) {
921
- if (far) marks.push({ kind: "text", key, role: "tick-label", x: p, y: plot.y - 6, text: label, anchor: "middle", baseline: "bottom", size: fs, fill: theme.mutedText, target });
922
- else marks.push({ kind: "text", key, role: "tick-label", x: p, y: plot.y + plot.height + 6, text: label, anchor: "middle", baseline: "top", size: fs, fill: theme.mutedText, target });
923
- } else if (far) marks.push({ kind: "text", key, role: "tick-label", x: plot.x + plot.width + 8, y: p, text: label, anchor: "start", baseline: "middle", size: fs, fill: theme.mutedText, target });
924
- else marks.push({ kind: "text", key, role: "tick-label", x: plot.x - 8, y: p, text: label, anchor: "end", baseline: "middle", size: fs, fill: theme.mutedText, target });
925
- });
926
- };
927
- ticksFor(value, primary, false);
928
- if (value2) ticksFor(value2, secondary, true);
929
- const xTarget = { kind: "axis", axis: "x" };
930
- if (xAxis.show) {
931
- const [x1, y1] = map({ c: catStart, v: value.zero });
932
- const [x2, y2] = map({ c: catStart + catLen, v: value.zero });
933
- marks.push({ kind: "line", key: "axis-x", role: "axis", x1, y1, x2, y2, stroke: theme.axis, strokeWidth: 1, target: xTarget });
934
- const every = dateLabels ? 1 : horizontal ? Math.max(1, Math.ceil(fs * 1.3 / band)) : rotate ? Math.max(1, Math.ceil(fs * 1.4 / band)) : 1;
935
- let hidden = 0;
936
- let truncated = 0;
937
- labels.forEach((c, i) => {
938
- const text0 = dateLabels ? dateLabels.labels.get(i) : i % every ? void 0 : c;
939
- if (text0 === void 0) {
940
- hidden++;
941
- return;
942
- }
943
- const target = labelTarget(i);
944
- const selected = target ? ctx.isSelected(target) : false;
945
- const fill = selected ? theme.selection : theme.mutedText;
946
- const extra = target ? { target, selected } : {};
947
- if (horizontal) {
948
- const maxW = left - (xAxis.title ? titleBand : 0) - 8;
949
- const text = truncate(text0, maxW, fs, measure);
950
- if (text !== text0) truncated++;
951
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: plot.x - 8, y: catCenter(i), text, anchor: "end", baseline: "middle", size: fs, fill, ...extra });
952
- } else if (rotate) {
953
- const room = (catCenter(i) - 2) / Math.cos(Math.PI / 4.5);
954
- const text = truncate(text0, Math.max(fs, Math.min(rotatedMax, room)), fs, measure);
955
- if (text !== text0) truncated++;
956
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: catCenter(i), y: plot.y + plot.height + 8, text, anchor: "end", baseline: "middle", size: fs, fill, rotate, ...extra });
957
- } else {
958
- const text = dateLabels ? text0 : truncate(text0, Math.max(band - 4, fs * 2), fs, measure);
959
- if (text !== text0) truncated++;
960
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: catCenter(i), y: plot.y + plot.height + 6, text, anchor: dateLabels ? "start" : "middle", baseline: "top", size: fs, fill, ...extra });
961
- }
962
- });
963
- if (dateLabels) {
964
- for (const i of dateLabels.indexes) {
965
- const x = catCenter(i);
966
- marks.push({ kind: "line", key: `tick-mark-x-${i}`, role: "tick", x1: x, y1: plot.y + plot.height, x2: x, y2: plot.y + plot.height + 4, stroke: theme.axis, strokeWidth: 1 });
967
- }
968
- }
969
- if (hidden && !dateLabels) ctx.warn("labels-hidden", `${hidden} of ${labels.length} category labels are hidden so the rest do not overlap.`);
970
- if (truncated) ctx.warn("labels-truncated", `${truncated} category label${truncated === 1 ? " was" : "s were"} shortened to fit.`);
971
- }
972
- const yTarget = { kind: "axis", axis: "y" };
973
- const valueTitle = primary.axis.title;
974
- const catTitle = xAxis.title;
975
- const bottomTitle = horizontal ? valueTitle : catTitle;
976
- const leftTitle = horizontal ? catTitle : valueTitle;
977
- if (bottomTitle)
978
- marks.push({ kind: "text", key: `axis-title-${horizontal ? "y" : "x"}`, role: "axis-title", x: plot.x + plot.width / 2, y: area.y + area.height, text: bottomTitle, anchor: "middle", baseline: "bottom", size: fs + 1, weight: 500, fill: theme.text, target: horizontal ? yTarget : xTarget });
979
- if (leftTitle)
980
- marks.push({ kind: "text", key: `axis-title-${horizontal ? "x" : "y"}`, role: "axis-title", x: area.x, y: plot.y + plot.height / 2, text: leftTitle, anchor: "middle", baseline: "top", size: fs + 1, weight: 500, fill: theme.text, rotate: -90, target: horizontal ? xTarget : yTarget });
981
- if (_optionalChain([secondary, 'optionalAccess', _4 => _4.axis, 'access', _5 => _5.title])) {
982
- const target = { kind: "axis", axis: "y2" };
983
- if (horizontal) marks.push({ kind: "text", key: "axis-title-y2", role: "axis-title", x: plot.x + plot.width / 2, y: area.y, text: secondary.axis.title, anchor: "middle", baseline: "top", size: fs + 1, weight: 500, fill: theme.text, target });
984
- else marks.push({ kind: "text", key: "axis-title-y2", role: "axis-title", x: area.x + area.width, y: plot.y + plot.height / 2, text: secondary.axis.title, anchor: "middle", baseline: "top", size: fs + 1, weight: 500, fill: theme.text, rotate: 90, target });
985
- }
986
- for (const axis of ["x", "y", "y2"]) {
987
- if (!ctx.isSelected({ kind: "axis", axis })) continue;
988
- if (axis === "y2" && !secondary) continue;
989
- let box;
990
- if (axis === "y2") box = horizontal ? { x: plot.x - 4, y: area.y, width: plot.width + 8, height: plot.y - area.y - 2 } : { x: plot.x + plot.width + 2, y: plot.y - fs / 2, width: area.x + area.width - plot.x - plot.width - 2, height: plot.height + fs };
991
- else {
992
- const onLeft = axis === "y" !== horizontal;
993
- box = onLeft ? { x: area.x, y: plot.y - fs / 2, width: left - 2, height: plot.height + fs } : { x: plot.x - 4, y: plot.y + plot.height + 2, width: plot.width + 8, height: area.y + area.height - plot.y - plot.height - 2 };
994
- }
995
- ctx.outline(`axis-${axis}-selection`, box);
996
- }
997
- return { plot, horizontal, n, band, catStart, catLen, catCenter, map, value, value2 };
998
- }
999
- var toValueScale = (info, axis) => ({ axis, domain: [info.scale.min, info.scale.max], range: info.range, ticks: info.scale.ticks });
1000
- var order = (t) => t === "area" ? 0 : t === "bar" ? 1 : t === "line" ? 2 : 3;
1001
- function pointMark(base, shape, cx, cy, r, fill, stroke, strokeWidth) {
1002
- if (shape === "circle" || shape === "hit" || shape === "none") return { kind: "circle", role: "point", ...base, cx, cy, r, fill, ...stroke ? { stroke, strokeWidth } : {} };
1003
- const closed = shape !== "cross";
1004
- return { kind: "path", role: "point", ...base, d: markerPath(shape, cx, cy, r), fill: closed ? fill : "none", stroke: _nullishCoalesce(stroke, () => ( fill)), strokeWidth: _nullishCoalesce(strokeWidth, () => ( 2)) };
1005
- }
1006
- function drawTrendlines(ctx, plot, series, color, points, toPx, labels) {
1007
- (_nullishCoalesce(series.trendlines, () => ( []))).forEach((t, ti) => {
1008
- const target = { kind: "trendline", seriesId: series.id, index: ti };
1009
- const selected = ctx.isSelected(target);
1010
- const stroke = _nullishCoalesce(t.color, () => ( color));
1011
- let px = [];
1012
- if (t.type === "moving-average") px = chartMovingAverage(points, _nullishCoalesce(t.period, () => ( 2))).map(([x, y]) => toPx(x, y));
1013
- else {
1014
- const fit = fitChartTrendline(t, points);
1015
- if (!fit) {
1016
- ctx.warn("values-skipped", `The ${t.type} trendline on "${series.name}" could not be fitted (too few usable points).`);
1017
- return;
1018
- }
1019
- const xs = points.map((p) => p[0]);
1020
- const lo = Math.min(...xs) - (_nullishCoalesce(t.backward, () => ( 0)));
1021
- const hi = Math.max(...xs) + (_nullishCoalesce(t.forward, () => ( 0)));
1022
- const steps = t.type === "linear" ? 1 : 200;
1023
- for (let k = 0; k <= steps; k++) {
1024
- const x = lo + (hi - lo) * k / steps;
1025
- const y = fit.evaluate(x);
1026
- if (y !== null) px.push(toPx(x, y));
1027
- }
1028
- if (t.showEquation) labels.push({ text: fit.equation, color: stroke, target });
1029
- if (t.showR2) labels.push({ text: fit.r2 === null ? "R\xB2 = #N/A" : `R\xB2 = ${trendNumberText(fit.r2)}`, color: stroke, target });
1030
- }
1031
- const d = clippedPolyline(px, plot);
1032
- if (!d) return;
1033
- ctx.marks.push({ kind: "path", key: `trendline-${series.id}-${ti}`, role: "trendline", d, fill: "none", stroke, strokeWidth: selected ? 3 : 1.5, dash: "6 4", target, selected });
1034
- });
1035
- }
1036
- function drawTrendLabels(ctx, plot, labels) {
1037
- labels.forEach(
1038
- (l, i) => ctx.marks.push({ kind: "text", key: `trendline-label-${i}`, role: "trendline-label", x: plot.x + plot.width - 4, y: plot.y + 4 + i * (ctx.fs + 3), text: l.text, anchor: "end", baseline: "top", size: ctx.fs - 1, fill: l.color, target: l.target })
1039
- );
1040
- }
1041
- function barLabel(ctx, text, rect, horizontal, positive, stacked, fill, plot) {
1042
- const { measure, fs, spec, theme } = ctx;
1043
- const size = fs - 1;
1044
- const tw = measure(text, size);
1045
- const th = size + 2;
1046
- const along = horizontal ? rect.width : rect.height;
1047
- const across = horizontal ? rect.height : rect.width;
1048
- const need = horizontal ? tw + 6 : th + 2;
1049
- const fitsInside = along >= need && across >= (horizontal ? th : Math.min(tw, across + 1));
1050
- let position = spec.labelPosition;
1051
- if (position === "auto") position = stacked ? "center" : "outside";
1052
- const cx = rect.x + rect.width / 2;
1053
- const cy = rect.y + rect.height / 2;
1054
- const inner = contrastingTextColor(fill);
1055
- const centre = () => ({ x: cx, y: cy, anchor: "middle", baseline: "middle", fill: inner });
1056
- const insideEnd = () => horizontal ? { x: positive ? rect.x + rect.width - 4 : rect.x + 4, y: cy, anchor: positive ? "end" : "start", baseline: "middle", fill: inner } : { x: cx, y: positive ? rect.y + 3 : rect.y + rect.height - 3, anchor: "middle", baseline: positive ? "top" : "bottom", fill: inner };
1057
- const outside = () => horizontal ? { x: positive ? rect.x + rect.width + 4 : rect.x - 4, y: cy, anchor: positive ? "start" : "end", baseline: "middle", fill: theme.text } : { x: cx, y: positive ? rect.y - 4 : rect.y + rect.height + 4, anchor: "middle", baseline: positive ? "bottom" : "top", fill: theme.text };
1058
- const outsideFits = () => {
1059
- if (horizontal) return positive ? rect.x + rect.width + 4 + tw <= plot.x + plot.width + 8 : rect.x - 4 - tw >= plot.x - 8;
1060
- return positive ? rect.y - 4 - th >= plot.y - fs : rect.y + rect.height + 4 + th <= plot.y + plot.height + fs;
1061
- };
1062
- if (position === "center") return fitsInside ? centre() : null;
1063
- if (position === "inside") return fitsInside ? insideEnd() : stacked ? null : outside();
1064
- if (stacked) return fitsInside ? centre() : null;
1065
- if (outsideFits()) return outside();
1066
- return fitsInside ? insideEnd() : null;
1067
- }
1068
- function layoutCartesian(ctx, area, visible) {
1069
- const { spec, theme, marks, measure, fs } = ctx;
1070
- const horizontal = spec.orientation === "horizontal";
1071
- const n = spec.categories.length;
1072
- const types = new Map(visible.map((s) => [s.id, _chunkNEOO6QJDcjs.chartSeriesType.call(void 0, spec, s)]));
1073
- const stacked = spec.stacking !== "none";
1074
- const percent = spec.stacking === "percent";
1075
- const onSecondary = (s) => s.axis === "secondary";
1076
- const useSecondary = visible.some(onSecondary);
1077
- const stacks = /* @__PURE__ */ new Map();
1078
- if (stacked) {
1079
- for (const kind of ["bar", "area"]) {
1080
- for (const secondary of [false, true]) {
1081
- const group = visible.filter((s) => types.get(s.id) === kind && onSecondary(s) === secondary);
1082
- if (!group.length) continue;
1083
- const totals = Array.from({ length: n }, (_, i) => group.reduce((t, s) => t + Math.abs(_nullishCoalesce(s.values[i], () => ( 0))), 0));
1084
- const pos = Array(n).fill(0);
1085
- const neg = Array(n).fill(0);
1086
- for (const s of group) {
1087
- const segments = s.values.map((raw, i) => {
1088
- if (raw === null && kind === "bar") return null;
1089
- let v = _nullishCoalesce(raw, () => ( 0));
1090
- if (percent) v = totals[i] ? v / totals[i] : 0;
1091
- const base = v >= 0 ? pos[i] : neg[i];
1092
- const seg = [base, base + v];
1093
- if (v >= 0) pos[i] += v;
1094
- else neg[i] += v;
1095
- return seg;
1096
- });
1097
- stacks.set(s.id, { segments });
1098
- }
1099
- }
1100
- }
1101
- }
1102
- const range = (secondary) => {
1103
- let lo = Infinity;
1104
- let hi = -Infinity;
1105
- const see = (v) => {
1106
- lo = Math.min(lo, v);
1107
- hi = Math.max(hi, v);
1108
- };
1109
- const group = visible.filter((s) => onSecondary(s) === secondary);
1110
- for (const s of group) {
1111
- const stack = stacks.get(s.id);
1112
- if (stack) stack.segments.forEach((seg) => seg && (see(seg[0]), see(seg[1])));
1113
- else s.values.forEach((v) => v !== null && Number.isFinite(v) && see(v));
1114
- }
1115
- if (!Number.isFinite(lo)) {
1116
- lo = 0;
1117
- hi = 1;
1118
- }
1119
- if (group.some((s) => types.get(s.id) === "bar" || types.get(s.id) === "area")) {
1120
- lo = Math.min(lo, 0);
1121
- hi = Math.max(hi, 0);
1122
- }
1123
- const lineLike = group.some((s) => types.get(s.id) === "line" || types.get(s.id) === "scatter");
1124
- return { lo, hi, lineLike };
1125
- };
1126
- const pctFormat = (f) => percent && !f.style && !f.code ? { ...f, style: "percent" } : f;
1127
- const p = range(false);
1128
- const s2 = useSecondary ? range(true) : null;
1129
- const frame = categoryFrame(ctx, area, {
1130
- labels: spec.categories,
1131
- horizontal,
1132
- primary: { lo: p.lo, hi: p.hi, axis: spec.yAxis, format: pctFormat(spec.yAxis.format), frozen: ctx.options.valueDomain, headroom: p.lineLike, key: "y" },
1133
- secondary: s2 ? { lo: s2.lo, hi: s2.hi, axis: spec.yAxis2, format: pctFormat(spec.yAxis2.format), frozen: ctx.options.valueDomain2, headroom: s2.lineLike, key: "y2" } : void 0
1134
- });
1135
- const { plot, band, catCenter, map, catStart } = frame;
1136
- const infoOf = (s) => onSecondary(s) && frame.value2 ? frame.value2 : frame.value;
1137
- const bars = visible.filter((s) => types.get(s.id) === "bar");
1138
- const barAxes = [...new Set(bars.map((s) => onSecondary(s)))];
1139
- const slots = stacked ? barAxes.length : bars.length;
1140
- const groupWidth = band * (1 - spec.gapWidth);
1141
- const o = Math.max(-1, Math.min(0.99, spec.overlap));
1142
- const barWidth = slots ? groupWidth / (slots - (slots - 1) * o) : 0;
1143
- const slotOf = (s) => stacked ? barAxes.indexOf(onSecondary(s)) : bars.indexOf(s);
1144
- const labelMarks = [];
1145
- const trendLabels = [];
1146
- let hiddenLabels = 0;
1147
- const trendsAllowed = chartSupportsTrendlines(spec.type, spec.stacking);
1148
- const drawOrder = [...visible].sort((a, b) => order(types.get(a.id)) - order(types.get(b.id)));
1149
- for (const s of drawOrder) {
1150
- const si = spec.series.indexOf(s);
1151
- const color = _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, si);
1152
- const type = types.get(s.id);
1153
- const stack = stacks.get(s.id);
1154
- const selSeries = ctx.seriesSelected(s.id);
1155
- const seriesTarget = { kind: "series", seriesId: s.id };
1156
- const info = infoOf(s);
1157
- const valuePx = info.px;
1158
- const labelsOn = (_nullishCoalesce(s.dataLabels, () => ( spec.dataLabels))) && s.values.length <= MAX_CHART_DATA_LABELS;
1159
- if ((_nullishCoalesce(s.dataLabels, () => ( spec.dataLabels))) && !labelsOn) ctx.warn("data-labels-hidden", `Data labels are off for "${s.name}": it has more than ${MAX_CHART_DATA_LABELS} points.`);
1160
- const labelFormat = _nullishCoalesce(s.format, () => ( info.format));
1161
- const dataLabel = (v) => formatChartNumber(v, labelFormat, _nullishCoalesce(labelFormat.decimals, () => ( void 0)));
1162
- if (type === "bar") {
1163
- const slot = slotOf(s);
1164
- s.values.forEach((raw, i) => {
1165
- const seg = stack ? stack.segments[i] : raw === null ? null : [0, raw];
1166
- if (!seg || raw === null || !Number.isFinite(raw)) return;
1167
- const a = valuePx(seg[0]);
1168
- const b = valuePx(seg[1]);
1169
- const c0 = catCenter(i) - groupWidth / 2 + slot * barWidth * (1 - o);
1170
- const cw = barWidth;
1171
- const target = { kind: "point", seriesId: s.id, index: i };
1172
- const selected = ctx.isSelected(target);
1173
- const [x, y] = map({ c: c0, v: Math.min(a, b) });
1174
- const rect = horizontal ? { x: Math.min(a, b), y: c0, width: Math.abs(b - a), height: cw } : { x, y, width: cw, height: Math.abs(b - a) };
1175
- const fill = _chunkNEOO6QJDcjs.chartPointColor.call(void 0, spec, si, i);
1176
- marks.push({
1177
- kind: "rect",
1178
- key: `bar-${s.id}-${i}`,
1179
- role: "bar",
1180
- ...rect,
1181
- fill,
1182
- radius: Math.min(2, cw / 4),
1183
- target,
1184
- selected: selected || selSeries,
1185
- ...selSeries ? { stroke: theme.selection, strokeWidth: 1.5 } : {}
1186
- });
1187
- if (selected) ctx.outline(`bar-${s.id}-${i}-selection`, { x: rect.x - 2, y: rect.y - 2, width: rect.width + 4, height: rect.height + 4 });
1188
- if (labelsOn) {
1189
- const v = percent ? seg[1] - seg[0] : raw;
1190
- const text = dataLabel(v);
1191
- const at = barLabel(ctx, text, rect, horizontal, seg[1] >= seg[0], stacked, fill, plot);
1192
- if (!at) {
1193
- hiddenLabels++;
1194
- return;
1195
- }
1196
- labelMarks.push({ kind: "text", key: `label-${s.id}-${i}`, role: "data-label", ...at, text, size: fs - 1, target });
1197
- }
1198
- });
1199
- } else {
1200
- const curve = _nullishCoalesce(s.curve, () => ( spec.curve));
1201
- const pointValue = (i) => {
1202
- const v = stack ? _nullishCoalesce(_optionalChain([stack, 'access', _6 => _6.segments, 'access', _7 => _7[i], 'optionalAccess', _8 => _8[1]]), () => ( null)) : s.values[i];
1203
- return v !== null && Number.isFinite(v) ? v : null;
1204
- };
1205
- const runs = [];
1206
- let run = [];
1207
- for (let i = 0; i < n; i++) {
1208
- const v = pointValue(i);
1209
- if (v === null) {
1210
- if (run.length) runs.push(run);
1211
- run = [];
1212
- continue;
1213
- }
1214
- run.push({ c: catCenter(i), v: valuePx(v) });
1215
- }
1216
- if (run.length) runs.push(run);
1217
- const thin = (r) => {
1218
- if (r.length <= MAX_CHART_LINE_POINTS) return r;
1219
- const pts = decimateChartPoints(r.map((p2) => ({ x: p2.c, y: p2.v, p: p2 })), MAX_CHART_LINE_POINTS).map((q) => q.p);
1220
- ctx.warn("points-decimated", `"${s.name}" has ${r.length} points; its line is drawn with ${pts.length} (one column of pixels each).`);
1221
- return pts;
1222
- };
1223
- const drawn = runs.map(thin);
1224
- if (type === "area") {
1225
- const parts = drawn.map((r) => {
1226
- const baseline = stack ? r.map((pt) => ({ c: pt.c, v: valuePx(_nullishCoalesce(_optionalChain([stack, 'access', _9 => _9.segments, 'access', _10 => _10[Math.round((pt.c - catStart) / band - 0.5)], 'optionalAccess', _11 => _11[0]]), () => ( 0))) })).reverse() : [
1227
- { c: r[r.length - 1].c, v: info.zero },
1228
- { c: r[0].c, v: info.zero }
1229
- ];
1230
- return `${curvePath(r, curve, map)}${stack ? curvePath(baseline, curve, map, false) : baseline.map((pt) => `L${map(pt).map(r2).join(",")}`).join("")}Z`;
1231
- });
1232
- marks.push({ kind: "path", key: `area-${s.id}`, role: "area", d: parts.join(""), fill: color, opacity: 0.22, target: seriesTarget, selected: selSeries });
1233
- }
1234
- if (type === "line" || type === "area") {
1235
- marks.push({ kind: "path", key: `line-${s.id}`, role: "line", d: drawn.map((r) => curvePath(r, curve, map)).join(""), fill: "none", stroke: color, strokeWidth: selSeries ? 3.5 : 2, target: seriesTarget, selected: selSeries });
1236
- }
1237
- const marker = _nullishCoalesce(s.marker, () => ( (type === "scatter" || spec.points ? "circle" : "none")));
1238
- const showDots = marker !== "none";
1239
- const thinMarkers = n > MAX_CHART_MARKERS;
1240
- const cells = /* @__PURE__ */ new Set();
1241
- for (let i = 0; i < n; i++) {
1242
- const v = pointValue(i);
1243
- if (v === null || s.values[i] === null) continue;
1244
- const [cx, cy] = map({ c: catCenter(i), v: valuePx(v) });
1245
- if (thinMarkers) {
1246
- const cell = `${Math.round(cx / 2)},${Math.round(cy / 2)}`;
1247
- if (cells.has(cell)) continue;
1248
- cells.add(cell);
1249
- }
1250
- const target = { kind: "point", seriesId: s.id, index: i };
1251
- const selected = ctx.isSelected(target);
1252
- const r = type === "scatter" ? 4.5 : 3.5;
1253
- const pointColor = _chunkNEOO6QJDcjs.chartPointColor.call(void 0, spec, si, i);
1254
- const fill = showDots ? type === "scatter" ? pointColor : theme.surface : "transparent";
1255
- marks.push(
1256
- pointMark({ key: `point-${s.id}-${i}`, target, selected: selected || selSeries, opacity: type === "scatter" ? 0.85 : void 0 }, showDots ? marker : "hit", cx, cy, showDots ? r : 6, fill, showDots ? pointColor : void 0, 2)
1257
- );
1258
- if (selected) marks.push({ kind: "circle", key: `point-${s.id}-${i}-selection`, role: "selection", cx, cy, r: r + 3.5, fill: "none", stroke: theme.selection, strokeWidth: 1.5 });
1259
- if (labelsOn) {
1260
- const raw = s.values[i];
1261
- const shown = percent && stack ? stack.segments[i][1] - stack.segments[i][0] : raw;
1262
- labelMarks.push({
1263
- kind: "text",
1264
- key: `label-${s.id}-${i}`,
1265
- role: "data-label",
1266
- x: horizontal ? cx + 8 : cx,
1267
- y: horizontal ? cy : cy - 8,
1268
- text: dataLabel(shown),
1269
- anchor: horizontal ? "start" : "middle",
1270
- baseline: horizontal ? "middle" : "bottom",
1271
- size: fs - 1,
1272
- fill: theme.text,
1273
- target
1274
- });
1275
- }
1276
- }
1277
- }
1278
- if (trendsAllowed && _optionalChain([s, 'access', _12 => _12.trendlines, 'optionalAccess', _13 => _13.length])) {
1279
- const points = [];
1280
- s.values.forEach((v, i) => v !== null && Number.isFinite(v) && points.push([i + 1, v]));
1281
- const toPx = (x, y) => map({ c: catStart + band * (x - 0.5), v: info.raw(y) });
1282
- drawTrendlines(ctx, plot, s, color, points, toPx, trendLabels);
1283
- }
1284
- }
1285
- marks.push(...labelMarks);
1286
- drawTrendLabels(ctx, plot, trendLabels);
1287
- if (hiddenLabels) ctx.warn("data-labels-hidden", `${hiddenLabels} data label${hiddenLabels === 1 ? "" : "s"} did not fit and ${hiddenLabels === 1 ? "is" : "are"} hidden.`);
1288
- return {
1289
- plot,
1290
- valueScale: toValueScale(frame.value, horizontal ? "x" : "y"),
1291
- ...frame.value2 ? { valueScale2: toValueScale(frame.value2, horizontal ? "x" : "y") } : {},
1292
- percent
1293
- };
1294
- }
1295
- function layoutXy(ctx, area, visible) {
1296
- const { spec, theme, marks, measure, fs } = ctx;
1297
- const bubble = spec.type === "bubble";
1298
- const pointsOf = (s) => s.values.map((y, i) => ({ i, x: _nullishCoalesce(_optionalChain([s, 'access', _14 => _14.x, 'optionalAccess', _15 => _15[i]]), () => ( (bubble || !s.x ? i + 1 : null))), y, size: _nullishCoalesce(_optionalChain([s, 'access', _16 => _16.sizes, 'optionalAccess', _17 => _17[i]]), () => ( null)) })).filter((p) => p.x !== null && p.y !== null && Number.isFinite(p.x) && Number.isFinite(p.y));
1299
- const all = visible.map((s) => ({ s, pts: pointsOf(s) }));
1300
- let xlo = Infinity;
1301
- let xhi = -Infinity;
1302
- let ylo = Infinity;
1303
- let yhi = -Infinity;
1304
- let maxSize = 0;
1305
- for (const { s, pts } of all) {
1306
- for (const p of pts) {
1307
- xlo = Math.min(xlo, p.x);
1308
- xhi = Math.max(xhi, p.x);
1309
- ylo = Math.min(ylo, p.y);
1310
- yhi = Math.max(yhi, p.y);
1311
- if (p.size !== null && p.size > maxSize) maxSize = p.size;
1312
- }
1313
- for (const t of _nullishCoalesce(s.trendlines, () => ( []))) {
1314
- if (!pts.length) continue;
1315
- xlo = Math.min(xlo, Math.min(...pts.map((p) => p.x)) - (_nullishCoalesce(t.backward, () => ( 0))));
1316
- xhi = Math.max(xhi, Math.max(...pts.map((p) => p.x)) + (_nullishCoalesce(t.forward, () => ( 0))));
1317
- }
1318
- }
1319
- if (!Number.isFinite(xlo)) [xlo, xhi, ylo, yhi] = [0, 1, 0, 1];
1320
- const titleBand = fs * 1.3 + 6;
1321
- const yAxis = spec.yAxis;
1322
- const xAxis = spec.xAxis;
1323
- const yEst = axisScale(ylo, yhi, area.height, yAxis, ctx.options.valueDomain, true);
1324
- const yText = (t, step) => formatChartNumber(t, yAxis.format, _nullishCoalesce(yAxis.format.decimals, () => ( stepDecimals(step))));
1325
- const left = (yAxis.show ? Math.max(0, ...yEst.ticks.map((t) => measure(yText(t, yEst.step), fs))) + 8 : 2) + (yAxis.title ? titleBand : 0);
1326
- const bottom = (xAxis.show ? fs * 1.6 : 2) + (xAxis.title ? titleBand : 0);
1327
- const plot = { x: area.x + left, y: area.y + fs / 2 + 2, width: Math.max(1, area.width - left - 12), height: Math.max(1, area.height - bottom - fs / 2 - 2) };
1328
- const maxR = bubble ? Math.max(4, Math.min(plot.width, plot.height) * 0.08) : 0;
1329
- const inset = bubble ? maxR : 0;
1330
- const yScale = axisScale(ylo, yhi, plot.height, yAxis, ctx.options.valueDomain, true);
1331
- const xScale = axisScale(xlo, xhi, plot.width, xAxis, ctx.options.xDomain, true);
1332
- const xRange = [plot.x + inset, plot.x + plot.width - inset];
1333
- const yRange = [plot.y + plot.height - inset, plot.y + inset];
1334
- const xRaw = (x) => linearMap(x, [xScale.min, xScale.max], xRange);
1335
- const yRaw = (y) => linearMap(y, [yScale.min, yScale.max], yRange);
1336
- const xPx = (x) => xRaw(Math.min(xScale.max, Math.max(xScale.min, x)));
1337
- const yPx = (y) => yRaw(Math.min(yScale.max, Math.max(yScale.min, y)));
1338
- const xTarget = { kind: "axis", axis: "x" };
1339
- const yTarget = { kind: "axis", axis: "y" };
1340
- if (yAxis.gridlines) yScale.ticks.forEach((t, i) => marks.push({ kind: "line", key: `grid-y-${i}`, role: "grid", x1: plot.x, y1: yPx(t), x2: plot.x + plot.width, y2: yPx(t), stroke: theme.grid, strokeWidth: 1 }));
1341
- if (xAxis.gridlines) xScale.ticks.forEach((t, i) => marks.push({ kind: "line", key: `grid-x-${i}`, role: "grid", x1: xPx(t), y1: plot.y, x2: xPx(t), y2: plot.y + plot.height, stroke: theme.grid, strokeWidth: 1 }));
1342
- if (yAxis.show) yScale.ticks.forEach((t, i) => marks.push({ kind: "text", key: `tick-y-${i}`, role: "tick-label", x: plot.x - 8, y: yPx(t), text: yText(t, yScale.step), anchor: "end", baseline: "middle", size: fs, fill: theme.mutedText, target: yTarget }));
1343
- if (xAxis.show) {
1344
- const y0 = yScale.min <= 0 && yScale.max >= 0 ? yPx(0) : plot.y + plot.height;
1345
- marks.push({ kind: "line", key: "axis-x", role: "axis", x1: plot.x, y1: y0, x2: plot.x + plot.width, y2: y0, stroke: theme.axis, strokeWidth: 1, target: xTarget });
1346
- const texts = xScale.ticks.map((t) => formatChartNumber(t, xAxis.format, _nullishCoalesce(xAxis.format.decimals, () => ( stepDecimals(xScale.step)))));
1347
- const widest = Math.max(0, ...texts.map((t) => measure(t, fs)));
1348
- const spacing = xScale.ticks.length > 1 ? Math.abs(xPx(xScale.ticks[1]) - xPx(xScale.ticks[0])) : Infinity;
1349
- const every = Math.max(1, Math.ceil((widest + 8) / spacing));
1350
- xScale.ticks.forEach((t, i) => {
1351
- if (i % every) return;
1352
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: xPx(t), y: plot.y + plot.height + 6, text: texts[i], anchor: "middle", baseline: "top", size: fs, fill: theme.mutedText, target: xTarget });
1353
- });
1354
- }
1355
- if (xAxis.title) marks.push({ kind: "text", key: "axis-title-x", role: "axis-title", x: plot.x + plot.width / 2, y: area.y + area.height, text: xAxis.title, anchor: "middle", baseline: "bottom", size: fs + 1, weight: 500, fill: theme.text, target: xTarget });
1356
- if (yAxis.title) marks.push({ kind: "text", key: "axis-title-y", role: "axis-title", x: area.x, y: plot.y + plot.height / 2, text: yAxis.title, anchor: "middle", baseline: "top", size: fs + 1, weight: 500, fill: theme.text, rotate: -90, target: yTarget });
1357
- for (const axis of ["x", "y"]) {
1358
- if (!ctx.isSelected({ kind: "axis", axis })) continue;
1359
- ctx.outline(`axis-${axis}-selection`, axis === "y" ? { x: area.x, y: plot.y - fs / 2, width: left - 2, height: plot.height + fs } : { x: plot.x - 4, y: plot.y + plot.height + 2, width: plot.width + 8, height: area.y + area.height - plot.y - plot.height - 2 });
1360
- }
1361
- const labelMarks = [];
1362
- const trendLabels = [];
1363
- for (const { s, pts } of all) {
1364
- const si = spec.series.indexOf(s);
1365
- const color = _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, si);
1366
- const type = _chunkNEOO6QJDcjs.chartSeriesType.call(void 0, spec, s);
1367
- const selSeries = ctx.seriesSelected(s.id);
1368
- const seriesTarget = { kind: "series", seriesId: s.id };
1369
- if (type === "line" || type === "area") {
1370
- const xy = pts.map((p) => ({ x: xPx(p.x), y: yPx(p.y) }));
1371
- const thinned = xy.length > MAX_CHART_LINE_POINTS ? decimateChartPoints(xy, MAX_CHART_LINE_POINTS) : xy;
1372
- if (thinned.length < xy.length) ctx.warn("points-decimated", `"${s.name}" has ${xy.length} points; its line is drawn with ${thinned.length}.`);
1373
- const d = curvePath(thinned.map((p) => ({ c: p.x, v: p.y })), _nullishCoalesce(s.curve, () => ( spec.curve)), (p) => [p.c, p.v]);
1374
- if (d) marks.push({ kind: "path", key: `line-${s.id}`, role: "line", d, fill: "none", stroke: color, strokeWidth: selSeries ? 3.5 : 2, target: seriesTarget, selected: selSeries });
1375
- }
1376
- const marker = bubble ? "circle" : _nullishCoalesce(s.marker, () => ( (type === "scatter" || spec.points ? "circle" : "none")));
1377
- const ordered = bubble ? [...pts].sort((a, b) => (_nullishCoalesce(b.size, () => ( 0))) - (_nullishCoalesce(a.size, () => ( 0)))) : pts;
1378
- const labelsOn = (_nullishCoalesce(s.dataLabels, () => ( spec.dataLabels))) && pts.length <= MAX_CHART_DATA_LABELS;
1379
- const labelFormat = _nullishCoalesce(s.format, () => ( yAxis.format));
1380
- const cells = /* @__PURE__ */ new Set();
1381
- for (const p of ordered) {
1382
- const cx = xPx(p.x);
1383
- const cy = yPx(p.y);
1384
- if (pts.length > MAX_CHART_MARKERS) {
1385
- const cell = `${Math.round(cx / 2)},${Math.round(cy / 2)}`;
1386
- if (cells.has(cell)) continue;
1387
- cells.add(cell);
1388
- }
1389
- const target = { kind: "point", seriesId: s.id, index: p.i };
1390
- const selected = ctx.isSelected(target);
1391
- const pointColor = _chunkNEOO6QJDcjs.chartPointColor.call(void 0, spec, si, p.i);
1392
- const r = bubble ? maxSize > 0 && p.size !== null && p.size > 0 ? Math.max(2, Math.sqrt(p.size / maxSize) * maxR) : 2 : 4.5;
1393
- if (bubble) marks.push({ kind: "circle", key: `point-${s.id}-${p.i}`, role: "point", cx, cy, r, fill: pointColor, stroke: pointColor, strokeWidth: 1, opacity: 0.6, target, selected: selected || selSeries });
1394
- else marks.push(pointMark({ key: `point-${s.id}-${p.i}`, target, selected: selected || selSeries, opacity: 0.85 }, marker === "none" ? "hit" : marker, cx, cy, marker === "none" ? 6 : r, marker === "none" ? "transparent" : pointColor, marker === "none" ? void 0 : pointColor, 2));
1395
- if (selected) marks.push({ kind: "circle", key: `point-${s.id}-${p.i}-selection`, role: "selection", cx, cy, r: r + 3.5, fill: "none", stroke: theme.selection, strokeWidth: 1.5 });
1396
- if (labelsOn) labelMarks.push({ kind: "text", key: `label-${s.id}-${p.i}`, role: "data-label", x: cx, y: cy - r - 4, text: formatChartNumber(p.y, labelFormat), anchor: "middle", baseline: "bottom", size: fs - 1, fill: theme.text, target });
1397
- }
1398
- if (_optionalChain([s, 'access', _18 => _18.trendlines, 'optionalAccess', _19 => _19.length])) drawTrendlines(ctx, plot, s, color, pts.map((p) => [p.x, p.y]), (x, y) => [xRaw(x), yRaw(y)], trendLabels);
1399
- }
1400
- marks.push(...labelMarks);
1401
- drawTrendLabels(ctx, plot, trendLabels);
1402
- return {
1403
- plot,
1404
- valueScale: { axis: "y", domain: [yScale.min, yScale.max], range: yRange, ticks: yScale.ticks },
1405
- xScale: { axis: "x", domain: [xScale.min, xScale.max], range: xRange, ticks: xScale.ticks }
1406
- };
1407
- }
1408
- function trendlineLegendItems(spec, color) {
1409
- if (!chartSupportsTrendlines(spec.type, spec.stacking)) return [];
1410
- return spec.series.flatMap(
1411
- (s, si) => s.hidden ? [] : (_nullishCoalesce(s.trendlines, () => ( []))).map((t, ti) => ({ label: chartTrendlineName(t, s.name), color: _nullishCoalesce(t.color, () => ( color(si))), target: { kind: "trendline", seriesId: s.id, index: ti }, after: s.id }))
1412
- );
1413
- }
1414
72
 
1415
- // src/chart/layout-families.ts
1416
- var sliceColor = (ctx, series, i) => _optionalChain([series, 'access', _20 => _20.pointColors, 'optionalAccess', _21 => _21[i]]) || _chunkNEOO6QJDcjs.chartSliceColor.call(void 0, ctx.spec, i);
1417
- function layoutPie(ctx, area, series) {
1418
- const { spec, theme, marks, fs, selection } = ctx;
1419
- const values = spec.categories.map((_, i) => {
1420
- const v = series.values[i];
1421
- return v !== null && Number.isFinite(v) ? Math.max(0, v) : 0;
1422
- });
1423
- const total = values.reduce((a, b) => a + b, 0);
1424
- const labelsOn = _nullishCoalesce(series.dataLabels, () => ( spec.dataLabels));
1425
- const labelRoom = labelsOn ? fs * 2.2 : 4;
1426
- const outer = Math.max(4, Math.min(area.width, area.height) / 2 - labelRoom);
1427
- const inner = spec.type === "donut" ? outer * spec.innerRadius : 0;
1428
- const cx = area.x + area.width / 2;
1429
- const cy = area.y + area.height / 2;
1430
- const plot = { x: cx - outer, y: cy - outer, width: outer * 2, height: outer * 2 };
1431
- if (total <= 0) {
1432
- marks.push({ kind: "text", key: "empty", role: "empty", x: cx, y: cy, text: "No positive values", anchor: "middle", baseline: "middle", size: fs + 1, fill: theme.mutedText });
1433
- return { plot };
1434
- }
1435
- let angle = 0;
1436
- const format = _nullishCoalesce(series.format, () => ( spec.yAxis.format));
1437
- let hidden = 0;
1438
- values.forEach((v, i) => {
1439
- if (v <= 0) return;
1440
- const sweep = v / total * Math.PI * 2;
1441
- const start = angle;
1442
- const end = angle + sweep;
1443
- angle = end;
1444
- const target = { kind: "point", seriesId: series.id, index: i };
1445
- const selected = ctx.isSelected(target) || ctx.isSelected({ kind: "category", index: i });
1446
- const seriesSel = _optionalChain([selection, 'optionalAccess', _22 => _22.kind]) === "series" && selection.seriesId === series.id;
1447
- const mid = (start + end) / 2;
1448
- const off = selected ? 6 : 0;
1449
- const ox = cx + off * Math.sin(mid);
1450
- const oy = cy - off * Math.cos(mid);
1451
- marks.push({
1452
- kind: "path",
1453
- key: `slice-${i}`,
1454
- role: "slice",
1455
- d: arcPath(ox, oy, outer, inner, start, end),
1456
- fill: sliceColor(ctx, series, i),
1457
- stroke: selected || seriesSel ? theme.selection : theme.surface,
1458
- strokeWidth: selected || seriesSel ? 2 : 1,
1459
- target,
1460
- selected: selected || seriesSel
1461
- });
1462
- if (!labelsOn) return;
1463
- if (sweep <= 0.12) {
1464
- hidden++;
1465
- return;
1466
- }
1467
- const share = v / total;
1468
- const text = format.style || format.code ? formatChartNumber(v, format) : `${Math.round(share * 100)}%`;
1469
- const lr = outer + fs * 1.1;
1470
- const lx = ox + lr * Math.sin(mid);
1471
- const ly = oy - lr * Math.cos(mid);
1472
- const anchor = Math.abs(Math.sin(mid)) < 0.2 ? "middle" : Math.sin(mid) > 0 ? "start" : "end";
1473
- marks.push({ kind: "text", key: `label-slice-${i}`, role: "data-label", x: lx, y: ly, text, anchor, baseline: "middle", size: fs, fill: theme.text, target });
1474
- });
1475
- if (hidden) ctx.warn("data-labels-hidden", `${hidden} slice label${hidden === 1 ? " is" : "s are"} hidden: the slices are too thin.`);
1476
- if (spec.type === "donut" && inner > fs * 2) {
1477
- marks.push({ kind: "text", key: "donut-total", role: "data-label", x: cx, y: cy, text: formatChartNumber(total, format), anchor: "middle", baseline: "middle", size: Math.min(theme.titleSize + 4, inner / 2), weight: 600, fill: theme.text, target: { kind: "series", seriesId: series.id } });
1478
- }
1479
- return { plot };
1480
- }
1481
- function layoutRadar(ctx, area, visible) {
1482
- const { spec, theme, marks, fs, measure } = ctx;
1483
- const n = spec.categories.length;
1484
- const labelW = Math.min(area.width * 0.25, Math.max(0, ...spec.categories.map((c) => measure(c, fs))));
1485
- const radius = Math.max(8, Math.min(area.width / 2 - labelW - 8, area.height / 2 - fs * 1.6));
1486
- const cx = area.x + area.width / 2;
1487
- const cy = area.y + area.height / 2;
1488
- let lo = 0;
1489
- let hi = -Infinity;
1490
- for (const s of visible) for (const v of s.values) if (v !== null && Number.isFinite(v)) lo = Math.min(lo, v), hi = Math.max(hi, v);
1491
- if (!Number.isFinite(hi)) hi = 1;
1492
- const scale = axisScale(lo, hi, radius, spec.yAxis, ctx.options.valueDomain);
1493
- const rOf = (v) => linearMap(Math.min(scale.max, Math.max(scale.min, v)), [scale.min, scale.max], [0, radius]);
1494
- const angle = (i) => i / n * Math.PI * 2;
1495
- const at = (i, r) => [cx + r * Math.sin(angle(i)), cy - r * Math.cos(angle(i))];
1496
- const yTarget = { kind: "axis", axis: "y" };
1497
- if (spec.yAxis.gridlines)
1498
- scale.ticks.forEach((t, k) => {
1499
- const r = rOf(t);
1500
- if (r <= 0) return;
1501
- const d = Array.from({ length: n }, (_, i) => at(i, r)).map(([x, y], i) => `${i ? "L" : "M"}${r2(x)},${r2(y)}`).join("") + "Z";
1502
- marks.push({ kind: "path", key: `grid-ring-${k}`, role: "grid", d, fill: "none", stroke: theme.grid, strokeWidth: 1 });
1503
- });
1504
- for (let i = 0; i < n; i++) {
1505
- const [x, y] = at(i, radius);
1506
- marks.push({ kind: "line", key: `spoke-${i}`, role: "axis", x1: cx, y1: cy, x2: x, y2: y, stroke: theme.grid, strokeWidth: 1, target: { kind: "axis", axis: "x" } });
1507
- if (spec.xAxis.show) {
1508
- const [lx, ly] = at(i, radius + 8);
1509
- const s = Math.sin(angle(i));
1510
- const c = Math.cos(angle(i));
1511
- const target = { kind: "category", index: i };
1512
- const selected = ctx.isSelected(target);
1513
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: lx, y: ly, text: truncate(spec.categories[i], labelW, fs, measure), anchor: Math.abs(s) < 0.2 ? "middle" : s > 0 ? "start" : "end", baseline: Math.abs(c) < 0.2 ? "middle" : c > 0 ? "bottom" : "top", size: fs, fill: selected ? theme.selection : theme.mutedText, target, selected });
1514
- }
1515
- }
1516
- if (spec.yAxis.show)
1517
- scale.ticks.forEach((t, k) => {
1518
- const r = rOf(t);
1519
- marks.push({ kind: "text", key: `tick-y-${k}`, role: "tick-label", x: cx + 4, y: cy - r, text: formatChartNumber(t, spec.yAxis.format, _nullishCoalesce(spec.yAxis.format.decimals, () => ( stepDecimals(scale.step)))), anchor: "start", baseline: "bottom", size: fs - 1, fill: theme.mutedText, target: yTarget });
1520
- });
1521
- for (const s of visible) {
1522
- const si = spec.series.indexOf(s);
1523
- const color = _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, si);
1524
- const selSeries = ctx.seriesSelected(s.id);
1525
- const pts = s.values.map((v, i) => v !== null && Number.isFinite(v) ? at(i, rOf(v)) : null);
1526
- const present = pts.filter((p) => p !== null);
1527
- if (!present.length) continue;
1528
- const d = present.map(([x, y], i) => `${i ? "L" : "M"}${r2(x)},${r2(y)}`).join("") + "Z";
1529
- marks.push({ kind: "path", key: `area-${s.id}`, role: "area", d, fill: color, opacity: s.type === "line" ? 0 : 0.15, target: { kind: "series", seriesId: s.id }, selected: selSeries });
1530
- marks.push({ kind: "path", key: `line-${s.id}`, role: "line", d, fill: "none", stroke: color, strokeWidth: selSeries ? 3.5 : 2, target: { kind: "series", seriesId: s.id }, selected: selSeries });
1531
- pts.forEach((p, i) => {
1532
- if (!p) return;
1533
- const target = { kind: "point", seriesId: s.id, index: i };
1534
- const selected = ctx.isSelected(target);
1535
- marks.push({ kind: "circle", key: `point-${s.id}-${i}`, role: "point", cx: p[0], cy: p[1], r: spec.points ? 3.5 : 6, fill: spec.points ? theme.surface : "transparent", ...spec.points ? { stroke: color, strokeWidth: 2 } : {}, target, selected: selected || selSeries });
1536
- if (selected) marks.push({ kind: "circle", key: `point-${s.id}-${i}-selection`, role: "selection", cx: p[0], cy: p[1], r: 7, fill: "none", stroke: theme.selection, strokeWidth: 1.5 });
1537
- if (_nullishCoalesce(s.dataLabels, () => ( spec.dataLabels))) marks.push({ kind: "text", key: `label-${s.id}-${i}`, role: "data-label", x: p[0], y: p[1] - 6, text: formatChartNumber(s.values[i], _nullishCoalesce(s.format, () => ( spec.yAxis.format))), anchor: "middle", baseline: "bottom", size: fs - 1, fill: theme.text, target });
1538
- });
1539
- }
1540
- return { plot: { x: cx - radius, y: cy - radius, width: radius * 2, height: radius * 2 } };
1541
- }
1542
- function layoutWaterfall(ctx, area, series) {
1543
- const { spec, theme, marks, fs } = ctx;
1544
- const isTotal = (label) => /\b(sub)?total\b/i.test(label);
1545
- const steps = [];
1546
- let running = 0;
1547
- spec.categories.forEach((label, i) => {
1548
- const v = series.values[i];
1549
- if (isTotal(label)) {
1550
- steps.push({ label, index: i, from: 0, to: running, total: true });
1551
- return;
1552
- }
1553
- const delta = v !== null && Number.isFinite(v) ? v : 0;
1554
- steps.push({ label, index: i, from: running, to: running + delta, total: false });
1555
- running += delta;
1556
- });
1557
- if (spec.showTotal && !(steps.length && steps[steps.length - 1].total)) steps.push({ label: "Total", index: null, from: 0, to: running, total: true });
1558
- let lo = 0;
1559
- let hi = 0;
1560
- for (const s of steps) {
1561
- lo = Math.min(lo, s.from, s.to);
1562
- hi = Math.max(hi, s.from, s.to);
1563
- }
1564
- const horizontal = spec.orientation === "horizontal";
1565
- const frame = categoryFrame(ctx, area, {
1566
- labels: steps.map((s) => s.label),
1567
- horizontal,
1568
- primary: { lo, hi, axis: spec.yAxis, format: spec.yAxis.format, frozen: ctx.options.valueDomain, key: "y" },
1569
- labelTarget: (k) => steps[k].index !== null ? { kind: "category", index: steps[k].index } : void 0
1570
- });
1571
- const { band, catCenter, map, value } = frame;
1572
- const w = band * (1 - spec.gapWidth);
1573
- const color = _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(series));
1574
- const format = _nullishCoalesce(series.format, () => ( spec.yAxis.format));
1575
- const labelsOn = _nullishCoalesce(series.dataLabels, () => ( spec.dataLabels));
1576
- let prevEnd = null;
1577
- steps.forEach((s, k) => {
1578
- const a = value.px(s.from);
1579
- const b = value.px(s.to);
1580
- const c0 = catCenter(k) - w / 2;
1581
- const [x, y] = map({ c: c0, v: Math.min(a, b) });
1582
- const rect = horizontal ? { x: Math.min(a, b), y: c0, width: Math.max(1, Math.abs(b - a)), height: w } : { x, y, width: w, height: Math.max(1, Math.abs(b - a)) };
1583
- const fill = s.total ? color : s.to >= s.from ? theme.positive : theme.negative;
1584
- const target = s.index !== null ? { kind: "point", seriesId: series.id, index: s.index } : { kind: "series", seriesId: series.id };
1585
- const selected = ctx.isSelected(target);
1586
- marks.push({ kind: "rect", key: `bar-${series.id}-${_nullishCoalesce(s.index, () => ( "total"))}`, role: "bar", ...rect, fill, radius: Math.min(2, w / 4), target, selected });
1587
- if (selected) ctx.outline(`bar-${series.id}-${_nullishCoalesce(s.index, () => ( "total"))}-selection`, { x: rect.x - 2, y: rect.y - 2, width: rect.width + 4, height: rect.height + 4 });
1588
- if (prevEnd !== null) {
1589
- const [x1, y1] = map({ c: catCenter(k - 1) + w / 2, v: value.px(prevEnd) });
1590
- const [x2, y2] = map({ c: c0, v: value.px(prevEnd) });
1591
- marks.push({ kind: "line", key: `connector-${k}`, role: "connector", x1, y1, x2, y2, stroke: theme.axis, strokeWidth: 1, dash: "3 3" });
1592
- }
1593
- prevEnd = s.to;
1594
- if (labelsOn) {
1595
- const text = formatChartNumber(s.total ? s.to : s.to - s.from, format);
1596
- const up = s.to >= s.from;
1597
- const [lx, ly] = map({ c: catCenter(k), v: horizontal ? Math.max(a, b) + 4 : up ? Math.min(a, b) - 4 : Math.max(a, b) + 4 });
1598
- marks.push({ kind: "text", key: `label-${series.id}-${_nullishCoalesce(s.index, () => ( "total"))}`, role: "data-label", x: lx, y: ly, text, anchor: horizontal ? "start" : "middle", baseline: horizontal ? "middle" : up ? "bottom" : "top", size: fs - 1, fill: theme.text, target });
1599
- }
1600
- });
1601
- return { plot: frame.plot, valueScale: toValueScale(value, horizontal ? "x" : "y") };
1602
- }
1603
- function layoutHistogram(ctx, area, visible) {
1604
- const { spec, marks, fs, theme } = ctx;
1605
- const pooled = visible.flatMap((s) => s.values);
1606
- const bins = chartHistogram(pooled, spec.bins);
1607
- if (!bins.length) return { plot: area };
1608
- const edgeFormat = spec.xAxis.format;
1609
- const edges = (b, k2) => `${k2 === 0 ? "[" : "("}${formatChartNumber(b.from, edgeFormat)}, ${formatChartNumber(b.to, edgeFormat)}]`;
1610
- const counts = visible.map((s) => {
1611
- const c = bins.map(() => 0);
1612
- for (const v of s.values) {
1613
- if (v === null || !Number.isFinite(v)) continue;
1614
- let k2 = bins.findIndex((b) => v <= b.to);
1615
- if (k2 < 0) k2 = bins.length - 1;
1616
- c[k2]++;
1617
- }
1618
- return c;
1619
- });
1620
- const maxCount = Math.max(1, ...counts.flat());
1621
- const frame = categoryFrame(ctx, area, {
1622
- labels: bins.map(edges),
1623
- horizontal: false,
1624
- primary: { lo: 0, hi: maxCount, axis: { ...spec.yAxis, format: spec.yAxis.format.code || spec.yAxis.format.style ? spec.yAxis.format : { decimals: 0 } }, format: spec.yAxis.format.code || spec.yAxis.format.style ? spec.yAxis.format : { decimals: 0 }, frozen: null, key: "y" },
1625
- labelTarget: () => void 0
1626
- });
1627
- const { band, catCenter, value, plot } = frame;
1628
- const k = visible.length;
1629
- const gap = k > 1 ? band * spec.gapWidth * 0.5 : 0;
1630
- const w = (band - gap) / k;
1631
- visible.forEach((s, si) => {
1632
- const color = _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s));
1633
- const target = { kind: "series", seriesId: s.id };
1634
- const selected = ctx.seriesSelected(s.id);
1635
- counts[si].forEach((c, b) => {
1636
- if (!c) return;
1637
- const top = value.px(c);
1638
- const x = catCenter(b) - band / 2 + gap / 2 + si * w;
1639
- marks.push({ kind: "rect", key: `bar-${s.id}-${b}`, role: "bar", x, y: top, width: w, height: value.zero - top, fill: color, stroke: theme.surface, strokeWidth: 0.75, opacity: k > 1 ? 0.85 : void 0, target, selected });
1640
- if (_nullishCoalesce(s.dataLabels, () => ( spec.dataLabels))) marks.push({ kind: "text", key: `label-${s.id}-${b}`, role: "data-label", x: x + w / 2, y: top - 3, text: String(c), anchor: "middle", baseline: "bottom", size: fs - 1, fill: theme.text, target });
1641
- });
1642
- });
1643
- return { plot };
1644
- }
1645
- function layoutBox(ctx, area, visible) {
1646
- const { spec, marks, theme, fs } = ctx;
1647
- const stats = visible.map((s) => chartBoxStats(s.values));
1648
- let lo = Infinity;
1649
- let hi = -Infinity;
1650
- for (const st of stats) if (st) lo = Math.min(lo, st.min), hi = Math.max(hi, st.max);
1651
- if (!Number.isFinite(lo)) [lo, hi] = [0, 1];
1652
- const frame = categoryFrame(ctx, area, {
1653
- labels: visible.map((s) => s.name),
1654
- horizontal: false,
1655
- primary: { lo, hi, axis: spec.yAxis, format: spec.yAxis.format, frozen: ctx.options.valueDomain, headroom: true, key: "y" },
1656
- labelTarget: (i) => ({ kind: "series", seriesId: visible[i].id })
1657
- });
1658
- const { band, catCenter, value, plot } = frame;
1659
- const bw = Math.min(80, band * (1 - spec.gapWidth) * 0.6);
1660
- visible.forEach((s, i) => {
1661
- const st = stats[i];
1662
- if (!st) return;
1663
- const color = _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s));
1664
- const target = { kind: "series", seriesId: s.id };
1665
- const selected = ctx.seriesSelected(s.id);
1666
- const c = catCenter(i);
1667
- const y = value.px;
1668
- const line = (key, x1, y1, x2, y2, width = 1.25, stroke = color) => marks.push({ kind: "line", key, role: "whisker", x1, y1, x2, y2, stroke, strokeWidth: width, target });
1669
- line(`whisker-hi-${s.id}`, c, y(st.upperWhisker), c, y(st.q3));
1670
- line(`whisker-lo-${s.id}`, c, y(st.q1), c, y(st.lowerWhisker));
1671
- line(`cap-hi-${s.id}`, c - bw / 4, y(st.upperWhisker), c + bw / 4, y(st.upperWhisker));
1672
- line(`cap-lo-${s.id}`, c - bw / 4, y(st.lowerWhisker), c + bw / 4, y(st.lowerWhisker));
1673
- const top = y(st.q3);
1674
- const bottom = y(st.q1);
1675
- marks.push({ kind: "rect", key: `box-${s.id}`, role: "box", x: c - bw / 2, y: top, width: bw, height: Math.max(0.5, bottom - top), fill: color, opacity: 0.3, stroke: selected ? theme.selection : color, strokeWidth: selected ? 2.5 : 1.5, target, selected });
1676
- line(`median-${s.id}`, c - bw / 2, y(st.median), c + bw / 2, y(st.median), 2.5);
1677
- const my = y(st.mean);
1678
- marks.push({ kind: "path", key: `mean-${s.id}`, role: "whisker", d: `M${r2(c - 3)},${r2(my - 3)}L${r2(c + 3)},${r2(my + 3)}M${r2(c - 3)},${r2(my + 3)}L${r2(c + 3)},${r2(my - 3)}`, stroke: color, strokeWidth: 1.25, fill: "none", target });
1679
- st.outliers.slice(0, 500).forEach((o, k) => marks.push({ kind: "circle", key: `outlier-${s.id}-${k}`, role: "outlier", cx: c, cy: y(o), r: 2.5, fill: "none", stroke: color, strokeWidth: 1, target }));
1680
- if (_nullishCoalesce(s.dataLabels, () => ( spec.dataLabels))) marks.push({ kind: "text", key: `label-${s.id}-median`, role: "data-label", x: c + bw / 2 + 4, y: y(st.median), text: formatChartNumber(st.median, _nullishCoalesce(s.format, () => ( spec.yAxis.format))), anchor: "start", baseline: "middle", size: fs - 1, fill: theme.text, target });
1681
- });
1682
- return { plot, valueScale: toValueScale(value, "y") };
1683
- }
1684
- function layoutFunnel(ctx, area, series) {
1685
- const { spec, marks, theme, fs, measure } = ctx;
1686
- const n = spec.categories.length;
1687
- const labelW = spec.xAxis.show ? Math.min(area.width * 0.3, Math.max(0, ...spec.categories.map((c) => measure(c, fs)))) + 10 : 0;
1688
- const plot = { x: area.x + labelW, y: area.y, width: Math.max(1, area.width - labelW), height: area.height };
1689
- const max = Math.max(0, ...series.values.map((v) => v !== null && Number.isFinite(v) ? Math.abs(v) : 0));
1690
- const band = plot.height / Math.max(1, n);
1691
- const h = band * (1 - Math.min(0.5, spec.gapWidth * 0.5));
1692
- const format = _nullishCoalesce(series.format, () => ( spec.yAxis.format));
1693
- const labelsOn = _nullishCoalesce(series.dataLabels, () => ( true));
1694
- const cx = plot.x + plot.width / 2;
1695
- spec.categories.forEach((label, i) => {
1696
- const v = series.values[i];
1697
- const cy = plot.y + band * (i + 0.5);
1698
- const target = { kind: "point", seriesId: series.id, index: i };
1699
- const selected = ctx.isSelected(target);
1700
- if (spec.xAxis.show) {
1701
- const catTarget = { kind: "category", index: i };
1702
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: plot.x - 8, y: cy, text: truncate(label, labelW - 10, fs, measure), anchor: "end", baseline: "middle", size: fs, fill: ctx.isSelected(catTarget) ? theme.selection : theme.mutedText, target: catTarget });
1703
- }
1704
- if (v === null || !Number.isFinite(v) || max <= 0) return;
1705
- const w = Math.max(1, Math.abs(v) / max * plot.width);
1706
- const fill = sliceColor(ctx, series, i);
1707
- marks.push({ kind: "rect", key: `bar-${series.id}-${i}`, role: "bar", x: cx - w / 2, y: cy - h / 2, width: w, height: h, fill, radius: 2, target, selected });
1708
- if (selected) ctx.outline(`bar-${series.id}-${i}-selection`, { x: cx - w / 2 - 2, y: cy - h / 2 - 2, width: w + 4, height: h + 4 });
1709
- if (labelsOn) {
1710
- const text = formatChartNumber(v, format);
1711
- const fits = measure(text, fs) + 8 <= w && fs + 2 <= h;
1712
- marks.push({ kind: "text", key: `label-${series.id}-${i}`, role: "data-label", x: fits ? cx : cx + w / 2 + 4, y: cy, text, anchor: fits ? "middle" : "start", baseline: "middle", size: fs, fill: fits ? contrastingTextColor(fill) : theme.text, target });
1713
- }
1714
- });
1715
- return { plot };
1716
- }
1717
- function layoutTreemap(ctx, area, series) {
1718
- const { spec, marks, theme, fs, measure } = ctx;
1719
- const values = spec.categories.map((_, i) => {
1720
- const v = series.values[i];
1721
- return v !== null && Number.isFinite(v) ? v : 0;
1722
- });
1723
- const rects = chartSquarify(values, area);
1724
- const format = _nullishCoalesce(series.format, () => ( spec.yAxis.format));
1725
- const labelsOn = _nullishCoalesce(series.dataLabels, () => ( true));
1726
- let unlabelled = 0;
1727
- rects.forEach((r, i) => {
1728
- if (r.width <= 0 || r.height <= 0) return;
1729
- const target = { kind: "point", seriesId: series.id, index: i };
1730
- const selected = ctx.isSelected(target) || ctx.isSelected({ kind: "category", index: i });
1731
- const fill = sliceColor(ctx, series, i);
1732
- marks.push({ kind: "rect", key: `cell-${i}`, role: "cell", ...r, fill, stroke: selected ? theme.selection : theme.surface, strokeWidth: selected ? 2.5 : 1.5, target, selected });
1733
- if (!labelsOn) return;
1734
- const room = r.width - 8;
1735
- if (room < fs * 2 || r.height < fs * 1.5) {
1736
- unlabelled++;
1737
- return;
1738
- }
1739
- const color = contrastingTextColor(fill);
1740
- marks.push({ kind: "text", key: `label-cell-${i}`, role: "data-label", x: r.x + 4, y: r.y + 4, text: truncate(spec.categories[i], room, fs, measure), anchor: "start", baseline: "top", size: fs, weight: 600, fill: color, target });
1741
- if (r.height >= fs * 3) marks.push({ kind: "text", key: `label-value-${i}`, role: "data-label", x: r.x + 4, y: r.y + 6 + fs * 1.2, text: truncate(formatChartNumber(values[i], format), room, fs - 1, measure), anchor: "start", baseline: "top", size: fs - 1, fill: color, target });
1742
- });
1743
- if (unlabelled) ctx.warn("data-labels-hidden", `${unlabelled} treemap cell${unlabelled === 1 ? " is" : "s are"} too small for a label.`);
1744
- return { plot: area };
1745
- }
1746
73
 
1747
- // src/chart/layout.ts
1748
- function legendItems(spec, ctx) {
1749
- const family = _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec);
1750
- if (spec.type === "funnel") return [];
1751
- if (_chunkNEOO6QJDcjs.chartColorsByCategory.call(void 0, spec.type)) {
1752
- const first = spec.series.find((s) => !s.hidden);
1753
- return spec.categories.map((c, i) => ({
1754
- label: c,
1755
- color: _optionalChain([first, 'optionalAccess', _23 => _23.pointColors, 'optionalAccess', _24 => _24[i]]) || _chunkNEOO6QJDcjs.chartSliceColor.call(void 0, spec, i),
1756
- target: { kind: "category", index: i },
1757
- faded: false,
1758
- selected: ctx.isSelected({ kind: "category", index: i }),
1759
- shape: "square"
1760
- }));
1761
- }
1762
- if (family === "waterfall") {
1763
- const first = spec.series.find((s) => !s.hidden);
1764
- if (!first) return [];
1765
- const target = { kind: "series", seriesId: first.id };
1766
- return [
1767
- { label: "Increase", color: ctx.theme.positive, target, faded: false, selected: false, shape: "square" },
1768
- { label: "Decrease", color: ctx.theme.negative, target, faded: false, selected: false, shape: "square" },
1769
- { label: "Total", color: _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(first)), target, faded: false, selected: false, shape: "square" }
1770
- ];
1771
- }
1772
- if (family === "box") return [];
1773
- const trends = trendlineLegendItems(spec, (i) => _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, i));
1774
- const items = [];
1775
- spec.series.forEach((s, i) => {
1776
- const type = _chunkNEOO6QJDcjs.chartSeriesType.call(void 0, spec, s);
1777
- items.push({
1778
- label: s.name,
1779
- color: _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, i),
1780
- target: { kind: "series", seriesId: s.id },
1781
- faded: !!s.hidden,
1782
- selected: ctx.seriesSelected(s.id),
1783
- shape: family === "cartesian" || family === "xy" || family === "radar" ? type === "line" ? "line" : "square" : "square"
1784
- });
1785
- for (const t of trends.filter((t2) => t2.after === s.id)) items.push({ label: t.label, color: t.color, target: t.target, faded: false, selected: ctx.isSelected(t.target), shape: "dash" });
1786
- });
1787
- return items;
1788
- }
1789
- function layoutChart(spec, options) {
1790
- const width = Math.max(1, Number.isFinite(options.width) ? options.width : 1);
1791
- const height = Math.max(1, Number.isFinite(options.height) ? options.height : 1);
1792
- const theme = { ..._chunkNEOO6QJDcjs.DEFAULT_CHART_THEME, ...options.theme };
1793
- const selection = _nullishCoalesce(options.selection, () => ( null));
1794
- const marks = [];
1795
- const warnings = [];
1796
- const ctx = {
1797
- spec,
1798
- options,
1799
- theme,
1800
- measure: _nullishCoalesce(options.measureText, () => ( estimateChartTextWidth)),
1801
- fs: theme.fontSize,
1802
- width,
1803
- height,
1804
- marks,
1805
- warnings,
1806
- selection,
1807
- isSelected: (target) => sameChartSelection(selection, target),
1808
- seriesSelected: (id) => _optionalChain([selection, 'optionalAccess', _25 => _25.kind]) === "series" && selection.seriesId === id,
1809
- outline: (key, box) => marks.push({ kind: "rect", key, role: "selection", ...box, fill: "none", stroke: theme.selection, strokeWidth: 1, radius: 3 }),
1810
- warn: (code, message) => {
1811
- if (!warnings.some((w) => w.code === code && w.message === message)) warnings.push({ code, message });
1812
- }
1813
- };
1814
- const pad = 12;
1815
- const fs = theme.fontSize;
1816
- marks.push({ kind: "rect", key: "background", role: "background", x: 0, y: 0, width, height, fill: theme.background, target: { kind: "chart" } });
1817
- let top = pad;
1818
- const titleMark = (kind, label, size, weight, fill) => {
1819
- const target = { kind };
1820
- const selected = ctx.isSelected(target);
1821
- marks.push({ kind: "text", key: kind, role: kind, x: width / 2, y: top, text: label, anchor: "middle", baseline: "top", size, weight, fill, target, selected });
1822
- if (selected) {
1823
- const w = ctx.measure(label, size, weight);
1824
- ctx.outline(`${kind}-selection`, { x: width / 2 - w / 2 - 4, y: top - 3, width: w + 8, height: size * 1.25 + 6 });
1825
- }
1826
- top += size * 1.35;
1827
- };
1828
- if (spec.title) titleMark("title", spec.title, theme.titleSize, 600, theme.text);
1829
- if (spec.subtitle) titleMark("subtitle", spec.subtitle, fs + 1, 400, theme.mutedText);
1830
- if (spec.title || spec.subtitle) top += 6;
1831
- const family = _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec);
1832
- const visible = spec.series.filter((s) => !s.hidden);
1833
- const items = legendItems(spec, ctx);
1834
- let area = { x: pad, y: top, width: width - pad * 2, height: height - top - pad };
1835
- const seriesLegend = family === "cartesian" || family === "xy" || family === "radar" || family === "histogram";
1836
- const hasTrend = items.some((i) => i.shape === "dash");
1837
- const showLegend = spec.legend.show && items.length > 0 && (!seriesLegend || spec.series.length > 1 || spec.series.some((s) => s.hidden) || hasTrend);
1838
- if (showLegend) area = layoutLegend(items, spec.legend.position, area, ctx, ctx.isSelected({ kind: "legend" }));
1839
- const finish = (result) => {
1840
- if (options.readout) addReadout(ctx, options.readout, result.plot);
1841
- const kept = finalizeMarks(marks, width, height);
1842
- if (kept.length < marks.length) ctx.warn("values-skipped", `${marks.length - kept.length} mark${marks.length - kept.length === 1 ? " was" : "s were"} left out: their values are not finite numbers.`);
1843
- return {
1844
- width,
1845
- height,
1846
- plot: result.plot,
1847
- marks: kept,
1848
- percent: _nullishCoalesce(result.percent, () => ( false)),
1849
- theme,
1850
- warnings,
1851
- ...result.valueScale ? { valueScale: result.valueScale } : {},
1852
- ...result.valueScale2 ? { valueScale2: result.valueScale2 } : {},
1853
- ...result.xScale ? { xScale: result.xScale } : {}
1854
- };
1855
- };
1856
- const empty = (message) => {
1857
- marks.push({ kind: "text", key: "empty", role: "empty", x: area.x + area.width / 2, y: area.y + area.height / 2, text: message, anchor: "middle", baseline: "middle", size: fs + 1, fill: theme.mutedText });
1858
- return finish({ plot: { x: area.x, y: area.y, width: 0, height: 0 } });
1859
- };
1860
- const hasData = visible.some((s) => s.values.some((v) => v !== null && Number.isFinite(v)));
1861
- const needsCategories = family !== "histogram" && family !== "box" && family !== "xy";
1862
- if (needsCategories && !spec.categories.length || !visible.length || !hasData) return empty(_nullishCoalesce(options.emptyMessage, () => ( "No data")));
1863
- switch (family) {
1864
- case "pie":
1865
- return finish(layoutPie(ctx, area, visible[0]));
1866
- case "radar":
1867
- if (spec.categories.length < 3) {
1868
- ctx.warn("type-fallback", "A radar chart needs at least 3 categories; it is drawn as a line chart until then.");
1869
- return finish(layoutCartesian(ctx, area, visible));
1870
- }
1871
- return finish(layoutRadar(ctx, area, visible));
1872
- case "waterfall":
1873
- return finish(layoutWaterfall(ctx, area, visible[0]));
1874
- case "histogram":
1875
- return finish(layoutHistogram(ctx, area, visible));
1876
- case "box":
1877
- return finish(layoutBox(ctx, area, visible));
1878
- case "funnel":
1879
- return finish(layoutFunnel(ctx, area, visible[0]));
1880
- case "treemap":
1881
- return finish(layoutTreemap(ctx, area, visible[0]));
1882
- case "xy":
1883
- return finish(layoutXy(ctx, area, visible));
1884
- default:
1885
- return finish(layoutCartesian(ctx, area, visible));
1886
- }
1887
- }
1888
- function layoutLegend(items, position, area, ctx, legendSelected) {
1889
- const { theme, measure, marks } = ctx;
1890
- const fs = theme.fontSize;
1891
- const swatch = 10;
1892
- const rowH = fs * 1.7;
1893
- const itemW = (item) => swatch + 6 + measure(item.label, fs) + 14;
1894
- const placed = [];
1895
- let box;
1896
- let rest;
1897
- if (position === "left" || position === "right") {
1898
- const w = Math.min(area.width * 0.35, Math.max(...items.map(itemW)));
1899
- const fit = Math.max(1, Math.floor((area.height + 0.5) / rowH));
1900
- const shown = items.slice(0, fit);
1901
- const h = Math.min(shown.length * rowH, area.height);
1902
- const x = position === "left" ? area.x : area.x + area.width - w;
1903
- const y = area.y + (area.height - h) / 2;
1904
- shown.forEach((item, i) => placed.push({ item, x, y: y + i * rowH + rowH / 2 }));
1905
- if (shown.length < items.length) ctx.warn("legend-truncated", `The legend shows ${shown.length} of ${items.length} entries; the chart is too short for the rest.`);
1906
- box = { x, y, width: w, height: h };
1907
- rest = position === "left" ? { ...area, x: area.x + w + 8, width: area.width - w - 8 } : { ...area, width: area.width - w - 8 };
1908
- } else {
1909
- const rows = [[]];
1910
- let used = 0;
1911
- for (const item of items) {
1912
- const w = itemW(item);
1913
- if (used + w > area.width && rows[rows.length - 1].length) {
1914
- rows.push([]);
1915
- used = 0;
1916
- }
1917
- rows[rows.length - 1].push(item);
1918
- used += w;
1919
- }
1920
- const maxRows = Math.max(1, Math.floor(ctx.height * 0.3 / rowH));
1921
- const shown = rows.slice(0, maxRows);
1922
- const hiddenCount = rows.slice(maxRows).reduce((t, r) => t + r.length, 0);
1923
- if (hiddenCount) ctx.warn("legend-truncated", `The legend shows ${items.length - hiddenCount} of ${items.length} entries; the rest do not fit.`);
1924
- const h = shown.length * rowH;
1925
- const y0 = position === "top" ? area.y : area.y + area.height - h;
1926
- shown.forEach((row, r) => {
1927
- const total = row.reduce((t, item) => t + itemW(item), 0) - 14;
1928
- let x = area.x + (area.width - total) / 2;
1929
- for (const item of row) {
1930
- placed.push({ item, x, y: y0 + r * rowH + rowH / 2 });
1931
- x += itemW(item);
1932
- }
1933
- });
1934
- box = { x: area.x, y: y0, width: area.width, height: h };
1935
- rest = position === "top" ? { ...area, y: area.y + h + 6, height: area.height - h - 6 } : { ...area, height: area.height - h - 6 };
1936
- }
1937
- placed.forEach(({ item, x, y }, i) => {
1938
- const opacity = item.faded ? 0.4 : void 0;
1939
- if (item.shape === "line" || item.shape === "dash")
1940
- marks.push({ kind: "line", key: `legend-swatch-${i}`, role: "legend-swatch", x1: x, y1: y, x2: x + swatch, y2: y, stroke: item.color, strokeWidth: item.shape === "dash" ? 1.5 : 2.5, ...item.shape === "dash" ? { dash: "3 2" } : {}, opacity, target: item.target, selected: item.selected });
1941
- else marks.push({ kind: "rect", key: `legend-swatch-${i}`, role: "legend-swatch", x, y: y - swatch / 2, width: swatch, height: swatch, radius: 2, fill: item.color, opacity, target: item.target, selected: item.selected });
1942
- marks.push({
1943
- kind: "text",
1944
- key: `legend-label-${i}`,
1945
- role: "legend-label",
1946
- x: x + swatch + 6,
1947
- y,
1948
- text: item.label,
1949
- anchor: "start",
1950
- baseline: "middle",
1951
- size: fs,
1952
- fill: item.selected ? theme.selection : theme.text,
1953
- weight: item.selected ? 600 : void 0,
1954
- opacity,
1955
- target: item.target,
1956
- selected: item.selected
1957
- });
1958
- });
1959
- if (legendSelected) marks.push({ kind: "rect", key: "legend-selection", role: "selection", x: box.x - 4, y: box.y - 2, width: box.width + 8, height: box.height + 4, fill: "none", stroke: theme.selection, strokeWidth: 1, radius: 3 });
1960
- return rest;
1961
- }
1962
- function addReadout(ctx, readout, plot) {
1963
- const { spec, marks, theme, fs, measure } = ctx;
1964
- const series = spec.series.find((s) => s.id === readout.seriesId);
1965
- const value = _optionalChain([series, 'optionalAccess', _26 => _26.values, 'access', _27 => _27[readout.index]]);
1966
- if (!series || value === null || value === void 0) return;
1967
- const mark = marks.find((m) => (m.role === "point" || m.role === "bar") && _optionalChain([m, 'access', _28 => _28.target, 'optionalAccess', _29 => _29.kind]) === "point" && m.target.seriesId === readout.seriesId && m.target.index === readout.index);
1968
- if (!mark) return;
1969
- let ax;
1970
- let ay;
1971
- if (mark.kind === "rect") {
1972
- ax = mark.x + mark.width / 2;
1973
- ay = mark.y;
1974
- } else if (mark.kind === "circle") {
1975
- ax = mark.cx;
1976
- ay = mark.cy - mark.r;
1977
- } else return;
1978
- const axis = series.axis === "secondary" ? spec.yAxis2 : spec.yAxis;
1979
- const x = _optionalChain([series, 'access', _30 => _30.x, 'optionalAccess', _31 => _31[readout.index]]);
1980
- const text = x !== null && x !== void 0 && _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec) === "xy" ? `${formatChartNumber(x, spec.xAxis.format)}, ${formatChartNumber(value, axis.format)}` : `${_nullishCoalesce(spec.categories[readout.index], () => ( ""))}: ${formatChartNumber(value, _nullishCoalesce(series.format, () => ( axis.format)))}`;
1981
- const w = measure(text, fs, 600) + 10;
1982
- const h = fs + 8;
1983
- const bx = Math.max(plot.x, Math.min(plot.x + plot.width - w, ax - w / 2));
1984
- const by = Math.max(plot.y, Math.min(plot.y + plot.height - h, ay - h - 6));
1985
- marks.push({ kind: "rect", key: "drag-readout-box", role: "drag-readout", x: bx, y: by, width: w, height: h, fill: theme.text, radius: 3, opacity: 0.9 });
1986
- marks.push({ kind: "text", key: "drag-readout", role: "drag-readout", x: bx + w / 2, y: by + h / 2, text, anchor: "middle", baseline: "middle", size: fs, weight: 600, fill: theme.surface });
1987
- }
1988
- var finite = (...n) => n.every((v) => v === void 0 || Number.isFinite(v));
1989
- function finalizeMarks(marks, width, height) {
1990
- const lim = (v, size) => Math.max(-size * 4, Math.min(size * 5, v));
1991
- const out = [];
1992
- for (const m of marks) {
1993
- switch (m.kind) {
1994
- case "rect":
1995
- if (!finite(m.x, m.y, m.width, m.height)) continue;
1996
- out.push({ ...m, x: lim(m.x, width), y: lim(m.y, height), width: Math.max(0, Math.min(m.width, width * 9)), height: Math.max(0, Math.min(m.height, height * 9)) });
1997
- break;
1998
- case "circle":
1999
- if (!finite(m.cx, m.cy, m.r)) continue;
2000
- out.push({ ...m, cx: lim(m.cx, width), cy: lim(m.cy, height) });
2001
- break;
2002
- case "line":
2003
- if (!finite(m.x1, m.y1, m.x2, m.y2)) continue;
2004
- out.push({ ...m, x1: lim(m.x1, width), y1: lim(m.y1, height), x2: lim(m.x2, width), y2: lim(m.y2, height) });
2005
- break;
2006
- case "text":
2007
- if (!finite(m.x, m.y, m.size)) continue;
2008
- out.push(m);
2009
- break;
2010
- case "path":
2011
- if (/NaN|Infinity/.test(m.d)) continue;
2012
- out.push(m);
2013
- break;
2014
- }
2015
- }
2016
- return out;
2017
- }
2018
- function chartValueAtPoint(scene, point, secondary = false) {
2019
- const scale = secondary ? _nullishCoalesce(scene.valueScale2, () => ( scene.valueScale)) : scene.valueScale;
2020
- if (!scale || scene.percent) return void 0;
2021
- const px = scale.axis === "y" ? point.y : point.x;
2022
- return linearMap(px, scale.range, scale.domain);
2023
- }
2024
- function chartXAtPoint(scene, point) {
2025
- const scale = scene.xScale;
2026
- if (!scale) return void 0;
2027
- return linearMap(point.x, scale.range, scale.domain);
2028
- }
2029
- function snapChartValue(scene, value, step, ticks = _nullishCoalesce(_optionalChain([scene, 'access', _32 => _32.valueScale, 'optionalAccess', _33 => _33.ticks]), () => ( []))) {
2030
- const unit = _nullishCoalesce(step, () => ( (ticks.length > 1 ? (ticks[1] - ticks[0]) / 10 : 1)));
2031
- if (!(unit > 0)) return value;
2032
- const snapped = Math.round(value / unit) * unit;
2033
- return Number(snapped.toPrecision(12));
2034
- }
74
+ var _chunkGTZXF4BIcjs = require('../chunk-GTZXF4BI.cjs');
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
2035
96
 
2036
- // src/chart/summary.ts
2037
- function summarizeChart(spec, size = { width: 640, height: 400 }, scene = layoutChart(spec, { ...size, selection: null })) {
2038
- const visible = spec.series.filter((s) => !s.hidden);
2039
- const series = visible.map((s) => summarizeChartSeries(s, spec.categories));
2040
- const colors = _chunkNEOO6QJDcjs.chartColorsByCategory.call(void 0, spec.type) ? spec.categories.map((_, i) => _optionalChain([visible, 'access', _34 => _34[0], 'optionalAccess', _35 => _35.pointColors, 'optionalAccess', _36 => _36[i]]) || _chunkNEOO6QJDcjs.chartSliceColor.call(void 0, spec, i)) : visible.map((s) => _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s)));
2041
- const check2 = _chunkNEOO6QJDcjs.checkChartColors.call(void 0, colors, { surface: scene.theme.surface.startsWith("var(") ? "#ffffff" : scene.theme.surface });
2042
- const axis = (s) => s ? { min: s.domain[0], max: s.domain[1], ticks: [...s.ticks] } : void 0;
2043
- return {
2044
- type: spec.type,
2045
- title: spec.title,
2046
- categories: spec.categories.length,
2047
- series,
2048
- ...scene.valueScale ? { valueAxis: axis(scene.valueScale) } : {},
2049
- ...scene.valueScale2 ? { secondaryAxis: axis(scene.valueScale2) } : {},
2050
- ...scene.xScale ? { xAxis: axis(scene.xScale) } : {},
2051
- warnings: scene.warnings,
2052
- colors: { ok: check2.ok, issues: check2.issues },
2053
- description: describeChart(spec, series)
2054
- };
2055
- }
2056
- function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((s) => summarizeChartSeries(s, spec.categories))) {
2057
- const kind = _chunkNEOO6QJDcjs.CHART_TYPE_LABELS[spec.type].toLowerCase();
2058
- const parts = [];
2059
- const family = _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec);
2060
- const format = spec.yAxis.format;
2061
- const fmt = (v) => v === null ? "blank" : formatChartNumber(v, format);
2062
- const head = spec.title ? `${spec.title}: a ${kind} chart` : `A ${kind} chart`;
2063
- if (!series.length || series.every((s) => s.count === 0)) return `${head} with no data.`;
2064
- if (family === "pie" || family === "funnel" || family === "treemap") {
2065
- const s = series[0];
2066
- const total = _nullishCoalesce(s.sum, () => ( 0));
2067
- const share = (v) => total && v !== null ? ` (${Math.round(v / total * 100)}%)` : "";
2068
- parts.push(`${head} of ${s.name} across ${spec.categories.length} categories, totalling ${fmt(s.sum)}.`);
2069
- parts.push(`The largest is ${s.maxAt} at ${fmt(s.max)}${share(s.max)}; the smallest is ${s.minAt} at ${fmt(s.min)}${share(s.min)}.`);
2070
- return parts.join(" ");
2071
- }
2072
- if (family === "waterfall") {
2073
- const s = spec.series.find((x) => !x.hidden);
2074
- const steps = s.values.filter((v, i) => v !== null && Number.isFinite(v) && !/\b(sub)?total\b/i.test(_nullishCoalesce(spec.categories[i], () => ( ""))));
2075
- const total = steps.reduce((t, v) => t + v, 0);
2076
- const up = steps.filter((v) => v > 0).length;
2077
- const down = steps.filter((v) => v < 0).length;
2078
- return `${head} of ${s.name}: ${up} increase${up === 1 ? "" : "s"} and ${down} decrease${down === 1 ? "" : "s"} over ${spec.categories.length} steps, ending at a total of ${fmt(total)}.`;
2079
- }
2080
- if (family === "histogram" || family === "box") {
2081
- parts.push(`${head} of ${series.map((s) => s.name).join(", ")}.`);
2082
- for (const s of series) parts.push(`${s.name}: ${s.count} values from ${fmt(s.min)} to ${fmt(s.max)}, mean ${fmt(s.mean)}.`);
2083
- return parts.join(" ");
2084
- }
2085
- const what = family === "xy" ? `${series.length} series of points` : `${series.length} series over ${spec.categories.length} categories${spec.categories.length ? ` (${spec.categories[0]} to ${spec.categories[spec.categories.length - 1]})` : ""}`;
2086
- parts.push(`${head} showing ${what}.`);
2087
- for (const s of series.slice(0, 8)) {
2088
- if (!s.count) {
2089
- parts.push(`${s.name} has no values.`);
2090
- continue;
2091
- }
2092
- const pct = s.change !== null ? Math.round(Math.abs(s.change) * 100) : 0;
2093
- const trend = s.trend && s.trend !== "flat" ? `, ${s.trend}${pct ? `, ${s.change > 0 ? "up" : "down"} ${pct}% from first to last` : ""}` : s.trend === "flat" ? ", roughly flat" : "";
2094
- parts.push(`${s.name} ranges from ${fmt(s.min)} (${s.minAt}) to ${fmt(s.max)} (${s.maxAt})${trend}.`);
2095
- }
2096
- if (series.length > 8) parts.push(`${series.length - 8} more series are not described.`);
2097
- return parts.join(" ");
2098
- }
2099
97
 
2100
- // src/chart/svg.ts
2101
- function chartTextBaseline(baseline) {
2102
- return baseline === "top" ? "hanging" : baseline === "middle" ? "central" : "text-after-edge";
2103
- }
2104
- function chartTextTransform(mark) {
2105
- return mark.rotate ? `rotate(${mark.rotate} ${mark.x} ${mark.y})` : void 0;
2106
- }
2107
- var escape = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2108
- function attrs(values) {
2109
- return Object.entries(values).filter(([, v]) => v !== void 0 && v !== "").map(([k, v]) => ` ${k}="${escape(String(v))}"`).join("");
2110
- }
2111
- function markToSvg(mark, fontFamily) {
2112
- const common = { opacity: mark.opacity, "data-role": mark.role };
2113
- switch (mark.kind) {
2114
- case "rect":
2115
- return `<rect${attrs({ x: mark.x, y: mark.y, width: mark.width, height: mark.height, rx: mark.radius, fill: mark.fill, stroke: mark.stroke, "stroke-width": mark.strokeWidth, ...common })}/>`;
2116
- case "path":
2117
- return `<path${attrs({ d: mark.d, fill: _nullishCoalesce(mark.fill, () => ( "none")), stroke: mark.stroke, "stroke-width": mark.strokeWidth, "stroke-dasharray": mark.dash, "stroke-linejoin": "round", "stroke-linecap": "round", ...common })}/>`;
2118
- case "circle":
2119
- return `<circle${attrs({ cx: mark.cx, cy: mark.cy, r: mark.r, fill: mark.fill, stroke: mark.stroke, "stroke-width": mark.strokeWidth, ...common })}/>`;
2120
- case "line":
2121
- return `<line${attrs({ x1: mark.x1, y1: mark.y1, x2: mark.x2, y2: mark.y2, stroke: mark.stroke, "stroke-width": mark.strokeWidth, "stroke-dasharray": mark.dash, ...common })}/>`;
2122
- case "text":
2123
- return `<text${attrs({
2124
- x: mark.x,
2125
- y: mark.y,
2126
- "text-anchor": mark.anchor,
2127
- "dominant-baseline": chartTextBaseline(mark.baseline),
2128
- "font-size": mark.size,
2129
- "font-weight": mark.weight,
2130
- "font-family": fontFamily,
2131
- fill: mark.fill,
2132
- transform: chartTextTransform(mark),
2133
- ...common
2134
- })}>${escape(mark.text)}</text>`;
2135
- }
2136
- }
2137
- function chartSceneToSvg(scene, options = {}) {
2138
- const hide = _nullishCoalesce(options.hideSelection, () => ( true));
2139
- const font = scene.theme.fontFamily;
2140
- const body = scene.marks.filter((m) => !(hide && m.role === "selection")).map((m) => markToSvg(m, font)).join("");
2141
- const label = options.ariaLabel;
2142
- const desc = options.description;
2143
- const labelled = [label ? "chart-title" : "", desc ? "chart-desc" : ""].filter(Boolean).join(" ");
2144
- const head = `${label ? `<title id="chart-title">${escape(label)}</title>` : ""}${desc ? `<desc id="chart-desc">${escape(desc)}</desc>` : ""}`;
2145
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${scene.width}" height="${scene.height}" viewBox="0 0 ${scene.width} ${scene.height}" role="img"${label ? ` aria-label="${escape(label)}"` : ""}${labelled ? ` aria-labelledby="${labelled}"` : ""}>${head}${body}</svg>`;
2146
- }
2147
- function chartToSvg(spec, options) {
2148
- const scene = layoutChart(spec, { ...options, selection: null });
2149
- return chartSceneToSvg(scene, { ...options, ariaLabel: _nullishCoalesce(options.ariaLabel, () => ( (spec.title || void 0))), description: _nullishCoalesce(options.description, () => ( describeChart(spec))) });
2150
- }
2151
98
 
2152
- // src/chart/sparkline.ts
2153
- var MAX_POINTS = 1e5;
2154
- function layoutSparkline(values, options) {
2155
- const kind = _nullishCoalesce(options.kind, () => ( "line"));
2156
- const w = Number.isFinite(options.width) ? Math.max(1, options.width) : 1;
2157
- const h = Number.isFinite(options.height) ? Math.max(1, options.height) : 1;
2158
- const color = _nullishCoalesce(options.color, () => ( "#4269d0"));
2159
- const negative = _nullishCoalesce(options.negativeColor, () => ( "#e5484d"));
2160
- const theme = { ..._chunkNEOO6QJDcjs.DEFAULT_CHART_THEME, background: "transparent" };
2161
- const marks = [];
2162
- const scene = { width: w, height: h, plot: { x: 0, y: 0, width: w, height: h }, marks, percent: false, theme, warnings: [] };
2163
- const vals = values.slice(0, MAX_POINTS).map((v) => v !== null && Number.isFinite(v) ? Math.max(-1e300, Math.min(1e300, v)) : null);
2164
- const n = vals.length;
2165
- if (!n) return scene;
2166
- const pad = Math.max(0.5, Math.min(2, h * 0.1));
2167
- const x0 = pad;
2168
- const y0 = pad;
2169
- const iw = Math.max(0.5, w - 2 * pad);
2170
- const ih = Math.max(0.5, h - 2 * pad);
2171
- let lo = Infinity;
2172
- let hi = -Infinity;
2173
- for (const v of vals) if (v !== null) lo = Math.min(lo, v), hi = Math.max(hi, v);
2174
- if (!Number.isFinite(lo)) return scene;
2175
- if (options.min !== void 0 && Number.isFinite(options.min)) lo = options.min;
2176
- if (options.max !== void 0 && Number.isFinite(options.max)) hi = options.max;
2177
- let hiAt = -1;
2178
- let loAt = -1;
2179
- vals.forEach((v, i) => {
2180
- if (v === null) return;
2181
- if (hiAt < 0 || v > vals[hiAt]) hiAt = i;
2182
- if (loAt < 0 || v < vals[loAt]) loAt = i;
2183
- });
2184
- if (kind === "line") {
2185
- const span2 = hi - lo;
2186
- const fy2 = (v) => y0 + ih - (span2 > 0 ? (v - lo) / span2 : 0.5) * ih;
2187
- const fx = (j) => n > 1 ? x0 + j / (n - 1) * iw : x0 + iw / 2;
2188
- let d = "";
2189
- let run = [];
2190
- const flush = () => {
2191
- if (run.length >= 2) {
2192
- const pts = run.length > 4e3 ? run.filter((_, i) => i % (Math.floor(run.length / 2e3) + 1) === 0) : run;
2193
- d += pts.map(([x, y], i) => `${i ? "L" : "M"}${r2(x)},${r2(y)}`).join("");
2194
- }
2195
- run = [];
2196
- };
2197
- vals.forEach((v, j) => v === null ? flush() : run.push([fx(j), fy2(v)]));
2198
- flush();
2199
- if (d) marks.push({ kind: "path", key: "sparkline", role: "line", d, fill: "none", stroke: color, strokeWidth: 1.25 });
2200
- const r = Math.max(1, Math.min(3, h * 0.08));
2201
- if (options.markers || n === 1) {
2202
- const step = Math.max(1, Math.floor(n / 500));
2203
- vals.forEach((v, j) => {
2204
- if (v !== null && j % step === 0) marks.push({ kind: "circle", key: `point-${j}`, role: "point", cx: fx(j), cy: fy2(v), r, fill: color });
2205
- });
2206
- }
2207
- if (options.highLow && n > 1) {
2208
- if (hiAt >= 0) marks.push({ kind: "circle", key: "high", role: "point", cx: fx(hiAt), cy: fy2(vals[hiAt]), r: r + 0.5, fill: color });
2209
- if (loAt >= 0 && loAt !== hiAt) marks.push({ kind: "circle", key: "low", role: "point", cx: fx(loAt), cy: fy2(vals[loAt]), r: r + 0.5, fill: negative });
2210
- }
2211
- return scene;
2212
- }
2213
- const slot = iw / n;
2214
- const bw = Math.max(0.25, slot * 0.8);
2215
- const win = kind === "win-loss";
2216
- const lo0 = win ? -1 : Math.min(lo, 0);
2217
- const hi0 = win ? 1 : Math.max(hi, 0);
2218
- const span = hi0 - lo0;
2219
- const fy = (v) => span > 0 ? y0 + ih - (v - lo0) / span * ih : y0 + ih;
2220
- const base = fy(0);
2221
- vals.forEach((raw, j) => {
2222
- if (raw === null) return;
2223
- const v = win ? Math.sign(raw) : raw;
2224
- if (win && v === 0) return;
2225
- const top = fy(v);
2226
- const highlight = options.highLow && !win && (j === hiAt || j === loAt);
2227
- marks.push({ kind: "rect", key: `bar-${j}`, role: "bar", x: x0 + j * slot + (slot - bw) / 2, y: Math.min(top, base), width: bw, height: Math.max(0.5, Math.abs(top - base)), fill: v < 0 ? negative : color, opacity: options.highLow && !win && !highlight ? 0.6 : void 0 });
2228
- });
2229
- return scene;
2230
- }
2231
- function sparklineToSvg(values, options) {
2232
- return chartSceneToSvg(layoutSparkline(values, options), { ariaLabel: options.ariaLabel });
2233
- }
2234
99
 
2235
- // src/chart/presets.ts
2236
- var CHART_LAYOUT_PRESETS = [
2237
- { id: "standard", label: "Standard", description: "Legend at the bottom, value grid lines, no data labels.", patch: { legend: { show: true, position: "bottom" }, dataLabels: false, xAxis: { gridlines: false, show: true }, yAxis: { gridlines: true, show: true } } },
2238
- { id: "minimal", label: "Minimal", description: "No legend, grid lines or axis titles; the data speaks.", patch: { legend: { show: false }, dataLabels: false, xAxis: { gridlines: false, title: "" }, yAxis: { gridlines: false, title: "" } } },
2239
- { id: "labelled", label: "Labelled", description: "Values written on the marks, no value axis or grid lines.", patch: { dataLabels: true, labelPosition: "auto", yAxis: { show: false, gridlines: false }, xAxis: { gridlines: false } } },
2240
- { id: "legend-right", label: "Legend on the right", description: "Legend beside the plot, value grid lines.", patch: { legend: { show: true, position: "right" }, yAxis: { gridlines: true } } },
2241
- { id: "presentation", label: "Presentation", description: "Legend on top, data labels, light grid.", patch: { legend: { show: true, position: "top" }, dataLabels: true, yAxis: { gridlines: true }, xAxis: { gridlines: false } } },
2242
- { id: "analysis", label: "Analysis", description: "Grid lines on both axes, point markers, legend at the bottom.", patch: { legend: { show: true, position: "bottom" }, points: true, dataLabels: false, xAxis: { gridlines: true }, yAxis: { gridlines: true } } }
2243
- ];
2244
- function monochromeChartPalette(base, count = 6) {
2245
- const steps = count <= 1 ? [0] : Array.from({ length: count }, (_, i) => -0.45 + 1.05 * i / (count - 1));
2246
- return steps.map((t) => _chunkNEOO6QJDcjs.shadeChartColor.call(void 0, base, t));
2247
- }
2248
- var CHART_COLOR_SCHEMES = [
2249
- { id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette: _chunkNEOO6QJDcjs.DEFAULT_CHART_PALETTE },
2250
- { id: "okabe-ito", label: "Okabe\u2013Ito", description: "Eight colours chosen to stay distinct with colour-blindness.", palette: ["#e69f00", "#56b4e9", "#009e73", "#f0e442", "#0072b2", "#d55e00", "#cc79a7", "#000000"] },
2251
- { id: "office", label: "Office", description: "The six accent colours of the default Office theme.", palette: ["#4472c4", "#ed7d31", "#a5a5a5", "#ffc000", "#5b9bd5", "#70ad47"] },
2252
- { id: "warm", label: "Warm", description: "Reds, oranges and yellows.", palette: ["#b2182b", "#d6604d", "#f4a582", "#e08214", "#fdb863", "#8c510a"] },
2253
- { id: "cool", label: "Cool", description: "Blues, teals and purples.", palette: ["#2166ac", "#4393c3", "#35978f", "#80cdc1", "#762a83", "#9970ab"] },
2254
- { id: "monochrome-blue", label: "Monochrome blue", description: "Shades of one blue.", palette: monochromeChartPalette("#4269d0") },
2255
- { id: "monochrome-green", label: "Monochrome green", description: "Shades of one green.", palette: monochromeChartPalette("#3ca951") },
2256
- { id: "monochrome-orange", label: "Monochrome orange", description: "Shades of one orange.", palette: monochromeChartPalette("#e8710a") },
2257
- { id: "monochrome-gray", label: "Monochrome grey", description: "Shades of grey.", palette: monochromeChartPalette("#6b7280") }
2258
- ];
2259
- function chartPresetPatch(options) {
2260
- const patch = {};
2261
- if (options.layout !== void 0) {
2262
- const preset = CHART_LAYOUT_PRESETS.find((p) => p.id === options.layout);
2263
- if (!preset) return { ok: false, message: `There is no layout "${options.layout}"; expected one of ${CHART_LAYOUT_PRESETS.map((p) => `"${p.id}"`).join(", ")}.` };
2264
- Object.assign(patch, preset.patch);
2265
- }
2266
- if (options.colors !== void 0) {
2267
- const scheme = CHART_COLOR_SCHEMES.find((p) => p.id === options.colors);
2268
- if (!scheme) return { ok: false, message: `There is no colour scheme "${options.colors}"; expected one of ${CHART_COLOR_SCHEMES.map((p) => `"${p.id}"`).join(", ")}.` };
2269
- patch.palette = [...scheme.palette];
2270
- }
2271
- if (options.layout === void 0 && options.colors === void 0) return { ok: false, message: "Name a layout, a colour scheme or both." };
2272
- return { ok: true, patch };
2273
- }
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+ var _chunkJOX6MJW4cjs = require('../chunk-JOX6MJW4.cjs');
125
+ require('../chunk-XP5IUZUO.cjs');
126
+
127
+
128
+ var _chunkTNNJXF46cjs = require('../chunk-TNNJXF46.cjs');
129
+ require('../chunk-QKLRAA4T.cjs');
2274
130
 
2275
131
  // src/chart/recommend.ts
2276
132
  var blank = (c) => c === null || c === void 0 || String(c).trim() === "";
2277
- var isText = (c) => blank(c) || _chunkNEOO6QJDcjs.parseChartValue.call(void 0, c) === void 0;
133
+ var isText = (c) => blank(c) || _chunkJOX6MJW4cjs.parseChartValue.call(void 0, c) === void 0;
2278
134
  function analyzeChartTable(rows) {
2279
135
  const grid = rows.filter((r) => r.some((c) => !blank(c)));
2280
136
  const height = grid.length;
2281
137
  const width = Math.max(0, ...grid.map((r) => r.length));
2282
- const cell = (r, c) => _optionalChain([grid, 'access', _37 => _37[r], 'optionalAccess', _38 => _38[c]]);
138
+ const cell = (r, c) => _optionalChain([grid, 'access', _2 => _2[r], 'optionalAccess', _3 => _3[c]]);
2283
139
  const headerRow = height > 1 && grid[0].some((c) => !blank(c) && isText(c)) && Array.from({ length: width - 1 }, (_, i) => i + 1).every((c) => isText(cell(0, c)));
2284
140
  const blankCorner = headerRow && blank(cell(0, 0));
2285
141
  const labelColumn = width > 1 && (blankCorner || Array.from({ length: height - (headerRow ? 1 : 0) }, (_, i) => i + (headerRow ? 1 : 0)).every((r) => isText(cell(r, 0))));
@@ -2292,7 +148,7 @@ function analyzeChartTable(rows) {
2292
148
  let anyPositive = false;
2293
149
  for (let r = headerRow ? 1 : 0; r < height; r++)
2294
150
  for (let c = labelColumn ? 1 : 0; c < width; c++) {
2295
- const v = _chunkNEOO6QJDcjs.parseChartValue.call(void 0, cell(r, c));
151
+ const v = _chunkJOX6MJW4cjs.parseChartValue.call(void 0, cell(r, c));
2296
152
  if (typeof v !== "number") continue;
2297
153
  anyNumber = true;
2298
154
  if (v < 0) {
@@ -2300,8 +156,8 @@ function analyzeChartTable(rows) {
2300
156
  anyNegative = true;
2301
157
  } else if (v > 0) anyPositive = true;
2302
158
  }
2303
- const labels = byRows ? _nullishCoalesce(_optionalChain([grid, 'access', _39 => _39[0], 'optionalAccess', _40 => _40.slice, 'call', _41 => _41(labelColumn ? 1 : 0)]), () => ( [])) : grid.slice(headerRow ? 1 : 0).map((r) => r[0]);
2304
- const dates = (byRows ? headerRow : labelColumn) && labels.length > 1 && labels.filter((l) => !blank(l) && parseChartDate(String(l)) !== null).length >= labels.length * 0.8;
159
+ const labels = byRows ? _nullishCoalesce(_optionalChain([grid, 'access', _4 => _4[0], 'optionalAccess', _5 => _5.slice, 'call', _6 => _6(labelColumn ? 1 : 0)]), () => ( [])) : grid.slice(headerRow ? 1 : 0).map((r) => r[0]);
160
+ const dates = (byRows ? headerRow : labelColumn) && labels.length > 1 && labels.filter((l) => !blank(l) && _chunkGTZXF4BIcjs.parseChartDate.call(void 0, String(l)) !== null).length >= labels.length * 0.8;
2305
161
  return {
2306
162
  headerRow,
2307
163
  labelColumn,
@@ -2377,8 +233,8 @@ function recommendForShape(shape) {
2377
233
  function chartFromTable(rows, options = {}) {
2378
234
  const shape = analyzeChartTable(rows);
2379
235
  const rec = (_nullishCoalesce(options.type, () => ( "auto"))) === "auto" ? recommendForShape(shape)[0] : void 0;
2380
- const type = _nullishCoalesce(_optionalChain([rec, 'optionalAccess', _42 => _42.type]), () => ( (options.type === "auto" || !options.type ? "bar" : options.type)));
2381
- const stacking = _nullishCoalesce(_optionalChain([rec, 'optionalAccess', _43 => _43.stacking]), () => ( "none"));
236
+ const type = _nullishCoalesce(_optionalChain([rec, 'optionalAccess', _7 => _7.type]), () => ( (options.type === "auto" || !options.type ? "bar" : options.type)));
237
+ const stacking = _nullishCoalesce(_optionalChain([rec, 'optionalAccess', _8 => _8.stacking]), () => ( "none"));
2382
238
  const grid = rows.filter((r) => r.some((c) => !blank(c))).map((r) => [...r]);
2383
239
  const width = Math.max(0, ...grid.map((r) => r.length));
2384
240
  let table = grid;
@@ -2388,1198 +244,16 @@ function chartFromTable(rows, options = {}) {
2388
244
  if (xFromFirst) {
2389
245
  table = table.map((r) => [r[1], ...r.slice(2)]);
2390
246
  }
2391
- const data = _chunkNEOO6QJDcjs.chartDataFromTable.call(void 0, table, { seriesIn: shape.byRows ? "rows" : "columns", header: true, xFromFirstColumn: xFromFirst });
247
+ const data = _chunkJOX6MJW4cjs.chartDataFromTable.call(void 0, table, { seriesIn: shape.byRows ? "rows" : "columns", header: true, xFromFirstColumn: xFromFirst });
2392
248
  return { type, stacking, categories: data.categories, series: data.series, issues: data.issues, shape };
2393
249
  }
2394
250
 
2395
- // src/chart/controller.ts
2396
- function sameChartJson(a, b) {
2397
- if (a === b) return true;
2398
- if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return Number.isNaN(a) && Number.isNaN(b);
2399
- if (Array.isArray(a) !== Array.isArray(b)) return false;
2400
- if (Array.isArray(a)) {
2401
- const bb = b;
2402
- return a.length === bb.length && a.every((v, i) => sameChartJson(v, bb[i]));
2403
- }
2404
- const ao = a;
2405
- const bo = b;
2406
- const keys = Object.keys(ao).filter((k) => ao[k] !== void 0);
2407
- if (keys.length !== Object.keys(bo).filter((k) => bo[k] !== void 0).length) return false;
2408
- return keys.every((k) => Object.prototype.hasOwnProperty.call(bo, k) && sameChartJson(ao[k], bo[k]));
2409
- }
2410
- var fail = (message, issues) => ({ ok: false, message, ...issues ? { issues } : {} });
2411
- var ChartController = (_class = class {
2412
-
2413
-
2414
- __init() {this.selection = null}
2415
- __init2() {this.issues = []}
2416
- __init3() {this.gestureKey = null}
2417
- __init4() {this.gestureCount = 0}
2418
- __init5() {this.gestureStart = null}
2419
- __init6() {this.revision = 0}
2420
- __init7() {this.applying = false}
2421
-
2422
- __init8() {this.listeners = /* @__PURE__ */ new Set()}
2423
-
2424
-
2425
- constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);
2426
- this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkQKLRAA4Tcjs.HistoryManager)()));
2427
- this.onChange = options.onChange;
2428
- const { spec, issues } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, _nullishCoalesce(options.spec, () => ( {})));
2429
- this.spec = spec;
2430
- this.issues = issues;
2431
- this.state = this.computeState();
2432
- this.connect();
2433
- }
2434
- connect() {
2435
- _optionalChain([this, 'access', _44 => _44.unsubscribeHistory, 'optionalCall', _45 => _45()]);
2436
- this.unsubscribeHistory = this.history.subscribe((h) => {
2437
- const s = this.state;
2438
- if (this.applying || s.canUndo === h.canUndo && s.canRedo === h.canRedo && s.undoLabel === h.undoName && s.redoLabel === h.redoName) return;
2439
- this.notify(false);
2440
- });
2441
- }
2442
- // -------------------------------------------------------------------------
2443
- // State
2444
- // -------------------------------------------------------------------------
2445
- /** The current snapshot (stable until the next change). */
2446
- __init9() {this.getState = () => this.state}
2447
- /** Calls `listener` after every change. Returns an unsubscribe function. */
2448
- __init10() {this.subscribe = (listener) => {
2449
- if (!this.unsubscribeHistory) this.connect();
2450
- this.listeners.add(listener);
2451
- return () => {
2452
- this.listeners.delete(listener);
2453
- };
2454
- }}
2455
- /** The current spec (do not mutate; edit through the controller). */
2456
- getSpec() {
2457
- return this.spec;
2458
- }
2459
- getSeries(id) {
2460
- return this.spec.series.find((s) => s.id === id);
2461
- }
2462
- computeState() {
2463
- const h = this.history.getState();
2464
- const sel = this.selection;
2465
- const seriesId = _optionalChain([sel, 'optionalAccess', _46 => _46.kind]) === "series" || _optionalChain([sel, 'optionalAccess', _47 => _47.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _48 => _48.kind]) === "trendline" ? sel.seriesId : null;
2466
- return {
2467
- spec: this.spec,
2468
- selection: sel,
2469
- selectedSeries: seriesId ? _nullishCoalesce(this.spec.series.find((s) => s.id === seriesId), () => ( null)) : null,
2470
- selectedIndex: _optionalChain([sel, 'optionalAccess', _49 => _49.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _50 => _50.kind]) === "category" ? sel.index : null,
2471
- issues: this.issues,
2472
- gesture: this.gestureKey,
2473
- canUndo: h.canUndo,
2474
- canRedo: h.canRedo,
2475
- undoLabel: h.undoName,
2476
- redoLabel: h.redoName,
2477
- revision: this.revision
2478
- };
2479
- }
2480
- notify(specChanged) {
2481
- this.revision++;
2482
- this.state = this.computeState();
2483
- if (specChanged) _optionalChain([this, 'access', _51 => _51.onChange, 'optionalCall', _52 => _52(this.spec)]);
2484
- const state = this.state;
2485
- this.listeners.forEach((listener) => {
2486
- try {
2487
- listener(state);
2488
- } catch (error) {
2489
- console.error("[ChartController] Error in state listener:", error);
2490
- }
2491
- });
2492
- }
2493
- // -------------------------------------------------------------------------
2494
- // Changes: every edit records a before / after snapshot of the spec
2495
- // -------------------------------------------------------------------------
2496
- /** Drops a selection that no longer points at anything. */
2497
- validSelection(sel, spec) {
2498
- if (!sel) return null;
2499
- switch (sel.kind) {
2500
- case "series":
2501
- return spec.series.some((s) => s.id === sel.seriesId) ? sel : null;
2502
- case "point":
2503
- return spec.series.some((s) => s.id === sel.seriesId) && sel.index < spec.categories.length ? sel : null;
2504
- case "category":
2505
- return sel.index < spec.categories.length ? sel : null;
2506
- case "trendline":
2507
- return _optionalChain([spec, 'access', _53 => _53.series, 'access', _54 => _54.find, 'call', _55 => _55((s) => s.id === sel.seriesId), 'optionalAccess', _56 => _56.trendlines, 'optionalAccess', _57 => _57[sel.index]]) ? sel : null;
2508
- case "title":
2509
- return spec.title ? sel : null;
2510
- case "subtitle":
2511
- return spec.subtitle ? sel : null;
2512
- default:
2513
- return sel;
2514
- }
2515
- }
2516
- applySpec(spec) {
2517
- this.applying = true;
2518
- try {
2519
- this.spec = spec;
2520
- this.selection = this.validSelection(this.selection, spec);
2521
- } finally {
2522
- this.applying = false;
2523
- }
2524
- this.notify(true);
2525
- }
2526
- commit(label, next, select) {
2527
- const before = this.spec;
2528
- const hadIssues = this.issues.length > 0;
2529
- this.issues = [];
2530
- if (sameChartJson(before, next)) {
2531
- const reselect = select !== void 0 && !sameChartSelection(this.selection, select) && !(select === null && this.selection === null);
2532
- if (reselect) this.selection = select;
2533
- if (reselect || hadIssues) this.notify(false);
2534
- return;
2535
- }
2536
- const command = {
2537
- name: label,
2538
- tag: "chart",
2539
- execute: () => this.applySpec(next),
2540
- undo: () => this.applySpec(before),
2541
- redo: () => this.applySpec(next)
2542
- };
2543
- if (select !== void 0) this.selection = select;
2544
- if (this.gestureKey !== null) this.history.executeMerged(command, { key: `chart.gesture:${this.gestureKey}:${this.gestureCount}` });
2545
- else this.history.execute(command);
2546
- }
2547
- reject(message, issues = []) {
2548
- this.issues = issues.length ? issues : [{ path: "", message }];
2549
- this.notify(false);
2550
- return fail(message, issues.length ? issues : void 0);
2551
- }
2552
- /** A copy of the spec with `edit` applied (series and categories copied as needed). */
2553
- edited(edit) {
2554
- const draft = _chunkNEOO6QJDcjs.cloneChartSpec.call(void 0, this.spec);
2555
- edit(draft);
2556
- return draft;
2557
- }
2558
- unknownSeries(id) {
2559
- const ids = this.spec.series.map((s) => `"${s.id}"`);
2560
- return fail(`There is no series "${id}"; ${ids.length ? `expected one of ${ids.join(", ")}` : "the chart has no series yet"}.`);
2561
- }
2562
- badIndex(index) {
2563
- const n = this.spec.categories.length;
2564
- return fail(n ? `Category index ${index} is out of range; expected 0 to ${n - 1}.` : "The chart has no categories yet.");
2565
- }
2566
- // -------------------------------------------------------------------------
2567
- // Presentation
2568
- // -------------------------------------------------------------------------
2569
- /**
2570
- * Changes any presentation or data fields as one undo step. All-or-nothing: if anything
2571
- * is invalid, nothing changes and every problem is returned (and shown in `state.issues`).
2572
- */
2573
- update(patch, options = {}) {
2574
- const s = this.spec;
2575
- const merged = {
2576
- ...s,
2577
- ...patch,
2578
- xAxis: patch.xAxis ? { ...s.xAxis, ...patch.xAxis } : s.xAxis,
2579
- yAxis: patch.yAxis ? { ...s.yAxis, ...patch.yAxis } : s.yAxis,
2580
- yAxis2: patch.yAxis2 ? { ...s.yAxis2, ...patch.yAxis2 } : s.yAxis2,
2581
- legend: patch.legend ? { ...s.legend, ...patch.legend } : s.legend,
2582
- version: 1
2583
- };
2584
- const { spec, issues } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, merged);
2585
- if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
2586
- if (JSON.stringify(spec) === JSON.stringify(s)) return { ok: true };
2587
- this.commit(_nullishCoalesce(options.label, () => ( updateLabel(patch))), spec);
2588
- return { ok: true };
2589
- }
2590
- setType(type) {
2591
- return this.update({ type }, { label: `Change chart type` });
2592
- }
2593
- setTitle(title) {
2594
- return this.update({ title }, { label: "Edit title" });
2595
- }
2596
- setSubtitle(subtitle) {
2597
- return this.update({ subtitle }, { label: "Edit subtitle" });
2598
- }
2599
- /** Changes the category (`x`), value (`y`) or secondary value (`y2`) axis. */
2600
- setAxis(axis, patch) {
2601
- const key = axis === "x" ? "xAxis" : axis === "y" ? "yAxis" : "yAxis2";
2602
- return this.update({ [key]: patch }, { label: `Change ${axis === "x" ? "category" : axis === "y" ? "value" : "secondary value"} axis` });
2603
- }
2604
- /**
2605
- * Applies a named quick layout and / or colour scheme (see `CHART_LAYOUT_PRESETS` and
2606
- * `CHART_COLOR_SCHEMES`) as one undo step.
2607
- */
2608
- applyPreset(options) {
2609
- const preset = chartPresetPatch(options);
2610
- if (!preset.ok) return this.reject(preset.message);
2611
- const label = options.layout && options.colors ? "Apply chart style" : options.layout ? "Apply quick layout" : "Change colours";
2612
- return this.update(preset.patch, { label });
2613
- }
2614
- setLegend(patch) {
2615
- return this.update({ legend: patch }, { label: "Change legend" });
2616
- }
2617
- // -------------------------------------------------------------------------
2618
- // Data
2619
- // -------------------------------------------------------------------------
2620
- /**
2621
- * Replaces categories and / or series as one undo step. Values are validated and padded
2622
- * to the categories; all-or-nothing like `update`.
2623
- */
2624
- setData(data, options = {}) {
2625
- return this.update({ ...data.categories ? { categories: data.categories } : {}, ...data.series ? { series: data.series } : {} }, { label: _nullishCoalesce(options.label, () => ( "Edit chart data")) });
2626
- }
2627
- /**
2628
- * Sets one value (numbers, numeric text such as `1,200` or `12%`, or blank for a gap).
2629
- * One undo step, or part of the current gesture.
2630
- */
2631
- setValue(seriesId, index, value, options = {}) {
2632
- const series = this.getSeries(seriesId);
2633
- if (!series) return this.unknownSeries(seriesId);
2634
- if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
2635
- const parsed = _chunkNEOO6QJDcjs.parseChartValue.call(void 0, value);
2636
- if (parsed === void 0) return this.reject(`"${String(value)}" is not a number; enter a number or leave the cell blank.`, [{ path: `${seriesId}[${index}]`, message: `"${String(value)}" is not a number.` }]);
2637
- if (series.values[index] === parsed) {
2638
- if (this.issues.length) {
2639
- this.issues = [];
2640
- this.notify(false);
2641
- }
2642
- return { ok: true };
2643
- }
2644
- const next = this.edited((d) => {
2645
- d.series.find((s) => s.id === seriesId).values[index] = parsed;
2646
- });
2647
- this.commit(_nullishCoalesce(options.label, () => ( `Edit ${series.name} \xB7 ${this.spec.categories[index]}`)), next);
2648
- return { ok: true };
2649
- }
2650
- /** Several values as one undo step (all-or-nothing). */
2651
- setValues(cells, options = {}) {
2652
- const issues = [];
2653
- const parsed = [];
2654
- for (const cell of cells) {
2655
- if (!this.getSeries(cell.seriesId)) issues.push({ path: cell.seriesId, message: this.unknownSeries(cell.seriesId).message });
2656
- else if (!Number.isInteger(cell.index) || cell.index < 0 || cell.index >= this.spec.categories.length) issues.push({ path: `${cell.seriesId}[${cell.index}]`, message: this.badIndex(cell.index).message });
2657
- else {
2658
- const value = _chunkNEOO6QJDcjs.parseChartValue.call(void 0, cell.value);
2659
- if (value === void 0) issues.push({ path: `${cell.seriesId}[${cell.index}]`, message: `"${String(cell.value)}" is not a number.` });
2660
- else parsed.push({ seriesId: cell.seriesId, index: cell.index, value });
2661
- }
2662
- }
2663
- if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
2664
- const next = this.edited((d) => {
2665
- for (const cell of parsed) d.series.find((s) => s.id === cell.seriesId).values[cell.index] = cell.value;
2666
- });
2667
- if (JSON.stringify(next.series) !== JSON.stringify(this.spec.series)) this.commit(_nullishCoalesce(options.label, () => ( "Edit values")), next);
2668
- return { ok: true };
2669
- }
2670
- /** Adds a series (values padded to the categories) and selects it. Returns its id. */
2671
- addSeries(input = {}, options = {}) {
2672
- const id = input.id && !this.getSeries(input.id) ? input.id : _chunkNEOO6QJDcjs.uniqueChartSeriesId.call(void 0, this.spec.series);
2673
- const name = _nullishCoalesce(input.name, () => ( `Series ${this.spec.series.length + 1}`));
2674
- const at = Math.max(0, Math.min(this.spec.series.length, _nullishCoalesce(options.at, () => ( this.spec.series.length))));
2675
- const series = [...this.spec.series];
2676
- series.splice(at, 0, { ...input, id, name, values: _nullishCoalesce(input.values, () => ( [])) });
2677
- const { spec, issues } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, { ...this.spec, series });
2678
- if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
2679
- this.commit(`Add series "${name}"`, spec, { kind: "series", seriesId: id });
2680
- return { ok: true, id };
2681
- }
2682
- removeSeries(id) {
2683
- const series = this.getSeries(id);
2684
- if (!series) return this.unknownSeries(id);
2685
- this.commit(
2686
- `Delete series "${series.name}"`,
2687
- this.edited((d) => {
2688
- d.series = d.series.filter((s) => s.id !== id);
2689
- })
2690
- );
2691
- return { ok: true };
2692
- }
2693
- updateSeries(id, patch) {
2694
- const series = this.getSeries(id);
2695
- if (!series) return this.unknownSeries(id);
2696
- const next = _chunkNEOO6QJDcjs.cloneChartSeries.call(void 0, series);
2697
- if (patch.name !== void 0) next.name = String(patch.name);
2698
- if (patch.color === null || patch.color === "") delete next.color;
2699
- else if (patch.color !== void 0) next.color = patch.color;
2700
- if (patch.type === null) delete next.type;
2701
- else if (patch.type !== void 0) next.type = patch.type;
2702
- if (patch.hidden !== void 0) {
2703
- if (patch.hidden) next.hidden = true;
2704
- else delete next.hidden;
2705
- }
2706
- const resettable = ["axis", "x", "sizes", "pointColors", "marker", "curve", "dataLabels", "format"];
2707
- for (const key of resettable) {
2708
- if (!(key in patch) || patch[key] === void 0) continue;
2709
- if (patch[key] === null) delete next[key];
2710
- else next[key] = patch[key];
2711
- }
2712
- if (next.axis === "primary") delete next.axis;
2713
- const series2 = this.spec.series.map((s) => s.id === id ? next : s);
2714
- const { spec, issues } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, { ...this.spec, series: series2 });
2715
- if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
2716
- if (JSON.stringify(spec.series) === JSON.stringify(this.spec.series)) return { ok: true };
2717
- const label = patch.hidden !== void 0 && Object.keys(patch).length === 1 ? `${patch.hidden ? "Hide" : "Show"} "${series.name}"` : patch.name !== void 0 && Object.keys(patch).length === 1 ? "Rename series" : `Change series "${series.name}"`;
2718
- this.commit(label, spec);
2719
- return { ok: true };
2720
- }
2721
- toggleSeries(id) {
2722
- const series = this.getSeries(id);
2723
- if (!series) return this.unknownSeries(id);
2724
- return this.updateSeries(id, { hidden: !series.hidden });
2725
- }
2726
- /** Moves a series to position `to` (drawing and legend order). */
2727
- moveSeries(id, to) {
2728
- const from = this.spec.series.findIndex((s) => s.id === id);
2729
- if (from < 0) return this.unknownSeries(id);
2730
- const target = Math.max(0, Math.min(this.spec.series.length - 1, to));
2731
- if (target === from) return { ok: true };
2732
- this.commit(
2733
- "Reorder series",
2734
- this.edited((d) => {
2735
- const [s] = d.series.splice(from, 1);
2736
- d.series.splice(target, 0, s);
2737
- })
2738
- );
2739
- return { ok: true };
2740
- }
2741
- /** Inserts a category (with gaps in every series) at `at` (default: the end). Returns its index. */
2742
- addCategory(label, options = {}) {
2743
- const at = Math.max(0, Math.min(this.spec.categories.length, _nullishCoalesce(options.at, () => ( this.spec.categories.length))));
2744
- const name = _nullishCoalesce(label, () => ( `${this.spec.categories.length + 1}`));
2745
- this.commit(
2746
- `Add category "${name}"`,
2747
- this.edited((d) => {
2748
- d.categories.splice(at, 0, name);
2749
- for (const s of d.series) s.values.splice(at, 0, null);
2750
- }),
2751
- { kind: "category", index: at }
2752
- );
2753
- return { ok: true, index: at };
2754
- }
2755
- removeCategory(index) {
2756
- if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
2757
- this.commit(
2758
- `Delete category "${this.spec.categories[index]}"`,
2759
- this.edited((d) => {
2760
- d.categories.splice(index, 1);
2761
- for (const s of d.series) s.values.splice(index, 1);
2762
- })
2763
- );
2764
- return { ok: true };
2765
- }
2766
- renameCategory(index, label) {
2767
- if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
2768
- if (this.spec.categories[index] === label) return { ok: true };
2769
- this.commit(
2770
- "Rename category",
2771
- this.edited((d) => {
2772
- d.categories[index] = String(label);
2773
- })
2774
- );
2775
- return { ok: true };
2776
- }
2777
- moveCategory(from, to) {
2778
- if (!Number.isInteger(from) || from < 0 || from >= this.spec.categories.length) return this.badIndex(from);
2779
- const target = Math.max(0, Math.min(this.spec.categories.length - 1, to));
2780
- if (target === from) return { ok: true };
2781
- const move = (list) => {
2782
- const [item] = list.splice(from, 1);
2783
- list.splice(target, 0, item);
2784
- };
2785
- this.commit(
2786
- "Reorder categories",
2787
- this.edited((d) => {
2788
- move(d.categories);
2789
- for (const s of d.series) move(s.values);
2790
- })
2791
- );
2792
- return { ok: true };
2793
- }
2794
- /**
2795
- * Pastes a block of cells (TSV / CSV text or rows) into the data grid with its top-left at
2796
- * `row` (category index) and `column` (series index; `-1` is the category column). The
2797
- * grid grows to fit. Non-numeric value cells become gaps and are reported in `issues`.
2798
- */
2799
- pasteCells(row, column, cells) {
2800
- const rows = typeof cells === "string" ? cells.includes(" ") ? _chunkTNNJXF46cjs.parseTsv.call(void 0, cells) : _chunkTNNJXF46cjs.parseCsv.call(void 0, cells) : cells.map((r) => [...r]);
2801
- if (!rows.length) return { ok: true };
2802
- const issues = [];
2803
- const next = this.edited((d) => {
2804
- const width = Math.max(...rows.map((r) => r.length));
2805
- const lastSeries = column + width - 1;
2806
- while (d.series.length <= lastSeries) {
2807
- const id = _chunkNEOO6QJDcjs.uniqueChartSeriesId.call(void 0, d.series);
2808
- d.series.push({ id, name: `Series ${d.series.length + 1}`, values: d.categories.map(() => null) });
2809
- }
2810
- const lastRow = row + rows.length - 1;
2811
- while (d.categories.length <= lastRow) {
2812
- d.categories.push(`${d.categories.length + 1}`);
2813
- for (const s of d.series) s.values.push(null);
2814
- }
2815
- rows.forEach((cellsInRow, r) => {
2816
- cellsInRow.forEach((cell, c) => {
2817
- const col = column + c;
2818
- const index = row + r;
2819
- if (col < 0) d.categories[index] = cell === null || cell === void 0 ? "" : String(cell).trim();
2820
- else {
2821
- const parsed = _chunkNEOO6QJDcjs.parseChartValue.call(void 0, cell);
2822
- if (parsed === void 0) issues.push({ path: `${d.series[col].id}[${index}]`, message: `"${String(cell)}" is not a number; it was left blank.` });
2823
- d.series[col].values[index] = _nullishCoalesce(parsed, () => ( null));
2824
- }
2825
- });
2826
- });
2827
- });
2828
- this.commit("Paste cells", next);
2829
- if (issues.length) {
2830
- this.issues = issues;
2831
- this.notify(false);
2832
- }
2833
- return issues.length ? { ok: true, issues } : { ok: true };
2834
- }
2835
- /**
2836
- * Replaces the data with a grid of cells (see `chartDataFromTable`): one undo step. Series
2837
- * colours and types are kept by name.
2838
- */
2839
- importTable(rows, options = {}) {
2840
- const data = _chunkNEOO6QJDcjs.chartDataFromTable.call(void 0, rows, options);
2841
- if (!data.categories.length || !data.series.length) return this.reject("There is no data to import: expected a header row and at least one row of values.");
2842
- const byName = new Map(this.spec.series.map((s) => [s.name, s]));
2843
- const series = data.series.map((s) => {
2844
- const old = byName.get(s.name);
2845
- return { ...s, ..._optionalChain([old, 'optionalAccess', _58 => _58.color]) ? { color: old.color } : {}, ..._optionalChain([old, 'optionalAccess', _59 => _59.type]) ? { type: old.type } : {}, ...old ? { id: old.id } : {} };
2846
- });
2847
- const { spec } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, { ...this.spec, categories: data.categories, series });
2848
- this.commit("Import data", spec);
2849
- if (data.issues.length) {
2850
- this.issues = data.issues;
2851
- this.notify(false);
2852
- return { ok: true, issues: data.issues };
2853
- }
2854
- return { ok: true };
2855
- }
2856
- /** Imports CSV (or TSV, detected by tabs) text; see `importTable`. */
2857
- importCsv(text, options = {}) {
2858
- const delimiter = _nullishCoalesce(options.delimiter, () => ( (text.includes(" ") ? " " : ",")));
2859
- return this.importTable(_chunkTNNJXF46cjs.parseCsv.call(void 0, text, { delimiter }), options);
2860
- }
2861
- // -------------------------------------------------------------------------
2862
- // Trendlines
2863
- // -------------------------------------------------------------------------
2864
- /** Adds a trendline to a series and selects it. Returns its index (and the fit, when it can be computed). */
2865
- addTrendline(seriesId, input) {
2866
- const series = this.getSeries(seriesId);
2867
- if (!series) return this.unknownSeries(seriesId);
2868
- if (!chartSupportsTrendlines(this.spec.type, this.spec.stacking))
2869
- return this.reject(`Trendlines need an unstacked bar, line, area, scatter or bubble chart; this is a ${this.spec.stacking !== "none" ? `${this.spec.stacking} ` : ""}${this.spec.type} chart.`);
2870
- const issues = [];
2871
- const line = _chunkNEOO6QJDcjs.normalizeChartTrendline.call(void 0, input, "trendline", issues);
2872
- if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The trendline is not valid.", issues);
2873
- const index = _nullishCoalesce(_optionalChain([series, 'access', _60 => _60.trendlines, 'optionalAccess', _61 => _61.length]), () => ( 0));
2874
- const next = this.edited((d) => {
2875
- const s = d.series.find((x) => x.id === seriesId);
2876
- s.trendlines = [..._nullishCoalesce(s.trendlines, () => ( [])), line];
2877
- });
2878
- this.commit(`Add trendline to "${series.name}"`, next, { kind: "trendline", seriesId, index });
2879
- return { ok: true, index, fit: this.trendlineFit(seriesId, index) };
2880
- }
2881
- /** Changes a trendline (all-or-nothing). */
2882
- updateTrendline(seriesId, index, patch) {
2883
- const series = this.getSeries(seriesId);
2884
- if (!series) return this.unknownSeries(seriesId);
2885
- const current = _optionalChain([series, 'access', _62 => _62.trendlines, 'optionalAccess', _63 => _63[index]]);
2886
- if (!current) return fail(`"${series.name}" has no trendline ${index}; ${_optionalChain([series, 'access', _64 => _64.trendlines, 'optionalAccess', _65 => _65.length]) ? `expected 0 to ${series.trendlines.length - 1}` : "it has none yet"}.`);
2887
- const issues = [];
2888
- const merged = { ...current, ...patch };
2889
- for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
2890
- const line = _chunkNEOO6QJDcjs.normalizeChartTrendline.call(void 0, merged, "trendline", issues);
2891
- if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
2892
- this.commit(
2893
- "Change trendline",
2894
- this.edited((d) => {
2895
- d.series.find((x) => x.id === seriesId).trendlines[index] = line;
2896
- })
2897
- );
2898
- return { ok: true };
2899
- }
2900
- removeTrendline(seriesId, index) {
2901
- const series = this.getSeries(seriesId);
2902
- if (!series) return this.unknownSeries(seriesId);
2903
- if (!_optionalChain([series, 'access', _66 => _66.trendlines, 'optionalAccess', _67 => _67[index]])) return fail(`"${series.name}" has no trendline ${index}.`);
2904
- this.commit(
2905
- "Delete trendline",
2906
- this.edited((d) => {
2907
- const s = d.series.find((x) => x.id === seriesId);
2908
- s.trendlines = s.trendlines.filter((_, i) => i !== index);
2909
- if (!s.trendlines.length) delete s.trendlines;
2910
- })
2911
- );
2912
- return { ok: true };
2913
- }
2914
- /** The points a series' trendlines are fitted to: (x, y) with x = 1, 2, 3 … on category charts. */
2915
- trendlinePoints(seriesId) {
2916
- const series = this.getSeries(seriesId);
2917
- if (!series) return [];
2918
- const xy = _chunkNEOO6QJDcjs.chartFamily.call(void 0, this.spec) === "xy";
2919
- const out = [];
2920
- series.values.forEach((v, i) => {
2921
- const x = xy ? _nullishCoalesce(_optionalChain([series, 'access', _68 => _68.x, 'optionalAccess', _69 => _69[i]]), () => ( (this.spec.type === "bubble" ? i + 1 : null))) : i + 1;
2922
- if (v !== null && x !== null && Number.isFinite(v) && Number.isFinite(x)) out.push([x, v]);
2923
- });
2924
- return out;
2925
- }
2926
- /** The fitted coefficients, R² and equation of a trendline (null for moving averages or unfittable data). */
2927
- trendlineFit(seriesId, index) {
2928
- const line = _optionalChain([this, 'access', _70 => _70.getSeries, 'call', _71 => _71(seriesId), 'optionalAccess', _72 => _72.trendlines, 'optionalAccess', _73 => _73[index]]);
2929
- if (!line) return null;
2930
- return fitChartTrendline(line, this.trendlinePoints(seriesId));
2931
- }
2932
- /** The moving-average points of a trendline (empty for other kinds). */
2933
- trendlineMovingAverage(seriesId, index) {
2934
- const line = _optionalChain([this, 'access', _74 => _74.getSeries, 'call', _75 => _75(seriesId), 'optionalAccess', _76 => _76.trendlines, 'optionalAccess', _77 => _77[index]]);
2935
- if (!line || line.type !== "moving-average") return [];
2936
- return chartMovingAverage(this.trendlinePoints(seriesId), _nullishCoalesce(line.period, () => ( 2)));
2937
- }
2938
- // -------------------------------------------------------------------------
2939
- // Reshaping
2940
- // -------------------------------------------------------------------------
2941
- /**
2942
- * Switches rows and columns: series become categories and categories become series (one
2943
- * undo step). Series colours, types and other per-series settings are dropped.
2944
- */
2945
- transpose() {
2946
- const s = this.spec;
2947
- if (!s.series.length || !s.categories.length) return this.reject("There is no data to switch: the chart needs at least one series and one category.");
2948
- const used = /* @__PURE__ */ new Set();
2949
- const series = s.categories.map((name, i) => {
2950
- let id = `series-${i + 1}`;
2951
- for (let k = i + 2; used.has(id); k++) id = `series-${k}`;
2952
- used.add(id);
2953
- return { id, name, values: s.series.map((x) => _nullishCoalesce(x.values[i], () => ( null))) };
2954
- });
2955
- const { spec } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, { ...s, categories: s.series.map((x) => x.name), series });
2956
- this.commit("Switch rows and columns", spec, null);
2957
- return { ok: true };
2958
- }
2959
- // -------------------------------------------------------------------------
2960
- // Selection and gestures
2961
- // -------------------------------------------------------------------------
2962
- /** Selects a chart element (view state; not an undo step). */
2963
- select(selection) {
2964
- const next = this.validSelection(selection, this.spec);
2965
- if (sameChartSelection(next, this.selection) || next === null && this.selection === null) return;
2966
- this.selection = next;
2967
- this.notify(false);
2968
- }
2969
- /**
2970
- * Deletes what is selected: a series or category is removed, a point becomes a gap, a
2971
- * title is cleared, the legend or an axis is hidden.
2972
- */
2973
- deleteSelection() {
2974
- const sel = this.selection;
2975
- if (!sel) return fail("Nothing is selected.");
2976
- switch (sel.kind) {
2977
- case "series":
2978
- return this.removeSeries(sel.seriesId);
2979
- case "category":
2980
- return this.removeCategory(sel.index);
2981
- case "point":
2982
- return this.setValue(sel.seriesId, sel.index, null, { label: "Clear value" });
2983
- case "title":
2984
- return this.setTitle("");
2985
- case "subtitle":
2986
- return this.setSubtitle("");
2987
- case "legend":
2988
- return this.setLegend({ show: false });
2989
- case "axis":
2990
- return this.setAxis(sel.axis, { show: false });
2991
- case "trendline":
2992
- return this.removeTrendline(sel.seriesId, sel.index);
2993
- default:
2994
- return fail("The chart itself cannot be deleted.");
2995
- }
2996
- }
2997
- /** Adds `delta` to a value (a gap counts as 0). */
2998
- nudgeValue(seriesId, index, delta) {
2999
- const series = this.getSeries(seriesId);
3000
- if (!series) return this.unknownSeries(seriesId);
3001
- const current = _nullishCoalesce(series.values[index], () => ( 0));
3002
- return this.setValue(seriesId, index, Number((current + delta).toPrecision(12)), { label: `Edit ${series.name} \xB7 ${_nullishCoalesce(this.spec.categories[index], () => ( index))}` });
3003
- }
3004
- /** Starts a continuous edit (a drag): every change until `endGesture()` is one undo step. */
3005
- beginGesture(key) {
3006
- if (this.gestureKey === key) return;
3007
- this.history.endGesture();
3008
- this.gestureKey = key;
3009
- this.gestureCount++;
3010
- this.gestureStart = { spec: this.spec, mark: this.history.mark() };
3011
- this.notify(false);
3012
- }
3013
- /**
3014
- * Cancels the gesture in progress (Escape during a drag): everything it changed is taken
3015
- * back and leaves no undo or redo step.
3016
- */
3017
- cancelGesture() {
3018
- if (this.gestureKey === null) return;
3019
- const start = this.gestureStart;
3020
- this.gestureKey = null;
3021
- this.gestureStart = null;
3022
- this.history.endGesture();
3023
- if (start) this.history.revertTo(start.mark);
3024
- this.notify(false);
3025
- }
3026
- endGesture() {
3027
- if (this.gestureKey === null) return;
3028
- this.gestureKey = null;
3029
- this.history.endGesture();
3030
- const start = this.gestureStart;
3031
- this.gestureStart = null;
3032
- if (start && sameChartJson(start.spec, this.spec)) this.history.revertTo(start.mark);
3033
- this.notify(false);
3034
- }
3035
- // -------------------------------------------------------------------------
3036
- // Persistence and history
3037
- // -------------------------------------------------------------------------
3038
- /** The spec, for saving (a copy). */
3039
- toJSON() {
3040
- return _chunkNEOO6QJDcjs.cloneChartSpec.call(void 0, this.spec);
3041
- }
3042
- /**
3043
- * Replaces the chart without an undo step (e.g. when opening a document). Problems are
3044
- * fixed with defaults and reported in `state.issues` (and returned).
3045
- */
3046
- load(input, options = {}) {
3047
- const { spec, issues } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, input);
3048
- this.spec = spec;
3049
- this.issues = issues;
3050
- this.selection = this.validSelection(this.selection, spec);
3051
- if (options.clearHistory) {
3052
- this.applying = true;
3053
- try {
3054
- this.history.clear();
3055
- } finally {
3056
- this.applying = false;
3057
- }
3058
- }
3059
- this.notify(true);
3060
- return issues;
3061
- }
3062
- undo() {
3063
- this.endGesture();
3064
- return this.history.undo();
3065
- }
3066
- redo() {
3067
- this.endGesture();
3068
- return this.history.redo();
3069
- }
3070
- /** Stops listening to the history (reconnected by the next `subscribe`). */
3071
- destroy() {
3072
- _optionalChain([this, 'access', _78 => _78.unsubscribeHistory, 'optionalCall', _79 => _79()]);
3073
- this.unsubscribeHistory = void 0;
3074
- this.listeners.clear();
3075
- }
3076
- }, _class);
3077
- function createChartController(options = {}) {
3078
- return new ChartController(options);
3079
- }
3080
- function updateLabel(patch) {
3081
- const keys = Object.keys(patch);
3082
- if (keys.length !== 1) return "Change chart";
3083
- const labels = {
3084
- type: "Change chart type",
3085
- title: "Edit title",
3086
- subtitle: "Edit subtitle",
3087
- categories: "Edit categories",
3088
- series: "Edit series",
3089
- xAxis: "Change category axis",
3090
- yAxis: "Change value axis",
3091
- yAxis2: "Change secondary value axis",
3092
- labelPosition: "Change label position",
3093
- gapWidth: "Change bar spacing",
3094
- overlap: "Change bar overlap",
3095
- bins: "Change histogram bins",
3096
- showTotal: "Toggle waterfall total",
3097
- legend: "Change legend",
3098
- stacking: "Change stacking",
3099
- orientation: "Change orientation",
3100
- curve: "Change line style",
3101
- points: "Toggle points",
3102
- dataLabels: "Toggle data labels",
3103
- palette: "Change colours",
3104
- innerRadius: "Change donut hole"
3105
- };
3106
- return _nullishCoalesce(labels[keys[0]], () => ( "Change chart"));
3107
- }
3108
-
3109
- // src/chart/mermaid.ts
3110
- var CHART_MERMAID_META_PREFIX = "%% @pixerate ";
3111
- var quote = (text) => `"${text.replace(/"/g, "#quot;")}"`;
3112
- var unquote = (text) => {
3113
- const t = text.trim();
3114
- return (t.length >= 2 && t.startsWith('"') && t.endsWith('"') ? t.slice(1, -1) : t).replace(/#quot;/g, '"');
3115
- };
3116
- var word = (text) => /^[A-Za-z0-9_]+$/.test(text) ? text : quote(text);
3117
- var num = (value) => Number.isInteger(value) ? String(value) : String(Number(value.toPrecision(10)));
3118
- function splitOutside(text, sep) {
3119
- const out = [];
3120
- let cur = "";
3121
- let quoted = false;
3122
- let depth = 0;
3123
- for (const ch of text) {
3124
- if (ch === '"') quoted = !quoted;
3125
- else if (!quoted && (ch === "[" || ch === "{")) depth++;
3126
- else if (!quoted && (ch === "]" || ch === "}")) depth--;
3127
- if (ch === sep && !quoted && depth === 0) {
3128
- out.push(cur);
3129
- cur = "";
3130
- } else cur += ch;
3131
- }
3132
- out.push(cur);
3133
- return out;
3134
- }
3135
- function chartMermaidFamily(spec) {
3136
- const family = _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec);
3137
- if (family === "pie" || family === "funnel" || family === "treemap") return "pie";
3138
- if (family === "radar") return "radar";
3139
- return "xychart";
3140
- }
3141
- function slug(label, i, taken) {
3142
- let base = label.normalize("NFKD").replace(/[^\w-]+/g, "_").replace(/^_+|_+$/g, "") || `a${i + 1}`;
3143
- if (!/^[A-Za-z_]/.test(base)) base = `a_${base}`;
3144
- let id = base;
3145
- for (let k = 2; taken.has(id); k++) id = `${base}_${k}`;
3146
- taken.add(id);
3147
- return id;
3148
- }
3149
- function metaFor(spec, text) {
3150
- const base = chartFromMermaid(text, { ignoreMeta: true }).spec;
3151
- const meta = {};
3152
- const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
3153
- for (const key of Object.keys(spec)) {
3154
- if (key === "series" || key === "version") continue;
3155
- if (!same(spec[key], base[key])) meta[key] = spec[key];
3156
- }
3157
- const series = spec.series.map((s, i) => {
3158
- const b = base.series[i];
3159
- const out = {};
3160
- for (const [k, v] of Object.entries(s)) {
3161
- if (k === "values") {
3162
- if (b && !same(v, b.values)) out.values = v;
3163
- continue;
3164
- }
3165
- if (!b || !same(v, b[k])) out[k] = v;
3166
- }
3167
- return out;
3168
- });
3169
- if (series.some((s) => Object.keys(s).length) || spec.series.length !== base.series.length) meta.series = series;
3170
- return Object.keys(meta).length ? meta : null;
3171
- }
3172
- function chartToMermaid(spec, options = {}) {
3173
- const ind = _nullishCoalesce(options.indent, () => ( " "));
3174
- const family = chartMermaidFamily(spec);
3175
- const visible = spec.series.filter((s) => !s.hidden);
3176
- const lines = [];
3177
- const v = (x) => x === null || !Number.isFinite(x) ? "0" : num(x);
3178
- if (family === "pie") {
3179
- const s = _nullishCoalesce(visible[0], () => ( spec.series[0]));
3180
- lines.push(`pie${spec.dataLabels ? " showData" : ""}`);
3181
- if (spec.title) lines.push(`${ind}title ${spec.title}`);
3182
- spec.categories.forEach((c, i) => {
3183
- const value = _optionalChain([s, 'optionalAccess', _80 => _80.values, 'access', _81 => _81[i]]);
3184
- if (value !== null && value !== void 0 && Number.isFinite(value) && value > 0) lines.push(`${ind}${quote(c)} : ${num(value)}`);
3185
- });
3186
- } else if (family === "radar") {
3187
- lines.push("radar-beta");
3188
- if (spec.title) lines.push(`${ind}title ${spec.title}`);
3189
- const taken = /* @__PURE__ */ new Set();
3190
- const ids = spec.categories.map((c, i) => slug(c, i, taken));
3191
- lines.push(`${ind}axis ${ids.map((id, i) => id === spec.categories[i] ? id : `${id}["${spec.categories[i].replace(/"/g, "'")}"]`).join(", ")}`);
3192
- const seriesTaken = new Set(ids);
3193
- for (const [i, s] of spec.series.entries()) {
3194
- const id = slug(s.id, i, seriesTaken);
3195
- lines.push(`${ind}curve ${id}["${s.name.replace(/"/g, "'")}"]{${s.values.map(v).join(", ")}}`);
3196
- }
3197
- if (spec.yAxis.max !== null) lines.push(`${ind}max ${num(spec.yAxis.max)}`);
3198
- if (spec.yAxis.min !== null) lines.push(`${ind}min ${num(spec.yAxis.min)}`);
3199
- if (!spec.legend.show) lines.push(`${ind}showLegend false`);
3200
- } else {
3201
- lines.push(`xychart-beta${spec.orientation === "horizontal" ? " horizontal" : ""}`);
3202
- if (spec.title) lines.push(`${ind}title ${quote(spec.title)}`);
3203
- const xTitle = spec.xAxis.title ? ` ${quote(spec.xAxis.title)}` : "";
3204
- lines.push(`${ind}x-axis${xTitle} [${spec.categories.map(word).join(", ")}]`);
3205
- const y = spec.yAxis;
3206
- if (y.title || y.min !== null || y.max !== null) {
3207
- let out = `${ind}y-axis`;
3208
- if (y.title) out += ` ${quote(y.title)}`;
3209
- if (y.min !== null || y.max !== null) {
3210
- const all = spec.series.flatMap((s) => s.values).filter((x) => x !== null && Number.isFinite(x));
3211
- const lo = _nullishCoalesce(y.min, () => ( Math.min(0, ...all)));
3212
- const hi = _nullishCoalesce(y.max, () => ( Math.max(lo + 1, ...all)));
3213
- out += ` ${num(lo)} --> ${num(hi)}`;
3214
- }
3215
- lines.push(out);
3216
- }
3217
- for (const s of spec.series) {
3218
- const kind = (_nullishCoalesce(s.type, () => ( (spec.type === "bar" ? "bar" : "line")))) === "bar" ? "bar" : "line";
3219
- lines.push(`${ind}${kind} ${quote(s.name)} [${s.values.map(v).join(", ")}]`);
3220
- }
3221
- }
3222
- let text = `${lines.join("\n")}
3223
- `;
3224
- if (options.meta !== false) {
3225
- const meta = metaFor(spec, text);
3226
- if (meta) {
3227
- const [header, ...rest] = lines;
3228
- text = `${[header, `${CHART_MERMAID_META_PREFIX}${JSON.stringify({ v: 1, ...meta })}`, ...rest].join("\n")}
3229
- `;
3230
- }
3231
- }
3232
- return text;
3233
- }
3234
- var RANGE = /^(-?\d+(?:\.\d+)?)\s*-->\s*(-?\d+(?:\.\d+)?)$/;
3235
- function takeTitle(text) {
3236
- const t = text.trim();
3237
- if (t.startsWith('"')) {
3238
- const end = t.indexOf('"', 1);
3239
- if (end > 0) return { title: unquote(t.slice(0, end + 1)), rest: t.slice(end + 1).trim() };
3240
- }
3241
- if (!t || t.startsWith("[") || RANGE.test(t) || /^-?\d/.test(t)) return { rest: t };
3242
- const m = /^(\S+)\s*(.*)$/.exec(t);
3243
- return { title: m[1], rest: m[2].trim() };
3244
- }
3245
- function parseList(text, partial) {
3246
- const t = text.trim();
3247
- let m = /^\[(.*)\]$/s.exec(t);
3248
- if (!m && partial) m = /^\[(.*)$/s.exec(t);
3249
- if (!m) return void 0;
3250
- if (!m[1].trim()) return [];
3251
- const items = splitOutside(m[1], ",").map((x) => x.trim());
3252
- if (partial && !/\]$/.test(t)) {
3253
- const last = items[items.length - 1];
3254
- if (!last || last.startsWith('"') && !/"$/.test(last.slice(1))) items.pop();
3255
- }
3256
- return items.map(unquote);
3257
- }
3258
- function chartFromMermaid(text, options = {}) {
3259
- const issues = [];
3260
- const partial = !!options.partial;
3261
- const all = text.replace(/^/, "").split(/\r?\n/);
3262
- let start = 0;
3263
- let frontTitle;
3264
- if (_optionalChain([all, 'access', _82 => _82[0], 'optionalAccess', _83 => _83.trim, 'call', _84 => _84()]) === "---") {
3265
- const end = all.findIndex((l, i) => i > 0 && l.trim() === "---");
3266
- if (end > 0) {
3267
- for (const l of all.slice(1, end)) {
3268
- const m = /^title:\s*(.+)$/.exec(l.trim());
3269
- if (m) frontTitle = unquote(m[1]);
3270
- }
3271
- start = end + 1;
3272
- }
3273
- }
3274
- let family = null;
3275
- let headerLine = -1;
3276
- let horizontal = false;
3277
- let showData = false;
3278
- let meta = null;
3279
- for (let i = start; i < all.length; i++) {
3280
- const t = all[i].trim();
3281
- if (!t || t.startsWith("%%")) continue;
3282
- let m;
3283
- if (m = /^xychart(?:-beta)?(?:\s+(horizontal|vertical))?\s*$/i.exec(t)) {
3284
- family = "xychart";
3285
- horizontal = _optionalChain([m, 'access', _85 => _85[1], 'optionalAccess', _86 => _86.toLowerCase, 'call', _87 => _87()]) === "horizontal";
3286
- } else if (m = /^pie(\s+showData)?(?:\s+title\s+(.*))?\s*$/i.exec(t)) {
3287
- family = "pie";
3288
- showData = !!m[1];
3289
- if (m[2]) frontTitle = m[2].trim();
3290
- } else if (/^radar(?:-beta)?\s*$/i.test(t)) family = "radar";
3291
- else issues.push({ path: "header", line: i + 1, message: `Line ${i + 1}: expected a chart header (xychart-beta, pie or radar-beta), got "${t.slice(0, 40)}".` });
3292
- headerLine = i;
3293
- break;
3294
- }
3295
- let title = _nullishCoalesce(frontTitle, () => ( ""));
3296
- const categories = [];
3297
- const series = [];
3298
- const xAxis = _chunkNEOO6QJDcjs.defaultChartAxis.call(void 0, false);
3299
- const yAxis = _chunkNEOO6QJDcjs.defaultChartAxis.call(void 0, true);
3300
- const radarAxes = [];
3301
- const pieSlices = [];
3302
- let legendShow = true;
3303
- const counts = { bar: 0, line: 0 };
3304
- const lineIssue = (i, message) => issues.push({ path: `line ${i + 1}`, line: i + 1, message: `Line ${i + 1}: ${message}` });
3305
- for (let i = headerLine + 1; family && i < all.length; i++) {
3306
- const raw = all[i];
3307
- const t = raw.trim();
3308
- if (!t) continue;
3309
- if (t.startsWith(CHART_MERMAID_META_PREFIX.trim())) {
3310
- if (options.ignoreMeta) continue;
3311
- try {
3312
- const parsed = JSON.parse(t.slice(CHART_MERMAID_META_PREFIX.trim().length).trim());
3313
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) meta = parsed;
3314
- else lineIssue(i, "the @pixerate metadata is not a JSON object; it was ignored.");
3315
- } catch (e2) {
3316
- if (!partial) lineIssue(i, "the @pixerate metadata is not valid JSON; it was ignored.");
3317
- }
3318
- continue;
3319
- }
3320
- if (t.startsWith("%%")) continue;
3321
- const isLast = i === all.length - 1 || all.slice(i + 1).every((l) => !l.trim());
3322
- let m;
3323
- if (m = /^title\s+(.+)$/i.exec(t)) {
3324
- title = unquote(m[1]);
3325
- continue;
3326
- }
3327
- if (family === "xychart") {
3328
- if (m = /^x-axis\b(.*)$/i.exec(t)) {
3329
- const { title: xt, rest } = takeTitle(m[1]);
3330
- if (xt) xAxis.title = xt;
3331
- const list = parseList(rest, partial && isLast);
3332
- if (list) categories.splice(0, categories.length, ...list);
3333
- else if (RANGE.test(rest)) {
3334
- const r = RANGE.exec(rest);
3335
- xAxis.min = Number(r[1]);
3336
- xAxis.max = Number(r[2]);
3337
- } else if (rest) lineIssue(i, `expected x-axis [a, b, \u2026] or a range "min --> max", got "${rest.slice(0, 40)}".`);
3338
- continue;
3339
- }
3340
- if (m = /^y-axis\b(.*)$/i.exec(t)) {
3341
- const { title: yt, rest } = takeTitle(m[1]);
3342
- if (yt) yAxis.title = yt;
3343
- const r = RANGE.exec(rest);
3344
- if (r) {
3345
- yAxis.min = Number(r[1]);
3346
- yAxis.max = Number(r[2]);
3347
- } else if (rest) lineIssue(i, `expected y-axis "min --> max", got "${rest.slice(0, 40)}".`);
3348
- continue;
3349
- }
3350
- if (m = /^(bar|line)\b(.*)$/i.exec(t)) {
3351
- const kind = m[1].toLowerCase();
3352
- const { title: st, rest } = takeTitle(m[2]);
3353
- const list = parseList(rest, partial && isLast);
3354
- if (!list) {
3355
- if (!(partial && isLast)) lineIssue(i, `expected ${kind} [1, 2, 3], got "${rest.slice(0, 40)}".`);
3356
- continue;
3357
- }
3358
- const values = list.map((x) => x.trim() === "" ? null : Number(x));
3359
- if (values.some((x) => x !== null && !Number.isFinite(x))) {
3360
- lineIssue(i, `${kind} values must be numbers.`);
3361
- continue;
3362
- }
3363
- counts[kind]++;
3364
- series.push({ id: `series-${series.length + 1}`, name: _nullishCoalesce(st, () => ( `${kind === "bar" ? "Bar" : "Line"} ${counts[kind]}`)), values, type: kind });
3365
- continue;
3366
- }
3367
- } else if (family === "pie") {
3368
- if (m = /^"((?:[^"\\]|\\.)*)"\s*:\s*(-?\d+(?:\.\d+)?)\s*$/.exec(t)) {
3369
- pieSlices.push({ label: m[1].replace(/#quot;/g, '"'), value: Number(m[2]) });
3370
- continue;
3371
- }
3372
- if (/^showData\s*$/i.test(t)) {
3373
- showData = true;
3374
- continue;
3375
- }
3376
- } else if (family === "radar") {
3377
- if (m = /^axis\s+(.+)$/.exec(t)) {
3378
- for (const part of splitOutside(m[1], ",")) {
3379
- const a = /^([A-Za-z_][\w-]*)\s*(?:\[\s*"((?:[^"\\]|\\.)*)"\s*\])?$/.exec(part.trim());
3380
- if (a) radarAxes.push({ id: a[1], label: _nullishCoalesce(a[2], () => ( a[1])) });
3381
- else lineIssue(i, `could not read the axis "${part.trim()}".`);
3382
- }
3383
- continue;
3384
- }
3385
- if (m = /^curve\s+([A-Za-z_][\w-]*)\s*(?:\[\s*"((?:[^"\\]|\\.)*)"\s*\])?\s*\{(.*)\}?\s*$/.exec(t)) {
3386
- const body = m[3].replace(/\}\s*$/, "");
3387
- const entries = body.trim() ? splitOutside(body, ",").map((x) => x.trim()).filter(Boolean) : [];
3388
- const ids = radarAxes.map((a) => a.id);
3389
- const values = ids.map(() => null);
3390
- let k = 0;
3391
- for (const e of entries) {
3392
- const keyed = /^([A-Za-z_][\w-]*)\s*:\s*(-?\d+(?:\.\d+)?)$/.exec(e);
3393
- if (keyed) {
3394
- const at = ids.indexOf(keyed[1]);
3395
- if (at >= 0) values[at] = Number(keyed[2]);
3396
- else lineIssue(i, `curve ${m[1]} names an unknown axis "${keyed[1]}".`);
3397
- } else if (/^-?\d+(?:\.\d+)?$/.test(e)) {
3398
- if (k < values.length) values[k] = Number(e);
3399
- else values.push(Number(e));
3400
- k++;
3401
- } else lineIssue(i, `could not read "${e}" in curve ${m[1]}.`);
3402
- }
3403
- series.push({ id: m[1], name: _nullishCoalesce(m[2], () => ( m[1])), values });
3404
- continue;
3405
- }
3406
- if (m = /^(max|min|ticks|graticule|showLegend)\s+(\S+)$/.exec(t)) {
3407
- if (m[1] === "max") yAxis.max = Number(m[2]);
3408
- else if (m[1] === "min") yAxis.min = Number(m[2]);
3409
- else if (m[1] === "showLegend") legendShow = m[2] !== "false";
3410
- continue;
3411
- }
3412
- }
3413
- if (!(partial && isLast)) lineIssue(i, `could not read "${t.slice(0, 60)}"; it was skipped.`);
3414
- }
3415
- let input;
3416
- if (family === "pie") {
3417
- input = {
3418
- type: "pie",
3419
- title,
3420
- dataLabels: showData,
3421
- categories: pieSlices.map((s) => s.label),
3422
- series: [{ id: "series-1", name: title || "Values", values: pieSlices.map((s) => s.value) }]
3423
- };
3424
- } else if (family === "radar") {
3425
- input = { type: "radar", title, categories: radarAxes.map((a) => a.label), series, yAxis, legend: { show: legendShow, position: "bottom" } };
3426
- } else {
3427
- const allBar = series.length > 0 && series.every((s) => s.type === "bar");
3428
- const allLine = series.length > 0 && series.every((s) => s.type === "line");
3429
- const type = allLine ? "line" : "bar";
3430
- const longest = Math.max(0, ...series.map((s) => s.values.length));
3431
- const cats = categories.length ? categories : Array.from({ length: longest }, (_, i) => `${i + 1}`);
3432
- input = {
3433
- type,
3434
- title,
3435
- orientation: horizontal ? "horizontal" : "vertical",
3436
- categories: cats,
3437
- xAxis,
3438
- yAxis,
3439
- // Series that match the chart type do not need their own type.
3440
- series: series.map((s) => allBar || allLine || s.type === type ? { ...s, type: void 0 } : s)
3441
- };
3442
- }
3443
- if (meta) {
3444
- const { v: _v, series: metaSeries, ...rest } = meta;
3445
- Object.assign(input, rest);
3446
- if (Array.isArray(metaSeries)) {
3447
- const base = _nullishCoalesce(input.series, () => ( []));
3448
- input.series = metaSeries.map((extra, i) => ({ ..._nullishCoalesce(base[i], () => ( {})), ..._nullishCoalesce(extra, () => ( {})) }));
3449
- }
3450
- }
3451
- const { spec, issues: specIssues } = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, input);
3452
- if (!family && !partial && !issues.length) issues.push({ path: "header", message: "The text is empty: expected a chart header (xychart-beta, pie or radar-beta)." });
3453
- return { spec, issues: [...issues, ...specIssues], family, hasMeta: !!meta };
3454
- }
3455
- function findMermaidCharts(text) {
3456
- const lines = text.replace(/^/, "").split(/\r?\n/);
3457
- const found = [];
3458
- const familyOf = (body) => {
3459
- const header = body.split(/\r?\n/).find((l) => l.trim() && !l.trim().startsWith("%%") && l.trim() !== "---");
3460
- if (!header) return null;
3461
- if (/^\s*xychart(-beta)?\b/.test(header)) return "xychart";
3462
- if (/^\s*pie\b/.test(header)) return "pie";
3463
- if (/^\s*radar(-beta)?\b/.test(header)) return "radar";
3464
- return null;
3465
- };
3466
- for (let i = 0; i < lines.length; i++) {
3467
- const open = /^ {0,3}(`{3,}|~{3,})\s*([\w-]*)/.exec(lines[i]);
3468
- if (!open) continue;
3469
- const fence = open[1];
3470
- const info = open[2].toLowerCase();
3471
- let end = i + 1;
3472
- while (end < lines.length && !new RegExp(`^ {0,3}${fence[0]}{${fence.length},}\\s*$`).test(lines[end])) end++;
3473
- const body = lines.slice(i + 1, end).join("\n");
3474
- if (!info || info === "mermaid") {
3475
- const family = familyOf(body);
3476
- if (family) found.push({ source: `${body.trimEnd()}
3477
- `, family, line: i + 2 });
3478
- }
3479
- i = end;
3480
- }
3481
- if (!found.length) {
3482
- const family = familyOf(text);
3483
- if (family) found.push({ source: `${text.trim()}
3484
- `, family, line: 1 });
3485
- }
3486
- return found;
3487
- }
3488
-
3489
- // src/chart/schemas.ts
3490
- var VALUE = { type: ["number", "string", "null"], description: 'A number, numeric text ("1,200", "12%", "$40", "(3)") or null for a gap.' };
3491
- var SERIES_REF = { type: "string", description: "Series id (from get_chart) or exact series name." };
3492
- var CATEGORY_REF = { type: ["string", "integer"], description: "Category index (0-based) or exact category label." };
3493
- var WIDTH = { type: "number", minimum: 50, maximum: 4096, description: "Width in pixels (default 640)." };
3494
- var HEIGHT = { type: "number", minimum: 50, maximum: 4096, description: "Height in pixels (default 400)." };
3495
- var FORMAT = {
3496
- type: "object",
3497
- description: "How numbers are written on this axis or series.",
3498
- properties: {
3499
- style: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_NUMBER_STYLES], description: "number (default), percent (0.25 \u2192 25%), currency or compact (1.2K)." },
3500
- decimals: { type: "integer", minimum: 0, maximum: 10, description: "Fixed decimals (default: what the ticks need)." },
3501
- currency: { type: "string", description: 'ISO currency code for style "currency", e.g. "EUR" (default USD).' },
3502
- prefix: { type: "string", description: "Text before every number." },
3503
- suffix: { type: "string", description: "Text after every number." },
3504
- code: { type: "string", description: 'Spreadsheet format code such as "#,##0.0,,\\"M\\"" or "0.0%"; wins over the other fields.' }
3505
- },
3506
- additionalProperties: false
3507
- };
3508
- var AXIS = (what) => ({
3509
- type: "object",
3510
- description: what,
3511
- properties: {
3512
- show: { type: "boolean", description: "Draw the axis labels (default true)." },
3513
- title: { type: "string", description: 'Axis title ("" for none).' },
3514
- min: { type: ["number", "null"], description: "Fixed lower bound, or null for automatic." },
3515
- max: { type: ["number", "null"], description: "Fixed upper bound, or null for automatic." },
3516
- step: { type: ["number", "null"], exclusiveMinimum: 0, description: "Fixed distance between ticks, or null for automatic." },
3517
- gridlines: { type: "boolean", description: "Grid lines at each tick." },
3518
- format: FORMAT,
3519
- kind: { type: ["string", "null"], enum: [..._chunkNEOO6QJDcjs.CHART_AXIS_KINDS, null], description: 'Category axis only: "date" reads categories as dates and labels them by calendar steps.' }
3520
- },
3521
- additionalProperties: false
3522
- });
3523
- var TRENDLINE_PROPS = {
3524
- type: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_TRENDLINE_TYPES], description: "Fit: linear, exponential, logarithmic, power, polynomial or moving-average." },
3525
- order: { type: "integer", minimum: 2, maximum: 6, description: "Polynomial order (default 2)." },
3526
- period: { type: "integer", minimum: 2, description: "Moving-average period in points (default 2)." },
3527
- forward: { type: "number", minimum: 0, description: "Extend the line this many x units past the last point (default 0)." },
3528
- backward: { type: "number", minimum: 0, description: "Extend the line this many x units before the first point (default 0)." },
3529
- intercept: { type: ["number", "null"], description: "Force the fit through this y at x = 0 (linear, polynomial, exponential)." },
3530
- showEquation: { type: "boolean", description: "Write the fitted equation on the chart." },
3531
- showR2: { type: "boolean", description: "Write R\xB2 on the chart." },
3532
- name: { type: "string", description: 'Legend name (default e.g. "Linear (Sales)").' },
3533
- color: { type: "string", description: "CSS colour (default: the series colour)." }
3534
- };
3535
- var SERIES_PROPS = {
3536
- name: { type: "string", description: "Series name (legend and data grid header)." },
3537
- values: { type: "array", items: VALUE, description: "One value per category, in category order (padded with gaps)." },
3538
- color: { type: ["string", "null"], description: "CSS colour, or null for the palette colour." },
3539
- type: { type: ["string", "null"], enum: [..._chunkNEOO6QJDcjs.CHART_SERIES_TYPES, null], description: "Draw this series as bar, line, area or scatter (a combo chart); null follows the chart type." },
3540
- hidden: { type: "boolean", description: "Hide the series (its data is kept)." },
3541
- axis: { type: ["string", "null"], enum: ["primary", "secondary", null], description: "Value axis: secondary is drawn on the right with its own scale." },
3542
- x: { type: ["array", "null"], items: VALUE, description: "Numeric x per category, for scatter and bubble charts." },
3543
- sizes: { type: ["array", "null"], items: VALUE, description: "Bubble sizes per category (area is proportional to size)." },
3544
- pointColors: { type: ["array", "null"], items: { type: ["string", "null"] }, description: "Colour per category (null keeps the series colour)." },
3545
- marker: { type: ["string", "null"], enum: [..._chunkNEOO6QJDcjs.CHART_MARKERS, null], description: "Point marker shape for line, area and scatter series." },
3546
- curve: { type: ["string", "null"], enum: [..._chunkNEOO6QJDcjs.CHART_CURVES, null], description: "Line shape for this series: linear, smooth or step." },
3547
- dataLabels: { type: ["boolean", "null"], description: "Value labels for this series (null follows the chart)." },
3548
- format: { ...FORMAT, type: ["object", "null"], description: "How this series' labels are written (null follows the value axis)." }
3549
- };
3550
- var CHART_UPDATE_PROPERTIES = {
3551
- type: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_TYPES], description: "Chart type." },
3552
- title: { type: "string", description: 'Title ("" for none).' },
3553
- subtitle: { type: "string", description: 'Subtitle ("" for none).' },
3554
- xAxis: AXIS("Category axis (or numeric x axis of scatter / bubble charts)."),
3555
- yAxis: AXIS("Value axis."),
3556
- yAxis2: AXIS('Secondary value axis (for series with axis "secondary").'),
3557
- legend: {
3558
- type: "object",
3559
- description: "Legend.",
3560
- properties: { show: { type: "boolean", description: "Show the legend." }, position: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_LEGEND_POSITIONS], description: "Where the legend goes." } },
3561
- additionalProperties: false
3562
- },
3563
- stacking: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_STACKINGS], description: "none, stacked, or percent (each category scaled to 100%)." },
3564
- orientation: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_ORIENTATIONS], description: "horizontal draws bars sideways." },
3565
- curve: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_CURVES], description: "Line shape: linear, smooth or step." },
3566
- points: { type: "boolean", description: "Dots on line and area series." },
3567
- dataLabels: { type: "boolean", description: "Value labels on bars, points and slices." },
3568
- labelPosition: { type: "string", enum: [..._chunkNEOO6QJDcjs.CHART_LABEL_POSITIONS], description: "Bar label position; auto drops labels that do not fit." },
3569
- palette: { type: "array", items: { type: "string" }, minItems: 1, description: "Series colours in order (CSS colours)." },
3570
- innerRadius: { type: "number", minimum: 0, maximum: 0.9, description: "Donut hole as a fraction of the radius." },
3571
- gapWidth: { type: "number", minimum: 0, maximum: 0.9, description: "Space between bar groups as a fraction of the category (default 0.28)." },
3572
- overlap: { type: "number", minimum: -1, maximum: 1, description: "Bar overlap within a group as a fraction of a bar (negative: a gap; default -0.12)." },
3573
- bins: { type: ["integer", "null"], minimum: 1, maximum: 500, description: "Histogram bin count, or null for \u221An." },
3574
- showTotal: { type: "boolean", description: "Waterfall: append a total bar." }
3575
- };
3576
-
3577
251
  // src/chart/commands.ts
3578
- var fail2 = (message) => {
252
+ var fail = (message) => {
3579
253
  throw new Error(message);
3580
254
  };
3581
255
  var check = (result) => {
3582
- if (!result.ok) fail2(_nullishCoalesce(result.message, () => ( "The change was rejected.")));
256
+ if (!result.ok) fail(_nullishCoalesce(result.message, () => ( "The change was rejected.")));
3583
257
  };
3584
258
  function createChartCommands(controller, options = {}) {
3585
259
  const prefix = _nullishCoalesce(options.prefix, () => ( "chart."));
@@ -3588,13 +262,13 @@ function createChartCommands(controller, options = {}) {
3588
262
  const resolveSeries = (ref) => {
3589
263
  const spec = controller.getSpec();
3590
264
  const series = _nullishCoalesce(spec.series.find((s) => s.id === ref), () => ( spec.series.find((s) => s.name === ref)));
3591
- if (!series) fail2(`There is no series "${ref}"; expected one of ${seriesIds().map((id) => `"${id}"`).join(", ") || "(none yet)"}.`);
265
+ if (!series) fail(`There is no series "${ref}"; expected one of ${seriesIds().map((id) => `"${id}"`).join(", ") || "(none yet)"}.`);
3592
266
  return series;
3593
267
  };
3594
268
  const resolveCategory = (ref) => {
3595
269
  const categories = controller.getSpec().categories;
3596
270
  const index = typeof ref === "number" ? ref : categories.indexOf(ref);
3597
- if (index < 0 || index >= categories.length || !Number.isInteger(index)) fail2(`There is no category ${JSON.stringify(ref)}; expected an index from 0 to ${categories.length - 1} or one of the labels.`);
271
+ if (index < 0 || index >= categories.length || !Number.isInteger(index)) fail(`There is no category ${JSON.stringify(ref)}; expected an index from 0 to ${categories.length - 1} or one of the labels.`);
3598
272
  return index;
3599
273
  };
3600
274
  const object = (properties, required) => ({ type: "object", properties, ...required ? { required } : {}, additionalProperties: false });
@@ -3606,10 +280,10 @@ function createChartCommands(controller, options = {}) {
3606
280
  readOnly: true,
3607
281
  keywords: ["chart", "data", "spec", "get", "summary"],
3608
282
  description: "Returns the chart spec, its data as a table (series names in the header row) and a summary: per-series min / max / mean / trend, axes as drawn, layout warnings and a colour check.",
3609
- params: object({ width: WIDTH, height: HEIGHT }),
283
+ params: object({ width: _chunkTGBCBQFVcjs.WIDTH, height: _chunkTGBCBQFVcjs.HEIGHT }),
3610
284
  run: (_ctx, params = {}) => {
3611
285
  const spec = controller.getSpec();
3612
- return { spec: controller.toJSON(), table: _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, spec), summary: summarizeChart(controller.toJSON(), { width: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _88 => _88.width]), () => ( 640)), height: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _89 => _89.height]), () => ( 400)) }), issues: controller.getState().issues };
286
+ return { spec: controller.toJSON(), table: _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, spec), summary: _chunkGTZXF4BIcjs.summarizeChart.call(void 0, controller.toJSON(), { width: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _9 => _9.width]), () => ( 640)), height: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _10 => _10.height]), () => ( 400)) }), issues: controller.getState().issues };
3613
287
  }
3614
288
  },
3615
289
  {
@@ -3618,7 +292,7 @@ function createChartCommands(controller, options = {}) {
3618
292
  label: "Change Chart\u2026",
3619
293
  keywords: ["chart", "title", "axis", "legend", "stack", "style", "format", "type"],
3620
294
  description: "Changes chart presentation as one undo step: type, titles, axes (xAxis = categories, yAxis = values, yAxis2 = secondary values), legend, stacking, orientation, curve, points, data labels, palette, donut hole, bar spacing, histogram bins or waterfall total. Invalid values change nothing and return why.",
3621
- params: object(CHART_UPDATE_PROPERTIES),
295
+ params: object(_chunkTGBCBQFVcjs.CHART_UPDATE_PROPERTIES),
3622
296
  run: (_ctx, params) => {
3623
297
  check(controller.update(params));
3624
298
  return { spec: controller.toJSON() };
@@ -3632,11 +306,11 @@ function createChartCommands(controller, options = {}) {
3632
306
  description: "Replaces the categories and series as one undo step. Each series has one value per category (padded with gaps).",
3633
307
  params: object({
3634
308
  categories: { type: "array", items: { type: "string" }, description: "Category labels in order." },
3635
- series: { type: "array", description: "The new series.", items: object({ id: { type: "string", description: "Stable id (optional)." }, ...SERIES_PROPS }, ["name", "values"]) }
309
+ series: { type: "array", description: "The new series.", items: object({ id: { type: "string", description: "Stable id (optional)." }, ..._chunkTGBCBQFVcjs.SERIES_PROPS }, ["name", "values"]) }
3636
310
  }),
3637
311
  run: (_ctx, params) => {
3638
312
  check(controller.setData(params));
3639
- return { table: _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, controller.getSpec()) };
313
+ return { table: _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, controller.getSpec()) };
3640
314
  }
3641
315
  },
3642
316
  {
@@ -3645,10 +319,10 @@ function createChartCommands(controller, options = {}) {
3645
319
  label: "Set Chart Values\u2026",
3646
320
  keywords: ["chart", "value", "cell", "edit"],
3647
321
  description: "Sets individual values as one undo step. Series by id or name; category by index or label.",
3648
- params: object({ cells: { type: "array", minItems: 1, description: "Values to set.", items: object({ series: SERIES_REF, category: CATEGORY_REF, value: VALUE }, ["series", "category", "value"]) } }, ["cells"]),
322
+ params: object({ cells: { type: "array", minItems: 1, description: "Values to set.", items: object({ series: _chunkTGBCBQFVcjs.SERIES_REF, category: _chunkTGBCBQFVcjs.CATEGORY_REF, value: _chunkTGBCBQFVcjs.VALUE }, ["series", "category", "value"]) } }, ["cells"]),
3649
323
  run: (_ctx, params) => {
3650
324
  check(controller.setValues(params.cells.map((c) => ({ seriesId: resolveSeries(c.series).id, index: resolveCategory(c.category), value: c.value }))));
3651
- return { table: _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, controller.getSpec()) };
325
+ return { table: _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, controller.getSpec()) };
3652
326
  }
3653
327
  },
3654
328
  {
@@ -3657,11 +331,11 @@ function createChartCommands(controller, options = {}) {
3657
331
  label: "Add Series",
3658
332
  keywords: ["chart", "series", "new"],
3659
333
  description: "Adds a series (default: an empty one at the end). Returns its id.",
3660
- params: object({ ...SERIES_PROPS, id: { type: "string", description: "Id to use (default series-N)." }, at: { type: "integer", minimum: 0, description: "Position (default: last)." } }),
334
+ params: object({ ..._chunkTGBCBQFVcjs.SERIES_PROPS, id: { type: "string", description: "Id to use (default series-N)." }, at: { type: "integer", minimum: 0, description: "Position (default: last)." } }),
3661
335
  run: (_ctx, params = {}) => {
3662
336
  const { at, ...input } = _nullishCoalesce(params, () => ( {}));
3663
- const clean3 = Object.fromEntries(Object.entries(input).filter(([, v]) => v !== null));
3664
- const result = controller.addSeries(clean3, { at });
337
+ const clean = Object.fromEntries(Object.entries(input).filter(([, v]) => v !== null));
338
+ const result = controller.addSeries(clean, { at });
3665
339
  check(result);
3666
340
  return { id: result.id };
3667
341
  }
@@ -3672,7 +346,7 @@ function createChartCommands(controller, options = {}) {
3672
346
  label: "Change Series\u2026",
3673
347
  keywords: ["chart", "series", "rename", "colour", "color", "hide", "axis", "marker"],
3674
348
  description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (null resets a field).",
3675
- params: object({ series: SERIES_REF, ...Object.fromEntries(Object.entries(SERIES_PROPS).filter(([k]) => k !== "values")) }, ["series"]),
349
+ params: object({ series: _chunkTGBCBQFVcjs.SERIES_REF, ...Object.fromEntries(Object.entries(_chunkTGBCBQFVcjs.SERIES_PROPS).filter(([k]) => k !== "values")) }, ["series"]),
3676
350
  run: (_ctx, params) => {
3677
351
  const { series, ...patch } = params;
3678
352
  const id = resolveSeries(series).id;
@@ -3686,7 +360,7 @@ function createChartCommands(controller, options = {}) {
3686
360
  label: "Delete Series",
3687
361
  keywords: ["chart", "series", "remove"],
3688
362
  description: "Deletes a series by id or name.",
3689
- params: object({ series: SERIES_REF }, ["series"]),
363
+ params: object({ series: _chunkTGBCBQFVcjs.SERIES_REF }, ["series"]),
3690
364
  run: (_ctx, params) => {
3691
365
  check(controller.removeSeries(resolveSeries(params.series).id));
3692
366
  return { series: seriesIds() };
@@ -3699,7 +373,7 @@ function createChartCommands(controller, options = {}) {
3699
373
  keywords: ["chart", "category", "row", "label"],
3700
374
  description: "Inserts a category (gaps in every series) at `at` (default: the end).",
3701
375
  params: object({ label: { type: "string", description: "Category label (default: its number)." }, at: { type: "integer", minimum: 0, description: "Index to insert at (default: the end)." } }),
3702
- run: (_ctx, params = {}) => controller.addCategory(_optionalChain([params, 'optionalAccess', _90 => _90.label]), { at: _optionalChain([params, 'optionalAccess', _91 => _91.at]) })
376
+ run: (_ctx, params = {}) => controller.addCategory(_optionalChain([params, 'optionalAccess', _11 => _11.label]), { at: _optionalChain([params, 'optionalAccess', _12 => _12.at]) })
3703
377
  },
3704
378
  {
3705
379
  ...base,
@@ -3707,7 +381,7 @@ function createChartCommands(controller, options = {}) {
3707
381
  label: "Delete Category",
3708
382
  keywords: ["chart", "category", "row", "remove"],
3709
383
  description: "Deletes a category (and its values) by index or label.",
3710
- params: object({ category: CATEGORY_REF }, ["category"]),
384
+ params: object({ category: _chunkTGBCBQFVcjs.CATEGORY_REF }, ["category"]),
3711
385
  run: (_ctx, params) => {
3712
386
  check(controller.removeCategory(resolveCategory(params.category)));
3713
387
  return { categories: controller.getSpec().categories };
@@ -3719,7 +393,7 @@ function createChartCommands(controller, options = {}) {
3719
393
  label: "Add Trendline\u2026",
3720
394
  keywords: ["chart", "trend", "regression", "fit", "forecast", "moving average"],
3721
395
  description: "Fits a trendline to a series (linear, exponential, logarithmic, power, polynomial or moving average). Returns its index and the fit.",
3722
- params: object({ series: SERIES_REF, ...TRENDLINE_PROPS }, ["series", "type"]),
396
+ params: object({ series: _chunkTGBCBQFVcjs.SERIES_REF, ..._chunkTGBCBQFVcjs.TRENDLINE_PROPS }, ["series", "type"]),
3723
397
  run: (_ctx, params) => {
3724
398
  const { series, ...line } = params;
3725
399
  const result = controller.addTrendline(resolveSeries(series).id, line);
@@ -3734,10 +408,10 @@ function createChartCommands(controller, options = {}) {
3734
408
  label: "Delete Trendline",
3735
409
  keywords: ["chart", "trend", "remove"],
3736
410
  description: "Deletes a trendline from a series.",
3737
- params: object({ series: SERIES_REF, index: { type: "integer", minimum: 0, description: "Trendline index (0 = first)." } }, ["series", "index"]),
411
+ params: object({ series: _chunkTGBCBQFVcjs.SERIES_REF, index: { type: "integer", minimum: 0, description: "Trendline index (0 = first)." } }, ["series", "index"]),
3738
412
  run: (_ctx, params) => {
3739
413
  check(controller.removeTrendline(resolveSeries(params.series).id, params.index));
3740
- return { trendlines: _nullishCoalesce(_optionalChain([controller, 'access', _92 => _92.getSeries, 'call', _93 => _93(resolveSeries(params.series).id), 'optionalAccess', _94 => _94.trendlines]), () => ( [])) };
414
+ return { trendlines: _nullishCoalesce(_optionalChain([controller, 'access', _13 => _13.getSeries, 'call', _14 => _14(resolveSeries(params.series).id), 'optionalAccess', _15 => _15.trendlines]), () => ( [])) };
3741
415
  }
3742
416
  },
3743
417
  {
@@ -3747,8 +421,8 @@ function createChartCommands(controller, options = {}) {
3747
421
  keywords: ["chart", "quick layout", "style", "colours", "colors", "monochrome", "theme"],
3748
422
  description: "Applies a quick layout and / or colour scheme as one undo step.",
3749
423
  params: object({
3750
- layout: { type: "string", enum: CHART_LAYOUT_PRESETS.map((p) => p.id), description: "Quick layout id." },
3751
- colors: { type: "string", enum: CHART_COLOR_SCHEMES.map((p) => p.id), description: "Colour scheme id." }
424
+ layout: { type: "string", enum: _chunkGTZXF4BIcjs.CHART_LAYOUT_PRESETS.map((p) => p.id), description: "Quick layout id." },
425
+ colors: { type: "string", enum: _chunkGTZXF4BIcjs.CHART_COLOR_SCHEMES.map((p) => p.id), description: "Colour scheme id." }
3752
426
  }),
3753
427
  run: (_ctx, params = {}) => {
3754
428
  check(controller.applyPreset(_nullishCoalesce(params, () => ( {}))));
@@ -3763,7 +437,7 @@ function createChartCommands(controller, options = {}) {
3763
437
  description: "Swaps series and categories as one undo step.",
3764
438
  run: () => {
3765
439
  check(controller.transpose());
3766
- return { table: _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, controller.getSpec()) };
440
+ return { table: _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, controller.getSpec()) };
3767
441
  }
3768
442
  },
3769
443
  {
@@ -3783,7 +457,7 @@ function createChartCommands(controller, options = {}) {
3783
457
  run: (_ctx, params) => {
3784
458
  const result = controller.importCsv(params.csv, { seriesIn: params.seriesIn, header: params.header });
3785
459
  check(result);
3786
- return { table: _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, controller.getSpec()), issues: _nullishCoalesce(result.issues, () => ( [])) };
460
+ return { table: _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, controller.getSpec()), issues: _nullishCoalesce(result.issues, () => ( [])) };
3787
461
  }
3788
462
  },
3789
463
  {
@@ -3794,8 +468,8 @@ function createChartCommands(controller, options = {}) {
3794
468
  description: "Replaces the chart with Mermaid xychart-beta, pie or radar-beta text (one undo step). Unreadable lines are listed with line numbers.",
3795
469
  params: object({ mermaid: { type: "string", description: "Mermaid text." } }, ["mermaid"]),
3796
470
  run: (_ctx, params) => {
3797
- const read = chartFromMermaid(params.mermaid);
3798
- if (!read.family) fail2(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie or radar-beta.");
471
+ const read = _chunkGTZXF4BIcjs.chartFromMermaid.call(void 0, params.mermaid);
472
+ if (!read.family) fail(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie or radar-beta.");
3799
473
  check(controller.update({ ...read.spec }, { label: "Import Mermaid chart" }));
3800
474
  return { spec: controller.toJSON(), issues: read.issues };
3801
475
  }
@@ -3808,7 +482,7 @@ function createChartCommands(controller, options = {}) {
3808
482
  keywords: ["chart", "mermaid", "markdown", "export"],
3809
483
  description: "Returns the chart as Mermaid text (with a round-trip comment unless meta is false).",
3810
484
  params: object({ meta: { type: "boolean", description: "Include the %% @pixerate round-trip comment (default true)." } }),
3811
- run: (_ctx, params = {}) => ({ mermaid: chartToMermaid(controller.toJSON(), { meta: _optionalChain([params, 'optionalAccess', _95 => _95.meta]) }) })
485
+ run: (_ctx, params = {}) => ({ mermaid: _chunkGTZXF4BIcjs.chartToMermaid.call(void 0, controller.toJSON(), { meta: _optionalChain([params, 'optionalAccess', _16 => _16.meta]) }) })
3812
486
  },
3813
487
  {
3814
488
  ...base,
@@ -3817,7 +491,7 @@ function createChartCommands(controller, options = {}) {
3817
491
  readOnly: true,
3818
492
  keywords: ["chart", "office", "word", "powerpoint", "docx", "pptx", "xml", "export"],
3819
493
  description: "Returns the chart as a DrawingML chart part (c:chartSpace) and what could not be written.",
3820
- run: () => _chunkNEOO6QJDcjs.chartToOoxml.call(void 0, controller.toJSON())
494
+ run: () => _chunk3JNRQVTScjs.chartToOoxml.call(void 0, controller.toJSON())
3821
495
  },
3822
496
  {
3823
497
  ...base,
@@ -3826,9 +500,9 @@ function createChartCommands(controller, options = {}) {
3826
500
  readOnly: true,
3827
501
  keywords: ["chart", "svg", "export", "image"],
3828
502
  description: "Returns the chart drawn as a standalone, accessible SVG string (with <title> and <desc>).",
3829
- params: object({ width: WIDTH, height: HEIGHT }),
503
+ params: object({ width: _chunkTGBCBQFVcjs.WIDTH, height: _chunkTGBCBQFVcjs.HEIGHT }),
3830
504
  run: (_ctx, params = {}) => ({
3831
- svg: chartToSvg(controller.toJSON(), { width: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _96 => _96.width]), () => ( 640)), height: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _97 => _97.height]), () => ( 400)) })
505
+ svg: _chunkGTZXF4BIcjs.chartToSvg.call(void 0, controller.toJSON(), { width: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _17 => _17.width]), () => ( 640)), height: _nullishCoalesce(_optionalChain([params, 'optionalAccess', _18 => _18.height]), () => ( 400)) })
3832
506
  })
3833
507
  },
3834
508
  {
@@ -3840,7 +514,7 @@ function createChartCommands(controller, options = {}) {
3840
514
  description: "Suggests chart types for the current data (or CSV), best first, each with a reason.",
3841
515
  params: object({ csv: { type: "string", description: "CSV text to analyse instead of the current data." } }),
3842
516
  run: (_ctx, params = {}) => ({
3843
- recommendations: recommendChartTypes(_optionalChain([params, 'optionalAccess', _98 => _98.csv]) !== void 0 ? _chunkTNNJXF46cjs.parseCsv.call(void 0, params.csv) : _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, controller.getSpec()))
517
+ recommendations: recommendChartTypes(_optionalChain([params, 'optionalAccess', _19 => _19.csv]) !== void 0 ? _chunkTNNJXF46cjs.parseCsv.call(void 0, params.csv) : _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, controller.getSpec()))
3844
518
  })
3845
519
  },
3846
520
  {
@@ -3853,8 +527,8 @@ function createChartCommands(controller, options = {}) {
3853
527
  run: () => {
3854
528
  const s = controller.getSpec();
3855
529
  const visible = s.series.filter((x) => !x.hidden);
3856
- const colors = _chunkNEOO6QJDcjs.chartColorsByCategory.call(void 0, s.type) ? s.categories.map((_, i) => _optionalChain([visible, 'access', _99 => _99[0], 'optionalAccess', _100 => _100.pointColors, 'optionalAccess', _101 => _101[i]]) || _chunkNEOO6QJDcjs.chartSliceColor.call(void 0, s, i)) : visible.map((x) => _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, s, s.series.indexOf(x)));
3857
- return { colors, ..._chunkNEOO6QJDcjs.checkChartColors.call(void 0, colors) };
530
+ const colors = _chunkJOX6MJW4cjs.chartColorsByCategory.call(void 0, s.type) ? s.categories.map((_, i) => _optionalChain([visible, 'access', _20 => _20[0], 'optionalAccess', _21 => _21.pointColors, 'optionalAccess', _22 => _22[i]]) || _chunkJOX6MJW4cjs.chartSliceColor.call(void 0, s, i)) : visible.map((x) => _chunkJOX6MJW4cjs.chartSeriesColor.call(void 0, s, s.series.indexOf(x)));
531
+ return { colors, ..._chunkJOX6MJW4cjs.checkChartColors.call(void 0, colors) };
3858
532
  }
3859
533
  },
3860
534
  {
@@ -3883,9 +557,9 @@ function chartClientToScene(scene, box, clientX, clientY) {
3883
557
  return { x: (clientX - box.left) * sx, y: (clientY - box.top) * sy };
3884
558
  }
3885
559
  function canDragChartPoint(controller, scene, target) {
3886
- if (_optionalChain([target, 'optionalAccess', _102 => _102.kind]) !== "point" || !scene.valueScale || scene.percent) return false;
560
+ if (_optionalChain([target, 'optionalAccess', _23 => _23.kind]) !== "point" || !scene.valueScale || scene.percent) return false;
3887
561
  const spec = controller.getSpec();
3888
- const family = _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec);
562
+ const family = _chunkJOX6MJW4cjs.chartFamily.call(void 0, spec);
3889
563
  if (family !== "cartesian" && family !== "xy" && family !== "waterfall") return false;
3890
564
  const series = controller.getSeries(target.seriesId);
3891
565
  return !!series && !series.hidden && series.values[target.index] !== null;
@@ -3894,7 +568,7 @@ function snapChartDragValue(scene, value, options = {}) {
3894
568
  const scale = _nullishCoalesce(options.scale, () => ( scene.valueScale));
3895
569
  const tolerance = _nullishCoalesce(options.tolerancePx, () => ( 6));
3896
570
  if (scale) {
3897
- const px = (v) => linearMap(v, scale.domain, scale.range);
571
+ const px = (v) => _chunkGTZXF4BIcjs.linearMap.call(void 0, v, scale.domain, scale.range);
3898
572
  const at = px(value);
3899
573
  let best = null;
3900
574
  let bestDist = tolerance;
@@ -3908,7 +582,7 @@ function snapChartDragValue(scene, value, options = {}) {
3908
582
  }
3909
583
  if (best !== null) return best;
3910
584
  }
3911
- return snapChartValue(scene, value, options.step, _optionalChain([scale, 'optionalAccess', _103 => _103.ticks]));
585
+ return _chunkGTZXF4BIcjs.snapChartValue.call(void 0, scene, value, options.step, _optionalChain([scale, 'optionalAccess', _24 => _24.ticks]));
3912
586
  }
3913
587
  function startChartPointDrag(controller, scene, target, start, options = {}) {
3914
588
  if (!canDragChartPoint(controller, scene, target)) return null;
@@ -3917,11 +591,11 @@ function startChartPointDrag(controller, scene, target, start, options = {}) {
3917
591
  const series = controller.getSeries(seriesId);
3918
592
  const secondary = series.axis === "secondary" && !!scene.valueScale2;
3919
593
  const scale = secondary ? scene.valueScale2 : scene.valueScale;
3920
- const xy = _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec) === "xy" && !!scene.xScale;
594
+ const xy = _chunkJOX6MJW4cjs.chartFamily.call(void 0, spec) === "xy" && !!scene.xScale;
3921
595
  const startValue = _nullishCoalesce(series.values[index], () => ( 0));
3922
- const startX = _nullishCoalesce(_optionalChain([series, 'access', _104 => _104.x, 'optionalAccess', _105 => _105[index]]), () => ( null));
3923
- const startAt = chartValueAtPoint(scene, start, secondary);
3924
- const startAtX = xy ? chartXAtPoint(scene, start) : void 0;
596
+ const startX = _nullishCoalesce(_optionalChain([series, 'access', _25 => _25.x, 'optionalAccess', _26 => _26[index]]), () => ( null));
597
+ const startAt = _chunkGTZXF4BIcjs.chartValueAtPoint.call(void 0, scene, start, secondary);
598
+ const startAtX = xy ? _chunkGTZXF4BIcjs.chartXAtPoint.call(void 0, scene, start) : void 0;
3925
599
  if (startAt === void 0) return null;
3926
600
  const candidates = [0, startValue];
3927
601
  if (!xy) {
@@ -3939,34 +613,34 @@ function startChartPointDrag(controller, scene, target, start, options = {}) {
3939
613
  target: { seriesId, index },
3940
614
  move(point, moveOptions = {}) {
3941
615
  if (ended) return;
3942
- const at = chartValueAtPoint(scene, point, secondary);
616
+ const at = _chunkGTZXF4BIcjs.chartValueAtPoint.call(void 0, scene, point, secondary);
3943
617
  if (at === void 0) return;
3944
618
  const factor = moveOptions.fine ? 0.1 : 1;
3945
619
  let dy = (at - startAt) * factor;
3946
620
  let dx = 0;
3947
621
  if (xy && startX !== null && startAtX !== void 0) {
3948
- const atX = chartXAtPoint(scene, point);
622
+ const atX = _chunkGTZXF4BIcjs.chartXAtPoint.call(void 0, scene, point);
3949
623
  if (atX !== void 0) dx = (atX - startAtX) * factor;
3950
624
  if (moveOptions.lockAxis) {
3951
625
  if (Math.abs(point.x - start.x) >= Math.abs(point.y - start.y)) dy = 0;
3952
626
  else dx = 0;
3953
627
  }
3954
628
  }
3955
- const snap2 = (v, s, c) => {
629
+ const snap = (v, s, c) => {
3956
630
  if (moveOptions.noSnap) return Number(v.toPrecision(12));
3957
631
  if (moveOptions.fine) {
3958
632
  const unit = options.step ? options.step / 10 : s.ticks.length > 1 ? (s.ticks[1] - s.ticks[0]) / 100 : void 0;
3959
- return snapChartValue(scene, v, unit, s.ticks);
633
+ return _chunkGTZXF4BIcjs.snapChartValue.call(void 0, scene, v, unit, s.ticks);
3960
634
  }
3961
635
  return snapChartDragValue(scene, v, { candidates: c, tolerancePx: options.tolerancePx, step: options.step, scale: s });
3962
636
  };
3963
- const y = snap2(startValue + dy, scale, candidates);
637
+ const y = snap(startValue + dy, scale, candidates);
3964
638
  if (xy && startX !== null) {
3965
- const x = dx !== 0 ? snap2(startX + dx, scene.xScale, [0, startX]) : startX;
639
+ const x = dx !== 0 ? snap(startX + dx, scene.xScale, [0, startX]) : startX;
3966
640
  const xs = [..._nullishCoalesce(series.x, () => ( []))];
3967
641
  xs[index] = x;
3968
642
  controller.setValue(seriesId, index, y, { label });
3969
- if (x !== _optionalChain([controller, 'access', _106 => _106.getSeries, 'call', _107 => _107(seriesId), 'optionalAccess', _108 => _108.x, 'optionalAccess', _109 => _109[index]])) controller.updateSeries(seriesId, { x: xs });
643
+ if (x !== _optionalChain([controller, 'access', _27 => _27.getSeries, 'call', _28 => _28(seriesId), 'optionalAccess', _29 => _29.x, 'optionalAccess', _30 => _30[index]])) controller.updateSeries(seriesId, { x: xs });
3970
644
  } else controller.setValue(seriesId, index, y, { label });
3971
645
  },
3972
646
  end() {
@@ -4000,7 +674,7 @@ function handleChartKey(controller, scene, event) {
4000
674
  return true;
4001
675
  case "ArrowLeft":
4002
676
  case "ArrowRight": {
4003
- if (event.altKey || _optionalChain([selection, 'optionalAccess', _110 => _110.kind]) !== "point" && _optionalChain([selection, 'optionalAccess', _111 => _111.kind]) !== "category") return false;
677
+ if (event.altKey || _optionalChain([selection, 'optionalAccess', _31 => _31.kind]) !== "point" && _optionalChain([selection, 'optionalAccess', _32 => _32.kind]) !== "category") return false;
4004
678
  const n = spec.categories.length;
4005
679
  const index = Math.max(0, Math.min(n - 1, selection.index + (event.key === "ArrowRight" ? 1 : -1)));
4006
680
  controller.select({ ...selection, index });
@@ -4008,9 +682,9 @@ function handleChartKey(controller, scene, event) {
4008
682
  }
4009
683
  case "ArrowUp":
4010
684
  case "ArrowDown": {
4011
- if (_optionalChain([selection, 'optionalAccess', _112 => _112.kind]) !== "point" || _optionalChain([scene, 'optionalAccess', _113 => _113.percent])) return false;
4012
- const secondary = _optionalChain([controller, 'access', _114 => _114.getSeries, 'call', _115 => _115(selection.seriesId), 'optionalAccess', _116 => _116.axis]) === "secondary";
4013
- const ticks = _nullishCoalesce(_nullishCoalesce(_optionalChain([(secondary ? _optionalChain([scene, 'optionalAccess', _117 => _117.valueScale2]) : null), 'optionalAccess', _118 => _118.ticks]), () => ( _optionalChain([scene, 'optionalAccess', _119 => _119.valueScale, 'optionalAccess', _120 => _120.ticks]))), () => ( []));
685
+ if (_optionalChain([selection, 'optionalAccess', _33 => _33.kind]) !== "point" || _optionalChain([scene, 'optionalAccess', _34 => _34.percent])) return false;
686
+ const secondary = _optionalChain([controller, 'access', _35 => _35.getSeries, 'call', _36 => _36(selection.seriesId), 'optionalAccess', _37 => _37.axis]) === "secondary";
687
+ const ticks = _nullishCoalesce(_nullishCoalesce(_optionalChain([(secondary ? _optionalChain([scene, 'optionalAccess', _38 => _38.valueScale2]) : null), 'optionalAccess', _39 => _39.ticks]), () => ( _optionalChain([scene, 'optionalAccess', _40 => _40.valueScale, 'optionalAccess', _41 => _41.ticks]))), () => ( []));
4014
688
  const step = ticks.length > 1 ? ticks[1] - ticks[0] : 1;
4015
689
  const amount = event.shiftKey ? step : event.altKey ? step / 100 : step / 10;
4016
690
  controller.nudgeValue(selection.seriesId, selection.index, amount * (event.key === "ArrowUp" ? 1 : -1));
@@ -4033,22 +707,22 @@ function describeChartSelection(controller, selection = controller.getState().se
4033
707
  case "legend":
4034
708
  return "Legend";
4035
709
  case "axis":
4036
- return selection.axis === "x" ? _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec) === "xy" ? "X axis" : "Category axis" : selection.axis === "y" ? "Value axis" : "Secondary value axis";
710
+ return selection.axis === "x" ? _chunkJOX6MJW4cjs.chartFamily.call(void 0, spec) === "xy" ? "X axis" : "Category axis" : selection.axis === "y" ? "Value axis" : "Secondary value axis";
4037
711
  case "series":
4038
- return `Series "${_nullishCoalesce(_optionalChain([controller, 'access', _121 => _121.getSeries, 'call', _122 => _122(selection.seriesId), 'optionalAccess', _123 => _123.name]), () => ( selection.seriesId))}"`;
712
+ return `Series "${_nullishCoalesce(_optionalChain([controller, 'access', _42 => _42.getSeries, 'call', _43 => _43(selection.seriesId), 'optionalAccess', _44 => _44.name]), () => ( selection.seriesId))}"`;
4039
713
  case "category":
4040
714
  return `Category "${_nullishCoalesce(spec.categories[selection.index], () => ( selection.index))}"`;
4041
715
  case "trendline": {
4042
716
  const series = controller.getSeries(selection.seriesId);
4043
- const line = _optionalChain([series, 'optionalAccess', _124 => _124.trendlines, 'optionalAccess', _125 => _125[selection.index]]);
4044
- return `${line ? line.type.replace("-", " ") : "Trendline"} trendline on "${_nullishCoalesce(_optionalChain([series, 'optionalAccess', _126 => _126.name]), () => ( selection.seriesId))}"`;
717
+ const line = _optionalChain([series, 'optionalAccess', _45 => _45.trendlines, 'optionalAccess', _46 => _46[selection.index]]);
718
+ return `${line ? line.type.replace("-", " ") : "Trendline"} trendline on "${_nullishCoalesce(_optionalChain([series, 'optionalAccess', _47 => _47.name]), () => ( selection.seriesId))}"`;
4045
719
  }
4046
720
  case "point": {
4047
721
  const series = controller.getSeries(selection.seriesId);
4048
- const value = _optionalChain([series, 'optionalAccess', _127 => _127.values, 'access', _128 => _128[selection.index]]);
4049
- const x = _optionalChain([series, 'optionalAccess', _129 => _129.x, 'optionalAccess', _130 => _130[selection.index]]);
4050
- if (x !== void 0 && x !== null && _chunkNEOO6QJDcjs.chartFamily.call(void 0, spec) === "xy") return `${_nullishCoalesce(_optionalChain([series, 'optionalAccess', _131 => _131.name]), () => ( selection.seriesId))}: (${x}, ${_nullishCoalesce(value, () => ( "blank"))})`;
4051
- return `${_nullishCoalesce(_optionalChain([series, 'optionalAccess', _132 => _132.name]), () => ( selection.seriesId))} \xB7 ${_nullishCoalesce(spec.categories[selection.index], () => ( selection.index))}: ${_nullishCoalesce(value, () => ( "blank"))}`;
722
+ const value = _optionalChain([series, 'optionalAccess', _48 => _48.values, 'access', _49 => _49[selection.index]]);
723
+ const x = _optionalChain([series, 'optionalAccess', _50 => _50.x, 'optionalAccess', _51 => _51[selection.index]]);
724
+ if (x !== void 0 && x !== null && _chunkJOX6MJW4cjs.chartFamily.call(void 0, spec) === "xy") return `${_nullishCoalesce(_optionalChain([series, 'optionalAccess', _52 => _52.name]), () => ( selection.seriesId))}: (${x}, ${_nullishCoalesce(value, () => ( "blank"))})`;
725
+ return `${_nullishCoalesce(_optionalChain([series, 'optionalAccess', _53 => _53.name]), () => ( selection.seriesId))} \xB7 ${_nullishCoalesce(spec.categories[selection.index], () => ( selection.index))}: ${_nullishCoalesce(value, () => ( "blank"))}`;
4052
726
  }
4053
727
  }
4054
728
  }
@@ -4093,11 +767,11 @@ var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, o
4093
767
  var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
4094
768
  var WRITE_IDEMPOTENT = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
4095
769
  var DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
4096
- var fail3 = (message) => {
770
+ var fail2 = (message) => {
4097
771
  throw new Error(message);
4098
772
  };
4099
773
  function resolve(result) {
4100
- if (!result.ok) fail3(_nullishCoalesce(result.message, () => ( "The change was rejected.")));
774
+ if (!result.ok) fail2(_nullishCoalesce(result.message, () => ( "The change was rejected.")));
4101
775
  return result;
4102
776
  }
4103
777
  function createChartToolProvider(controller, options = {}) {
@@ -4110,23 +784,23 @@ function createChartToolProvider(controller, options = {}) {
4110
784
  const spec = () => controller.getSpec();
4111
785
  const seriesById = (ref) => {
4112
786
  const s = _nullishCoalesce(spec().series.find((x) => x.id === ref), () => ( spec().series.find((x) => x.name === ref)));
4113
- if (!s) fail3(`There is no series "${ref}"; expected one of ${spec().series.map((x) => `"${x.id}" (${x.name})`).join(", ") || "(none yet; add one with add_chart_series)"}.`);
787
+ if (!s) fail2(`There is no series "${ref}"; expected one of ${spec().series.map((x) => `"${x.id}" (${x.name})`).join(", ") || "(none yet; add one with add_chart_series)"}.`);
4114
788
  return s;
4115
789
  };
4116
790
  const categoryIndex = (ref) => {
4117
791
  const categories = spec().categories;
4118
792
  const index = typeof ref === "number" ? ref : categories.indexOf(ref);
4119
793
  if (!Number.isInteger(index) || index < 0 || index >= categories.length)
4120
- fail3(`There is no category ${JSON.stringify(ref)}; expected an index from 0 to ${categories.length - 1} or one of ${categories.slice(0, 20).map((c) => JSON.stringify(c)).join(", ")}.`);
794
+ fail2(`There is no category ${JSON.stringify(ref)}; expected an index from 0 to ${categories.length - 1} or one of ${categories.slice(0, 20).map((c) => JSON.stringify(c)).join(", ")}.`);
4121
795
  return index;
4122
796
  };
4123
- const table = () => _chunkNEOO6QJDcjs.chartDataToTable.call(void 0, spec());
797
+ const table = () => _chunkJOX6MJW4cjs.chartDataToTable.call(void 0, spec());
4124
798
  const Parser = () => _nullishCoalesce(options.DOMParser, () => ( globalThis.DOMParser));
4125
799
  const getChart = {
4126
800
  name: "get_chart",
4127
801
  title: "Read the chart",
4128
802
  description: "Returns the chart spec (type, titles, axes, legend, series with ids and settings), its data as a table (header row of series names, then one row per category), the current selection, and a summary at the given size: per-series min / max / mean / trend, the axes as drawn, layout warnings (hidden labels, thinned lines), a colour check and a plain-language description. Use the series ids and category indexes it returns with the write tools.",
4129
- inputSchema: { type: "object", properties: { width: WIDTH, height: HEIGHT }, additionalProperties: false },
803
+ inputSchema: { type: "object", properties: { width: _chunkTGBCBQFVcjs.WIDTH, height: _chunkTGBCBQFVcjs.HEIGHT }, additionalProperties: false },
4130
804
  annotations: { title: "Read the chart", ...READ },
4131
805
  handler: ({ width = size.width, height = size.height }) => {
4132
806
  const reason = readOnlyReason();
@@ -4134,7 +808,7 @@ function createChartToolProvider(controller, options = {}) {
4134
808
  spec: controller.toJSON(),
4135
809
  table: table(),
4136
810
  selection: controller.getState().selection,
4137
- summary: summarizeChart(controller.toJSON(), { width, height }),
811
+ summary: _chunkGTZXF4BIcjs.summarizeChart.call(void 0, controller.toJSON(), { width, height }),
4138
812
  issues: controller.getState().issues,
4139
813
  ...reason ? { readOnly: reason } : {}
4140
814
  };
@@ -4146,14 +820,14 @@ function createChartToolProvider(controller, options = {}) {
4146
820
  description: 'Draws the chart without changing it, to check it visually: SVG text by default, or a PNG image (format "png") when the host can rasterize. Look for overlapping or hidden labels; get_chart lists layout warnings without a render.',
4147
821
  inputSchema: {
4148
822
  type: "object",
4149
- properties: { width: WIDTH, height: HEIGHT, format: { type: "string", enum: ["svg", "png"], description: "svg (default) or png (only when the host supports it)." } },
823
+ properties: { width: _chunkTGBCBQFVcjs.WIDTH, height: _chunkTGBCBQFVcjs.HEIGHT, format: { type: "string", enum: ["svg", "png"], description: "svg (default) or png (only when the host supports it)." } },
4150
824
  additionalProperties: false
4151
825
  },
4152
826
  annotations: { title: "Render the chart", ...READ },
4153
827
  handler: async ({ width = size.width, height = size.height, format = "svg" }) => {
4154
- const svg = chartToSvg(controller.toJSON(), { width, height });
828
+ const svg = _chunkGTZXF4BIcjs.chartToSvg.call(void 0, controller.toJSON(), { width, height });
4155
829
  if (format === "png") {
4156
- if (!options.rasterize) fail3('This host cannot rasterize charts; call render_chart with format "svg".');
830
+ if (!options.rasterize) fail2('This host cannot rasterize charts; call render_chart with format "svg".');
4157
831
  const image = await options.rasterize(svg, { width, height });
4158
832
  return { content: [{ type: "image", data: image.data, mimeType: image.mimeType }], structuredContent: { width, height, mimeType: image.mimeType } };
4159
833
  }
@@ -4176,8 +850,8 @@ function createChartToolProvider(controller, options = {}) {
4176
850
  handler: ({ colors, surface }) => {
4177
851
  const s = spec();
4178
852
  const visible = s.series.filter((x) => !x.hidden);
4179
- const own = _chunkNEOO6QJDcjs.chartColorsByCategory.call(void 0, s.type) ? s.categories.map((_, i) => _optionalChain([visible, 'access', _133 => _133[0], 'optionalAccess', _134 => _134.pointColors, 'optionalAccess', _135 => _135[i]]) || _chunkNEOO6QJDcjs.chartSliceColor.call(void 0, s, i)) : visible.map((x) => _chunkNEOO6QJDcjs.chartSeriesColor.call(void 0, s, s.series.indexOf(x)));
4180
- return { colors: _nullishCoalesce(colors, () => ( own)), ..._chunkNEOO6QJDcjs.checkChartColors.call(void 0, _nullishCoalesce(colors, () => ( own)), { surface }) };
853
+ const own = _chunkJOX6MJW4cjs.chartColorsByCategory.call(void 0, s.type) ? s.categories.map((_, i) => _optionalChain([visible, 'access', _54 => _54[0], 'optionalAccess', _55 => _55.pointColors, 'optionalAccess', _56 => _56[i]]) || _chunkJOX6MJW4cjs.chartSliceColor.call(void 0, s, i)) : visible.map((x) => _chunkJOX6MJW4cjs.chartSeriesColor.call(void 0, s, s.series.indexOf(x)));
854
+ return { colors: _nullishCoalesce(colors, () => ( own)), ..._chunkJOX6MJW4cjs.checkChartColors.call(void 0, _nullishCoalesce(colors, () => ( own)), { surface }) };
4181
855
  }
4182
856
  };
4183
857
  const recommend = {
@@ -4189,7 +863,7 @@ function createChartToolProvider(controller, options = {}) {
4189
863
  handler: ({ csv }) => {
4190
864
  const rows = csv !== void 0 ? _chunkTNNJXF46cjs.parseCsv.call(void 0, csv, { delimiter: csv.includes(" ") ? " " : "," }) : table();
4191
865
  const recommendations = recommendChartTypes(rows);
4192
- if (!recommendations.length) fail3("There are no numbers to chart: give CSV with at least one numeric column.");
866
+ if (!recommendations.length) fail2("There are no numbers to chart: give CSV with at least one numeric column.");
4193
867
  return { recommendations };
4194
868
  }
4195
869
  };
@@ -4199,18 +873,18 @@ function createChartToolProvider(controller, options = {}) {
4199
873
  description: "Returns a trendline's fitted coefficients (in x for category charts, x = 1, 2, 3, \u2026), R\xB2, equation and the number of points, or the moving-average points.",
4200
874
  inputSchema: {
4201
875
  type: "object",
4202
- properties: { series: SERIES_REF, index: { type: "integer", minimum: 0, description: "Trendline index on the series (0 = first)." } },
876
+ properties: { series: _chunkTGBCBQFVcjs.SERIES_REF, index: { type: "integer", minimum: 0, description: "Trendline index on the series (0 = first)." } },
4203
877
  required: ["series", "index"],
4204
878
  additionalProperties: false
4205
879
  },
4206
880
  annotations: { title: "Read a trendline fit", ...READ },
4207
881
  handler: ({ series, index }) => {
4208
882
  const s = seriesById(series);
4209
- const line = _optionalChain([s, 'access', _136 => _136.trendlines, 'optionalAccess', _137 => _137[index]]);
4210
- if (!line) fail3(`"${s.name}" has no trendline ${index}; it has ${_nullishCoalesce(_optionalChain([s, 'access', _138 => _138.trendlines, 'optionalAccess', _139 => _139.length]), () => ( 0))}.`);
883
+ const line = _optionalChain([s, 'access', _57 => _57.trendlines, 'optionalAccess', _58 => _58[index]]);
884
+ if (!line) fail2(`"${s.name}" has no trendline ${index}; it has ${_nullishCoalesce(_optionalChain([s, 'access', _59 => _59.trendlines, 'optionalAccess', _60 => _60.length]), () => ( 0))}.`);
4211
885
  if (line.type === "moving-average") return { trendline: line, points: controller.trendlineMovingAverage(s.id, index) };
4212
886
  const fit = controller.trendlineFit(s.id, index);
4213
- if (!fit) fail3(`The ${line.type} trendline on "${s.name}" cannot be fitted: it needs more points (and positive values for log, exponential and power fits).`);
887
+ if (!fit) fail2(`The ${line.type} trendline on "${s.name}" cannot be fitted: it needs more points (and positive values for log, exponential and power fits).`);
4214
888
  return { trendline: line, coefficients: fit.coefficients, r2: fit.r2, equation: fit.equation, points: fit.points };
4215
889
  }
4216
890
  };
@@ -4221,8 +895,8 @@ function createChartToolProvider(controller, options = {}) {
4221
895
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
4222
896
  annotations: { title: "List chart presets", ...READ },
4223
897
  handler: () => ({
4224
- layouts: CHART_LAYOUT_PRESETS.map(({ id, label, description }) => ({ id, label, description })),
4225
- colorSchemes: CHART_COLOR_SCHEMES.map(({ id, label, description, palette }) => ({ id, label, description, palette }))
898
+ layouts: _chunkGTZXF4BIcjs.CHART_LAYOUT_PRESETS.map(({ id, label, description }) => ({ id, label, description })),
899
+ colorSchemes: _chunkGTZXF4BIcjs.CHART_COLOR_SCHEMES.map(({ id, label, description, palette }) => ({ id, label, description, palette }))
4226
900
  })
4227
901
  };
4228
902
  const exportMermaid = {
@@ -4231,7 +905,7 @@ function createChartToolProvider(controller, options = {}) {
4231
905
  description: 'Returns the chart as Mermaid text (xychart-beta, pie or radar-beta) for Markdown or chat. With meta (default true) one "%% @pixerate {\u2026}" comment keeps what Mermaid cannot express, so import_chart_mermaid gets the chart back exactly.',
4232
906
  inputSchema: { type: "object", properties: { meta: { type: "boolean", description: "Include the round-trip comment (default true)." } }, additionalProperties: false },
4233
907
  annotations: { title: "Export chart as Mermaid", ...READ },
4234
- handler: ({ meta = true }) => ({ mermaid: chartToMermaid(controller.toJSON(), { meta }) })
908
+ handler: ({ meta = true }) => ({ mermaid: _chunkGTZXF4BIcjs.chartToMermaid.call(void 0, controller.toJSON(), { meta }) })
4235
909
  };
4236
910
  const exportOoxml = {
4237
911
  name: "export_chart_ooxml",
@@ -4239,7 +913,7 @@ function createChartToolProvider(controller, options = {}) {
4239
913
  description: "Returns the chart as a DrawingML chart part (c:chartSpace) for Word or PowerPoint files, with what could not be written as sentences.",
4240
914
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
4241
915
  annotations: { title: "Export chart as Office XML", ...READ },
4242
- handler: () => _chunkNEOO6QJDcjs.chartToOoxml.call(void 0, controller.toJSON())
916
+ handler: () => _chunk3JNRQVTScjs.chartToOoxml.call(void 0, controller.toJSON())
4243
917
  };
4244
918
  const updateChart = {
4245
919
  name: "update_chart",
@@ -4247,12 +921,12 @@ function createChartToolProvider(controller, options = {}) {
4247
921
  description: "Changes how the chart looks, as one undo step: type, titles, axes (xAxis = categories or numeric x, yAxis = values, yAxis2 = secondary values), legend, stacking, orientation, curve, points, data labels and their position, palette, donut hole, bar spacing, histogram bins, waterfall total. All-or-nothing: invalid values change nothing and come back as sentences. Returns the new spec.",
4248
922
  inputSchema: {
4249
923
  type: "object",
4250
- properties: CHART_UPDATE_PROPERTIES,
924
+ properties: _chunkTGBCBQFVcjs.CHART_UPDATE_PROPERTIES,
4251
925
  additionalProperties: false
4252
926
  },
4253
927
  annotations: { title: "Change chart presentation", ...WRITE_IDEMPOTENT },
4254
928
  handler: (args) => {
4255
- if (!Object.keys(args).length) fail3('Nothing to change: pass at least one field, e.g. {"type": "line"}.');
929
+ if (!Object.keys(args).length) fail2('Nothing to change: pass at least one field, e.g. {"type": "line"}.');
4256
930
  resolve(controller.update(args));
4257
931
  return { spec: controller.toJSON() };
4258
932
  }
@@ -4268,14 +942,14 @@ function createChartToolProvider(controller, options = {}) {
4268
942
  series: {
4269
943
  type: "array",
4270
944
  description: "The new series (replaces all).",
4271
- items: { type: "object", properties: { id: { type: "string", description: "Stable id (optional)." }, ...SERIES_PROPS }, required: ["name", "values"], additionalProperties: false }
945
+ items: { type: "object", properties: { id: { type: "string", description: "Stable id (optional)." }, ..._chunkTGBCBQFVcjs.SERIES_PROPS }, required: ["name", "values"], additionalProperties: false }
4272
946
  }
4273
947
  },
4274
948
  additionalProperties: false
4275
949
  },
4276
950
  annotations: { title: "Replace chart data", ...DESTRUCTIVE },
4277
951
  handler: (args) => {
4278
- if (!args.categories && !args.series) fail3("Pass categories, series or both.");
952
+ if (!args.categories && !args.series) fail2("Pass categories, series or both.");
4279
953
  resolve(controller.setData(args));
4280
954
  return { table: table(), series: spec().series.map((s) => ({ id: s.id, name: s.name })) };
4281
955
  }
@@ -4291,7 +965,7 @@ function createChartToolProvider(controller, options = {}) {
4291
965
  type: "array",
4292
966
  minItems: 1,
4293
967
  description: "Values to set.",
4294
- items: { type: "object", properties: { series: SERIES_REF, category: CATEGORY_REF, value: VALUE }, required: ["series", "category", "value"], additionalProperties: false }
968
+ items: { type: "object", properties: { series: _chunkTGBCBQFVcjs.SERIES_REF, category: _chunkTGBCBQFVcjs.CATEGORY_REF, value: _chunkTGBCBQFVcjs.VALUE }, required: ["series", "category", "value"], additionalProperties: false }
4295
969
  }
4296
970
  },
4297
971
  required: ["cells"],
@@ -4300,13 +974,13 @@ function createChartToolProvider(controller, options = {}) {
4300
974
  annotations: { title: "Set chart values", ...WRITE_IDEMPOTENT },
4301
975
  handler: async ({ cells }) => {
4302
976
  const resolved = cells.map((c) => ({ seriesId: seriesById(c.series).id, index: categoryIndex(c.category), value: c.value }));
4303
- const parsed = resolved.map((c) => _chunkNEOO6QJDcjs.parseChartValue.call(void 0, c.value));
977
+ const parsed = resolved.map((c) => _chunkJOX6MJW4cjs.parseChartValue.call(void 0, c.value));
4304
978
  const bad = resolved.find((_, i) => parsed[i] === void 0);
4305
- if (bad) fail3(`"${String(bad.value)}" is not a number; pass a number, numeric text or null for a gap. Nothing was changed.`);
979
+ if (bad) fail2(`"${String(bad.value)}" is not a number; pass a number, numeric text or null for a gap. Nothing was changed.`);
4306
980
  if (options.director && parsed.every((v) => typeof v === "number")) {
4307
981
  const results = await options.director.perform(_nullishCoalesce(options.actor, () => ( { id: "agent", name: "Agent" })), resolved.map((c, i) => ({ kind: "setValue", seriesId: c.seriesId, index: c.index, value: parsed[i] })));
4308
982
  const failed = results.find((r) => !r.ok);
4309
- if (failed && !failed.ok) fail3(failed.message);
983
+ if (failed && !failed.ok) fail2(failed.message);
4310
984
  } else resolve(controller.setValues(resolved));
4311
985
  return { cells: resolved.map((c) => ({ series: c.seriesId, category: spec().categories[c.index], index: c.index, value: controller.getSeries(c.seriesId).values[c.index] })) };
4312
986
  }
@@ -4317,14 +991,14 @@ function createChartToolProvider(controller, options = {}) {
4317
991
  description: "Adds a series (values padded to the categories) and selects it. Returns its id and stored values.",
4318
992
  inputSchema: {
4319
993
  type: "object",
4320
- properties: { ...SERIES_PROPS, id: { type: "string", description: "Id to use (default: series-N)." }, at: { type: "integer", minimum: 0, description: "Position (default: last)." } },
994
+ properties: { ..._chunkTGBCBQFVcjs.SERIES_PROPS, id: { type: "string", description: "Id to use (default: series-N)." }, at: { type: "integer", minimum: 0, description: "Position (default: last)." } },
4321
995
  required: ["name"],
4322
996
  additionalProperties: false
4323
997
  },
4324
998
  annotations: { title: "Add a series", ...WRITE },
4325
999
  handler: ({ at, ...input }) => {
4326
- const clean3 = Object.fromEntries(Object.entries(input).filter(([, v]) => v !== null));
4327
- const result = resolve(controller.addSeries(clean3, { at }));
1000
+ const clean = Object.fromEntries(Object.entries(input).filter(([, v]) => v !== null));
1001
+ const result = resolve(controller.addSeries(clean, { at }));
4328
1002
  const s = controller.getSeries(result.id);
4329
1003
  return { id: s.id, name: s.name, values: s.values };
4330
1004
  }
@@ -4335,14 +1009,14 @@ function createChartToolProvider(controller, options = {}) {
4335
1009
  description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (marker, curve, labels, format, x values, bubble sizes, point colours). null resets a field. Values change with set_chart_values. Returns the series.",
4336
1010
  inputSchema: {
4337
1011
  type: "object",
4338
- properties: { series: SERIES_REF, ...Object.fromEntries(Object.entries(SERIES_PROPS).filter(([k]) => k !== "values")) },
1012
+ properties: { series: _chunkTGBCBQFVcjs.SERIES_REF, ...Object.fromEntries(Object.entries(_chunkTGBCBQFVcjs.SERIES_PROPS).filter(([k]) => k !== "values")) },
4339
1013
  required: ["series"],
4340
1014
  additionalProperties: false
4341
1015
  },
4342
1016
  annotations: { title: "Change a series", ...WRITE_IDEMPOTENT },
4343
1017
  handler: ({ series, ...patch }) => {
4344
1018
  const id = seriesById(series).id;
4345
- if (!Object.keys(patch).length) fail3('Nothing to change: pass a field such as {"color": "#e8710a"} or {"axis": "secondary"}.');
1019
+ if (!Object.keys(patch).length) fail2('Nothing to change: pass a field such as {"color": "#e8710a"} or {"axis": "secondary"}.');
4346
1020
  resolve(controller.updateSeries(id, patch));
4347
1021
  return { series: controller.getSeries(id) };
4348
1022
  }
@@ -4351,7 +1025,7 @@ function createChartToolProvider(controller, options = {}) {
4351
1025
  name: "remove_chart_series",
4352
1026
  title: "Delete a series",
4353
1027
  description: "Deletes a series and its values. Returns the remaining series ids.",
4354
- inputSchema: { type: "object", properties: { series: SERIES_REF }, required: ["series"], additionalProperties: false },
1028
+ inputSchema: { type: "object", properties: { series: _chunkTGBCBQFVcjs.SERIES_REF }, required: ["series"], additionalProperties: false },
4355
1029
  annotations: { title: "Delete a series", ...DESTRUCTIVE },
4356
1030
  handler: ({ series }) => {
4357
1031
  resolve(controller.removeSeries(seriesById(series).id));
@@ -4377,7 +1051,7 @@ function createChartToolProvider(controller, options = {}) {
4377
1051
  name: "remove_chart_category",
4378
1052
  title: "Delete a category",
4379
1053
  description: "Deletes a category and its value in every series. Returns the remaining categories.",
4380
- inputSchema: { type: "object", properties: { category: CATEGORY_REF }, required: ["category"], additionalProperties: false },
1054
+ inputSchema: { type: "object", properties: { category: _chunkTGBCBQFVcjs.CATEGORY_REF }, required: ["category"], additionalProperties: false },
4381
1055
  annotations: { title: "Delete a category", ...DESTRUCTIVE },
4382
1056
  handler: ({ category }) => {
4383
1057
  resolve(controller.removeCategory(categoryIndex(category)));
@@ -4404,7 +1078,7 @@ function createChartToolProvider(controller, options = {}) {
4404
1078
  if (chartType === "auto") {
4405
1079
  const rows = _chunkTNNJXF46cjs.parseCsv.call(void 0, csv, { delimiter: csv.includes(" ") ? " " : "," });
4406
1080
  const built = chartFromTable(rows);
4407
- if (!built.series.length || !built.categories.length) fail3("There is no data to import: expected at least one row of numbers.");
1081
+ if (!built.series.length || !built.categories.length) fail2("There is no data to import: expected at least one row of numbers.");
4408
1082
  resolve(controller.update({ type: built.type, stacking: built.stacking, categories: built.categories, series: built.series }, { label: "Import data" }));
4409
1083
  return { type: built.type, table: table(), issues: built.issues };
4410
1084
  }
@@ -4420,8 +1094,8 @@ function createChartToolProvider(controller, options = {}) {
4420
1094
  annotations: { title: "Import a Mermaid chart", ...DESTRUCTIVE },
4421
1095
  handler: ({ mermaid }) => {
4422
1096
  const fenced = /```(?:mermaid)?\s*\n([\s\S]*?)```/.exec(mermaid);
4423
- const read = chartFromMermaid(fenced ? fenced[1] : mermaid);
4424
- if (!read.family) fail3(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie or radar-beta.");
1097
+ const read = _chunkGTZXF4BIcjs.chartFromMermaid.call(void 0, fenced ? fenced[1] : mermaid);
1098
+ if (!read.family) fail2(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie or radar-beta.");
4425
1099
  resolve(controller.update({ ...read.spec }, { label: "Import Mermaid chart" }));
4426
1100
  return { spec: controller.toJSON(), issues: read.issues };
4427
1101
  }
@@ -4433,8 +1107,8 @@ function createChartToolProvider(controller, options = {}) {
4433
1107
  inputSchema: { type: "object", properties: { xml: { type: "string", description: "The chart part XML, e.g. word/charts/chart1.xml." } }, required: ["xml"], additionalProperties: false },
4434
1108
  annotations: { title: "Import an Office chart", ...DESTRUCTIVE },
4435
1109
  handler: ({ xml }) => {
4436
- const read = _chunkNEOO6QJDcjs.chartFromOoxml.call(void 0, xml, { DOMParser: Parser() });
4437
- if (read.issues.some((i) => i.path === "" || i.path === "plotArea")) fail3(read.issues.map((i) => i.message).join(" "));
1110
+ const read = _chunk3JNRQVTScjs.chartFromOoxml.call(void 0, xml, { DOMParser: Parser() });
1111
+ if (read.issues.some((i) => i.path === "" || i.path === "plotArea")) fail2(read.issues.map((i) => i.message).join(" "));
4438
1112
  resolve(controller.update({ ...read.spec }, { label: "Import Office chart" }));
4439
1113
  return { spec: controller.toJSON(), issues: read.issues.map((i) => i.message), unsupported: read.unsupported, lossless: read.lossless };
4440
1114
  }
@@ -4443,7 +1117,7 @@ function createChartToolProvider(controller, options = {}) {
4443
1117
  name: "add_chart_trendline",
4444
1118
  title: "Add a trendline",
4445
1119
  description: "Fits a trendline to a series and draws it (unstacked bar, line, area, scatter and bubble charts). Returns its index and the fit: coefficients, R\xB2 and equation.",
4446
- inputSchema: { type: "object", properties: { series: SERIES_REF, ...TRENDLINE_PROPS }, required: ["series", "type"], additionalProperties: false },
1120
+ inputSchema: { type: "object", properties: { series: _chunkTGBCBQFVcjs.SERIES_REF, ..._chunkTGBCBQFVcjs.TRENDLINE_PROPS }, required: ["series", "type"], additionalProperties: false },
4447
1121
  annotations: { title: "Add a trendline", ...WRITE },
4448
1122
  handler: ({ series, ...line }) => {
4449
1123
  const s = seriesById(series);
@@ -4457,7 +1131,7 @@ function createChartToolProvider(controller, options = {}) {
4457
1131
  description: "Deletes a trendline from a series. Returns the series' remaining trendlines.",
4458
1132
  inputSchema: {
4459
1133
  type: "object",
4460
- properties: { series: SERIES_REF, index: { type: "integer", minimum: 0, description: "Trendline index on the series (0 = first)." } },
1134
+ properties: { series: _chunkTGBCBQFVcjs.SERIES_REF, index: { type: "integer", minimum: 0, description: "Trendline index on the series (0 = first)." } },
4461
1135
  required: ["series", "index"],
4462
1136
  additionalProperties: false
4463
1137
  },
@@ -4465,7 +1139,7 @@ function createChartToolProvider(controller, options = {}) {
4465
1139
  handler: ({ series, index }) => {
4466
1140
  const s = seriesById(series);
4467
1141
  resolve(controller.removeTrendline(s.id, index));
4468
- return { series: s.id, trendlines: _nullishCoalesce(_optionalChain([controller, 'access', _140 => _140.getSeries, 'call', _141 => _141(s.id), 'optionalAccess', _142 => _142.trendlines]), () => ( [])) };
1142
+ return { series: s.id, trendlines: _nullishCoalesce(_optionalChain([controller, 'access', _61 => _61.getSeries, 'call', _62 => _62(s.id), 'optionalAccess', _63 => _63.trendlines]), () => ( [])) };
4469
1143
  }
4470
1144
  };
4471
1145
  const applyPreset = {
@@ -4475,8 +1149,8 @@ function createChartToolProvider(controller, options = {}) {
4475
1149
  inputSchema: {
4476
1150
  type: "object",
4477
1151
  properties: {
4478
- layout: { type: "string", enum: CHART_LAYOUT_PRESETS.map((p) => p.id), description: "Quick layout id." },
4479
- colors: { type: "string", enum: CHART_COLOR_SCHEMES.map((p) => p.id), description: "Colour scheme id." }
1152
+ layout: { type: "string", enum: _chunkGTZXF4BIcjs.CHART_LAYOUT_PRESETS.map((p) => p.id), description: "Quick layout id." },
1153
+ colors: { type: "string", enum: _chunkGTZXF4BIcjs.CHART_COLOR_SCHEMES.map((p) => p.id), description: "Colour scheme id." }
4480
1154
  },
4481
1155
  additionalProperties: false
4482
1156
  },
@@ -4505,8 +1179,8 @@ function createChartToolProvider(controller, options = {}) {
4505
1179
  type: "object",
4506
1180
  properties: {
4507
1181
  kind: { type: "string", enum: ["none", "chart", "title", "subtitle", "legend", "axis", "series", "point", "category", "trendline"], description: "What to select." },
4508
- series: { ...SERIES_REF, description: "Series id or name (series, point, trendline)." },
4509
- category: { ...CATEGORY_REF, description: "Category index or label (point, category)." },
1182
+ series: { ..._chunkTGBCBQFVcjs.SERIES_REF, description: "Series id or name (series, point, trendline)." },
1183
+ category: { ..._chunkTGBCBQFVcjs.CATEGORY_REF, description: "Category index or label (point, category)." },
4510
1184
  axis: { type: "string", enum: ["x", "y", "y2"], description: "Axis (axis)." },
4511
1185
  index: { type: "integer", minimum: 0, description: "Trendline index (trendline)." }
4512
1186
  },
@@ -4516,7 +1190,7 @@ function createChartToolProvider(controller, options = {}) {
4516
1190
  annotations: { title: "Select a chart element", ...WRITE_IDEMPOTENT },
4517
1191
  handler: async ({ kind, series, category, axis, index }) => {
4518
1192
  let sel;
4519
- const need = (v, what) => v === void 0 && fail3(`kind "${kind}" needs ${what}.`);
1193
+ const need = (v, what) => v === void 0 && fail2(`kind "${kind}" needs ${what}.`);
4520
1194
  switch (kind) {
4521
1195
  case "none":
4522
1196
  sel = null;
@@ -4549,7 +1223,7 @@ function createChartToolProvider(controller, options = {}) {
4549
1223
  if (options.director) await options.director.perform(_nullishCoalesce(options.actor, () => ( { id: "agent", name: "Agent" })), [{ kind: "select", selection: sel }]);
4550
1224
  else controller.select(sel);
4551
1225
  const now = controller.getState().selection;
4552
- if (sel && !now) fail3(`Nothing to select there (e.g. the chart has no ${kind} of that kind).`);
1226
+ if (sel && !now) fail2(`Nothing to select there (e.g. the chart has no ${kind} of that kind).`);
4553
1227
  return { selection: now };
4554
1228
  }
4555
1229
  };
@@ -4564,22 +1238,22 @@ function createChartToolProvider(controller, options = {}) {
4564
1238
  to: { type: "object", description: "End, as fractions of the chart.", properties: { x: { type: "number", minimum: 0, maximum: 1, description: "Fraction of the width." }, y: { type: "number", minimum: 0, maximum: 1, description: "Fraction of the height." } }, required: ["x", "y"], additionalProperties: false },
4565
1239
  fine: { type: "boolean", description: "Move a tenth as far (Alt)." },
4566
1240
  lockAxis: { type: "boolean", description: "Scatter charts: change only the axis moved along most (Shift)." },
4567
- width: WIDTH,
4568
- height: HEIGHT
1241
+ width: _chunkTGBCBQFVcjs.WIDTH,
1242
+ height: _chunkTGBCBQFVcjs.HEIGHT
4569
1243
  },
4570
1244
  required: ["from", "to"],
4571
1245
  additionalProperties: false
4572
1246
  },
4573
1247
  annotations: { title: "Drag a chart point", ...WRITE },
4574
1248
  handler: ({ from, to, fine, lockAxis, width = size.width, height = size.height }) => {
4575
- const scene = layoutChart(controller.toJSON(), { width, height });
1249
+ const scene = _chunkGTZXF4BIcjs.layoutChart.call(void 0, controller.toJSON(), { width, height });
4576
1250
  const start = { x: from.x * width, y: from.y * height };
4577
1251
  const target = chartHitTest(scene, start);
4578
- if (_optionalChain([target, 'optionalAccess', _143 => _143.kind]) !== "point") fail3(`There is no bar or point at (${from.x}, ${from.y}); ${target ? `that is the ${target.kind}` : "that is outside the chart"}. Use render_chart to find marks.`);
1252
+ if (_optionalChain([target, 'optionalAccess', _64 => _64.kind]) !== "point") fail2(`There is no bar or point at (${from.x}, ${from.y}); ${target ? `that is the ${target.kind}` : "that is outside the chart"}. Use render_chart to find marks.`);
4579
1253
  const t = target;
4580
- const before = _nullishCoalesce(_optionalChain([controller, 'access', _144 => _144.getSeries, 'call', _145 => _145(t.seriesId), 'optionalAccess', _146 => _146.values, 'access', _147 => _147[t.index]]), () => ( null));
1254
+ const before = _nullishCoalesce(_optionalChain([controller, 'access', _65 => _65.getSeries, 'call', _66 => _66(t.seriesId), 'optionalAccess', _67 => _67.values, 'access', _68 => _68[t.index]]), () => ( null));
4581
1255
  const session = startChartPointDrag(controller, scene, t, start);
4582
- if (!session) fail3("That point cannot be dragged here (percent-stacked charts, pies and gaps cannot be dragged).");
1256
+ if (!session) fail2("That point cannot be dragged here (percent-stacked charts, pies and gaps cannot be dragged).");
4583
1257
  session.move({ x: to.x * width, y: to.y * height }, { fine, lockAxis });
4584
1258
  session.end();
4585
1259
  const s = controller.getSeries(t.seriesId);
@@ -4602,10 +1276,10 @@ function createChartToolProvider(controller, options = {}) {
4602
1276
  },
4603
1277
  annotations: { title: "Press a key on the chart", ...DESTRUCTIVE },
4604
1278
  handler: ({ key: k, shift, alt }) => {
4605
- const scene = layoutChart(controller.toJSON(), size);
1279
+ const scene = _chunkGTZXF4BIcjs.layoutChart.call(void 0, controller.toJSON(), size);
4606
1280
  const used = handleChartKey(controller, scene, { key: k, shiftKey: shift, altKey: alt });
4607
1281
  const sel = controller.getState().selection;
4608
- const value = _optionalChain([sel, 'optionalAccess', _148 => _148.kind]) === "point" ? _nullishCoalesce(_optionalChain([controller, 'access', _149 => _149.getSeries, 'call', _150 => _150(sel.seriesId), 'optionalAccess', _151 => _151.values, 'access', _152 => _152[sel.index]]), () => ( null)) : void 0;
1282
+ const value = _optionalChain([sel, 'optionalAccess', _69 => _69.kind]) === "point" ? _nullishCoalesce(_optionalChain([controller, 'access', _70 => _70.getSeries, 'call', _71 => _71(sel.seriesId), 'optionalAccess', _72 => _72.values, 'access', _73 => _73[sel.index]]), () => ( null)) : void 0;
4609
1283
  return { used, selection: sel, ...value !== void 0 ? { value } : {} };
4610
1284
  }
4611
1285
  };
@@ -4661,7 +1335,7 @@ function parsePartialChartJson(text) {
4661
1335
  if (!src) return void 0;
4662
1336
  try {
4663
1337
  return JSON.parse(src);
4664
- } catch (e3) {
1338
+ } catch (e2) {
4665
1339
  }
4666
1340
  const stack = [];
4667
1341
  let inString = false;
@@ -4685,7 +1359,7 @@ function parsePartialChartJson(text) {
4685
1359
  const candidate = trimmed + [...stack].reverse().join("");
4686
1360
  try {
4687
1361
  return JSON.parse(candidate);
4688
- } catch (e4) {
1362
+ } catch (e3) {
4689
1363
  const next = trimmed.replace(/,\s*$/, "").replace(/(?:,|\{)\s*"[^"]*"\s*:?\s*$/, (m) => m.trim().startsWith("{") ? "{" : "").replace(/:\s*$/, ": null").replace(/(?<=[\[,:]\s*)(-|tr?u?|fa?l?s?|nu?l?)$/, "").replace(/(?<=[\[,:]\s*)(-?\d+\.)$/, (m) => m.slice(0, -1));
4690
1364
  if (next === trimmed) break;
4691
1365
  out = next;
@@ -4693,14 +1367,14 @@ function parsePartialChartJson(text) {
4693
1367
  }
4694
1368
  return void 0;
4695
1369
  }
4696
- var ChartStream = (_class2 = class {
4697
- constructor(format = "auto") {;_class2.prototype.__init11.call(this);_class2.prototype.__init12.call(this);_class2.prototype.__init13.call(this);
1370
+ var ChartStream = (_class = class {
1371
+ constructor(format = "auto") {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);
4698
1372
  this.format = format;
4699
1373
  }
4700
1374
 
4701
- __init11() {this.lo = Infinity}
4702
- __init12() {this.hi = -Infinity}
4703
- __init13() {this.last = null}
1375
+ __init() {this.lo = Infinity}
1376
+ __init2() {this.hi = -Infinity}
1377
+ __init3() {this.last = null}
4704
1378
  /** Reads the source so far. `complete` when nothing more will arrive. */
4705
1379
  update(source, complete = false) {
4706
1380
  const text = source.replace(/^\s*```(?:mermaid|json)?\s*\n?/, "").replace(/```\s*$/, "");
@@ -4710,12 +1384,12 @@ var ChartStream = (_class2 = class {
4710
1384
  if (format === "json") {
4711
1385
  const value = complete ? safeParse(text) : parsePartialChartJson(text);
4712
1386
  if (value !== void 0) {
4713
- const read = _chunkNEOO6QJDcjs.normalizeChartSpec.call(void 0, value);
1387
+ const read = _chunkJOX6MJW4cjs.normalizeChartSpec.call(void 0, value);
4714
1388
  spec = read.spec;
4715
1389
  issues = complete ? read.issues : [];
4716
1390
  }
4717
1391
  } else {
4718
- const read = chartFromMermaid(text, { partial: !complete });
1392
+ const read = _chunkGTZXF4BIcjs.chartFromMermaid.call(void 0, text, { partial: !complete });
4719
1393
  if (read.family) {
4720
1394
  spec = read.spec;
4721
1395
  issues = complete ? read.issues : [];
@@ -4735,11 +1409,11 @@ var ChartStream = (_class2 = class {
4735
1409
  this.hi = -Infinity;
4736
1410
  this.last = null;
4737
1411
  }
4738
- }, _class2);
1412
+ }, _class);
4739
1413
  function safeParse(text) {
4740
1414
  try {
4741
1415
  return JSON.parse(text);
4742
- } catch (e5) {
1416
+ } catch (e4) {
4743
1417
  return parsePartialChartJson(text);
4744
1418
  }
4745
1419
  }
@@ -4788,11 +1462,11 @@ function blendChartScenes(from, to, t) {
4788
1462
  var easeChartTween = (t) => 1 - Math.pow(1 - Math.max(0, Math.min(1, t)), 3);
4789
1463
 
4790
1464
  // src/chart/presence.ts
4791
- var ChartPresence = (_class3 = class {constructor() { _class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this); }
4792
- __init14() {this.state = { actors: [] }}
4793
- __init15() {this.listeners = /* @__PURE__ */ new Set()}
4794
- __init16() {this.getState = () => this.state}
4795
- __init17() {this.subscribe = (listener) => {
1465
+ var ChartPresence = (_class2 = class {constructor() { _class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this); }
1466
+ __init4() {this.state = { actors: [] }}
1467
+ __init5() {this.listeners = /* @__PURE__ */ new Set()}
1468
+ __init6() {this.getState = () => this.state}
1469
+ __init7() {this.subscribe = (listener) => {
4796
1470
  this.listeners.add(listener);
4797
1471
  return () => {
4798
1472
  this.listeners.delete(listener);
@@ -4810,7 +1484,7 @@ var ChartPresence = (_class3 = class {constructor() { _class3.prototype.__init14
4810
1484
  this.state = { actors: this.state.actors.filter((a) => a.id !== id) };
4811
1485
  this.listeners.forEach((l) => l(this.state));
4812
1486
  }
4813
- }, _class3);
1487
+ }, _class2);
4814
1488
  var CHART_PRESENCE_COLORS = ["#7c3aed", "#db2777", "#0891b2", "#ea580c", "#16a34a"];
4815
1489
  var realChartClock = {
4816
1490
  now: () => Date.now(),
@@ -4827,7 +1501,7 @@ function createInstantChartClock(start = 0) {
4827
1501
  };
4828
1502
  }
4829
1503
  function chartPointAnchor(scene, seriesId, index) {
4830
- const mark = scene.marks.find((m) => (m.role === "bar" || m.role === "point") && _optionalChain([m, 'access', _153 => _153.target, 'optionalAccess', _154 => _154.kind]) === "point" && m.target.seriesId === seriesId && m.target.index === index);
1504
+ const mark = scene.marks.find((m) => (m.role === "bar" || m.role === "point") && _optionalChain([m, 'access', _74 => _74.target, 'optionalAccess', _75 => _75.kind]) === "point" && m.target.seriesId === seriesId && m.target.index === index);
4831
1505
  if (!mark) return null;
4832
1506
  if (mark.kind === "rect") return { x: mark.x + mark.width / 2, y: mark.y };
4833
1507
  if (mark.kind === "circle") return { x: mark.cx, y: mark.cy };
@@ -4853,10 +1527,10 @@ function planChartCommand(spec, scene, command, speed = 1) {
4853
1527
  case "setValue": {
4854
1528
  const at = chartPointAnchor(scene, command.seriesId, command.index);
4855
1529
  const series = spec.series.find((s) => s.id === command.seriesId);
4856
- const from = _nullishCoalesce(_optionalChain([series, 'optionalAccess', _155 => _155.values, 'access', _156 => _156[command.index]]), () => ( 0));
4857
- const scale = _optionalChain([series, 'optionalAccess', _157 => _157.axis]) === "secondary" ? _nullishCoalesce(scene.valueScale2, () => ( scene.valueScale)) : scene.valueScale;
1530
+ const from = _nullishCoalesce(_optionalChain([series, 'optionalAccess', _76 => _76.values, 'access', _77 => _77[command.index]]), () => ( 0));
1531
+ const scale = _optionalChain([series, 'optionalAccess', _78 => _78.axis]) === "secondary" ? _nullishCoalesce(scene.valueScale2, () => ( scene.valueScale)) : scene.valueScale;
4858
1532
  if (at && scale) {
4859
- const px = linearMap(command.value, scale.domain, scale.range);
1533
+ const px = _chunkGTZXF4BIcjs.linearMap.call(void 0, command.value, scale.domain, scale.range);
4860
1534
  const to = scale.axis === "y" ? { x: at.x, y: px } : { x: px, y: at.y };
4861
1535
  steps.push({ type: "move", to: at, ms: ms(380) }, { type: "press" }, { type: "drag", to, ms: ms(520), from, value: command.value }, { type: "release" });
4862
1536
  } else steps.push({ type: "drag", to: { x: scene.plot.x + scene.plot.width / 2, y: scene.plot.y + scene.plot.height / 2 }, ms: ms(200), from, value: command.value });
@@ -4866,12 +1540,12 @@ function planChartCommand(spec, scene, command, speed = 1) {
4866
1540
  case "select": {
4867
1541
  const sel = command.selection;
4868
1542
  let to = null;
4869
- if (_optionalChain([sel, 'optionalAccess', _158 => _158.kind]) === "point") to = chartPointAnchor(scene, sel.seriesId, sel.index);
1543
+ if (_optionalChain([sel, 'optionalAccess', _79 => _79.kind]) === "point") to = chartPointAnchor(scene, sel.seriesId, sel.index);
4870
1544
  else if (sel) {
4871
1545
  const m = scene.marks.find((x) => x.target && JSON.stringify(x.target) === JSON.stringify(sel));
4872
- if (_optionalChain([m, 'optionalAccess', _159 => _159.kind]) === "text") to = { x: m.x, y: m.y };
4873
- else if (_optionalChain([m, 'optionalAccess', _160 => _160.kind]) === "rect") to = { x: m.x + m.width / 2, y: m.y + m.height / 2 };
4874
- else if (_optionalChain([m, 'optionalAccess', _161 => _161.kind]) === "circle") to = { x: m.cx, y: m.cy };
1546
+ if (_optionalChain([m, 'optionalAccess', _80 => _80.kind]) === "text") to = { x: m.x, y: m.y };
1547
+ else if (_optionalChain([m, 'optionalAccess', _81 => _81.kind]) === "rect") to = { x: m.x + m.width / 2, y: m.y + m.height / 2 };
1548
+ else if (_optionalChain([m, 'optionalAccess', _82 => _82.kind]) === "circle") to = { x: m.cx, y: m.cy };
4875
1549
  }
4876
1550
  if (to) steps.push({ type: "move", to, ms: ms(380) }, { type: "press" }, { type: "release" });
4877
1551
  steps.push({ type: "commit" });
@@ -4886,8 +1560,8 @@ function planChartCommand(spec, scene, command, speed = 1) {
4886
1560
  }
4887
1561
  }
4888
1562
  }
4889
- var ChartDirector = (_class4 = class {
4890
- constructor(controller, presence, options) {;_class4.prototype.__init18.call(this);_class4.prototype.__init19.call(this);
1563
+ var ChartDirector = (_class3 = class {
1564
+ constructor(controller, presence, options) {;_class3.prototype.__init8.call(this);_class3.prototype.__init9.call(this);
4891
1565
  this.controller = controller;
4892
1566
  this.presence = presence;
4893
1567
  this.options = options;
@@ -4896,9 +1570,9 @@ var ChartDirector = (_class4 = class {
4896
1570
 
4897
1571
 
4898
1572
 
4899
- __init18() {this.queues = /* @__PURE__ */ new Map()}
1573
+ __init8() {this.queues = /* @__PURE__ */ new Map()}
4900
1574
 
4901
- __init19() {this.calls = 0}
1575
+ __init9() {this.calls = 0}
4902
1576
  /** Acts out `commands` in order for `actor`. Resolves with one result per command. */
4903
1577
  perform(actor, commands) {
4904
1578
  const prev = _nullishCoalesce(this.queues.get(actor.id), () => ( Promise.resolve()));
@@ -4938,7 +1612,7 @@ var ChartDirector = (_class4 = class {
4938
1612
  const t = f / frames;
4939
1613
  const e = 1 - Math.pow(1 - t, 3);
4940
1614
  this.presence.set({ id, x: from.x + (to.x - from.x) * e, y: from.y + (to.y - from.y) * e });
4941
- _optionalChain([each, 'optionalCall', _162 => _162(e)]);
1615
+ _optionalChain([each, 'optionalCall', _83 => _83(e)]);
4942
1616
  await this.clock.wait(ms / frames);
4943
1617
  }
4944
1618
  }
@@ -4970,7 +1644,7 @@ var ChartDirector = (_class4 = class {
4970
1644
  if (command.kind !== "setValue") break;
4971
1645
  const stale2 = this.stale(command);
4972
1646
  if (stale2) return { ok: false, command, message: stale2 };
4973
- const label = `${_nullishCoalesce(_optionalChain([this, 'access', _163 => _163.presence, 'access', _164 => _164.getState, 'call', _165 => _165(), 'access', _166 => _166.actors, 'access', _167 => _167.find, 'call', _168 => _168((a) => a.id === id), 'optionalAccess', _169 => _169.name]), () => ( "Agent"))}: edit value`;
1647
+ const label = `${_nullishCoalesce(_optionalChain([this, 'access', _84 => _84.presence, 'access', _85 => _85.getState, 'call', _86 => _86(), 'access', _87 => _87.actors, 'access', _88 => _88.find, 'call', _89 => _89((a) => a.id === id), 'optionalAccess', _90 => _90.name]), () => ( "Agent"))}: edit value`;
4974
1648
  await this.move(id, where(), step.to, step.ms, (e) => {
4975
1649
  const v = step.from + (step.value - step.from) * e;
4976
1650
  this.controller.setValue(command.seriesId, command.index, Number(v.toPrecision(12)), { label });
@@ -4991,7 +1665,8 @@ var ChartDirector = (_class4 = class {
4991
1665
  return { ok: true, command };
4992
1666
  }
4993
1667
  }
4994
- }, _class4);
1668
+ }, _class3);
1669
+
4995
1670
 
4996
1671
 
4997
1672
 
@@ -5124,5 +1799,5 @@ var ChartDirector = (_class4 = class {
5124
1799
 
5125
1800
 
5126
1801
 
5127
- exports.CHART_AXIS_KINDS = _chunkNEOO6QJDcjs.CHART_AXIS_KINDS; exports.CHART_COLOR_SCHEMES = CHART_COLOR_SCHEMES; exports.CHART_CURVES = _chunkNEOO6QJDcjs.CHART_CURVES; exports.CHART_DATE_STEPS = CHART_DATE_STEPS; exports.CHART_LABEL_POSITIONS = _chunkNEOO6QJDcjs.CHART_LABEL_POSITIONS; exports.CHART_LAYOUT_PRESETS = CHART_LAYOUT_PRESETS; exports.CHART_LEGEND_POSITIONS = _chunkNEOO6QJDcjs.CHART_LEGEND_POSITIONS; exports.CHART_MARKERS = _chunkNEOO6QJDcjs.CHART_MARKERS; exports.CHART_MERMAID_META_PREFIX = CHART_MERMAID_META_PREFIX; exports.CHART_NUMBER_STYLES = _chunkNEOO6QJDcjs.CHART_NUMBER_STYLES; exports.CHART_OOXML_CONTENT_TYPE = _chunkNEOO6QJDcjs.CHART_OOXML_CONTENT_TYPE; exports.CHART_OOXML_NS = _chunkNEOO6QJDcjs.CHART_OOXML_NS; exports.CHART_OOXML_RELATIONSHIP = _chunkNEOO6QJDcjs.CHART_OOXML_RELATIONSHIP; exports.CHART_ORIENTATIONS = _chunkNEOO6QJDcjs.CHART_ORIENTATIONS; exports.CHART_PALETTE_SHADES = _chunkNEOO6QJDcjs.CHART_PALETTE_SHADES; exports.CHART_PRESENCE_COLORS = CHART_PRESENCE_COLORS; exports.CHART_SERIES_TYPES = _chunkNEOO6QJDcjs.CHART_SERIES_TYPES; exports.CHART_STACKINGS = _chunkNEOO6QJDcjs.CHART_STACKINGS; exports.CHART_TRENDLINE_TYPES = _chunkNEOO6QJDcjs.CHART_TRENDLINE_TYPES; exports.CHART_TYPES = _chunkNEOO6QJDcjs.CHART_TYPES; exports.CHART_TYPE_LABELS = _chunkNEOO6QJDcjs.CHART_TYPE_LABELS; exports.CSS_VARIABLE_CHART_THEME = _chunkNEOO6QJDcjs.CSS_VARIABLE_CHART_THEME; exports.ChartController = ChartController; exports.ChartDirector = ChartDirector; exports.ChartPresence = ChartPresence; exports.ChartStream = ChartStream; exports.DEFAULT_CHART_PALETTE = _chunkNEOO6QJDcjs.DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = _chunkNEOO6QJDcjs.DEFAULT_CHART_THEME; exports.MAX_CHART_DATA_LABELS = MAX_CHART_DATA_LABELS; exports.MAX_CHART_LINE_POINTS = MAX_CHART_LINE_POINTS; exports.MAX_CHART_MARKERS = MAX_CHART_MARKERS; exports.analyzeChartTable = analyzeChartTable; exports.blendChartScenes = blendChartScenes; exports.canDragChartPoint = canDragChartPoint; exports.chartBoxStats = chartBoxStats; exports.chartClientToScene = chartClientToScene; exports.chartColorDistance = _chunkNEOO6QJDcjs.chartColorDistance; exports.chartColorInputValue = _chunkNEOO6QJDcjs.chartColorInputValue; exports.chartColorsByCategory = _chunkNEOO6QJDcjs.chartColorsByCategory; exports.chartContrastRatio = _chunkNEOO6QJDcjs.chartContrastRatio; exports.chartDataFromTable = _chunkNEOO6QJDcjs.chartDataFromTable; exports.chartDataToTable = _chunkNEOO6QJDcjs.chartDataToTable; exports.chartDateLabels = chartDateLabels; exports.chartDateToSerial = chartDateToSerial; exports.chartFamily = _chunkNEOO6QJDcjs.chartFamily; exports.chartFormatToCode = _chunkNEOO6QJDcjs.chartFormatToCode; exports.chartFromMermaid = chartFromMermaid; exports.chartFromOoxml = _chunkNEOO6QJDcjs.chartFromOoxml; exports.chartFromTable = chartFromTable; exports.chartHistogram = chartHistogram; exports.chartHitTest = chartHitTest; exports.chartLuminance = _chunkNEOO6QJDcjs.chartLuminance; exports.chartMermaidFamily = chartMermaidFamily; exports.chartMovingAverage = chartMovingAverage; exports.chartPointAnchor = chartPointAnchor; exports.chartPointColor = _chunkNEOO6QJDcjs.chartPointColor; exports.chartPresetPatch = chartPresetPatch; exports.chartQuantile = chartQuantile; exports.chartRgbToHex = _chunkNEOO6QJDcjs.chartRgbToHex; exports.chartRgbToOklab = _chunkNEOO6QJDcjs.chartRgbToOklab; exports.chartSceneToSvg = chartSceneToSvg; exports.chartSerialToDate = chartSerialToDate; exports.chartSeriesColor = _chunkNEOO6QJDcjs.chartSeriesColor; exports.chartSeriesType = _chunkNEOO6QJDcjs.chartSeriesType; exports.chartSliceColor = _chunkNEOO6QJDcjs.chartSliceColor; exports.chartSquarify = chartSquarify; exports.chartSupportsTrendlines = chartSupportsTrendlines; exports.chartTextBaseline = chartTextBaseline; exports.chartTextOn = _chunkNEOO6QJDcjs.chartTextOn; exports.chartTextTransform = chartTextTransform; exports.chartToMermaid = chartToMermaid; exports.chartToOoxml = _chunkNEOO6QJDcjs.chartToOoxml; exports.chartToSvg = chartToSvg; exports.chartTrendlineName = chartTrendlineName; exports.chartValueAtPoint = chartValueAtPoint; exports.chartXAtPoint = chartXAtPoint; exports.checkChartColors = _chunkNEOO6QJDcjs.checkChartColors; exports.cloneChartSeries = _chunkNEOO6QJDcjs.cloneChartSeries; exports.cloneChartSpec = _chunkNEOO6QJDcjs.cloneChartSpec; exports.compileChartFormatCode = compileChartFormatCode; exports.contrastingTextColor = contrastingTextColor; exports.createChartCommands = createChartCommands; exports.createChartController = createChartController; exports.createChartSpec = _chunkNEOO6QJDcjs.createChartSpec; exports.createChartToolProvider = createChartToolProvider; exports.createInstantChartClock = createInstantChartClock; exports.cyclePaletteColor = _chunkNEOO6QJDcjs.cyclePaletteColor; exports.decimateChartPoints = decimateChartPoints; exports.defaultChartAxis = _chunkNEOO6QJDcjs.defaultChartAxis; exports.describeChart = describeChart; exports.describeChartSelection = describeChartSelection; exports.easeChartTween = easeChartTween; exports.estimateChartTextWidth = estimateChartTextWidth; exports.findMermaidCharts = findMermaidCharts; exports.fitChartTrendline = fitChartTrendline; exports.formatChartDate = formatChartDate; exports.formatChartNumber = formatChartNumber; exports.formatChartValueWithCode = formatChartValueWithCode; exports.handleChartKey = handleChartKey; exports.isCartesianChart = _chunkNEOO6QJDcjs.isCartesianChart; exports.isXyChart = _chunkNEOO6QJDcjs.isXyChart; exports.layoutChart = layoutChart; exports.layoutSparkline = layoutSparkline; exports.linearMap = linearMap; exports.monochromeChartPalette = monochromeChartPalette; exports.niceScale = niceScale; exports.niceStep = niceStep; exports.normalizeChartAxis = _chunkNEOO6QJDcjs.normalizeChartAxis; exports.normalizeChartSpec = _chunkNEOO6QJDcjs.normalizeChartSpec; exports.normalizeChartTrendline = _chunkNEOO6QJDcjs.normalizeChartTrendline; exports.normalizeChartValues = _chunkNEOO6QJDcjs.normalizeChartValues; exports.parseChartColor = _chunkNEOO6QJDcjs.parseChartColor; exports.parseChartDate = parseChartDate; exports.parseChartValue = _chunkNEOO6QJDcjs.parseChartValue; exports.parsePartialChartJson = parsePartialChartJson; exports.planChartCommand = planChartCommand; exports.realChartClock = realChartClock; exports.recommendChartTypes = recommendChartTypes; exports.recommendForShape = recommendForShape; exports.sameChartSelection = sameChartSelection; exports.shadeChartColor = _chunkNEOO6QJDcjs.shadeChartColor; exports.simulateChartVision = _chunkNEOO6QJDcjs.simulateChartVision; exports.snapChartDragValue = snapChartDragValue; exports.snapChartValue = snapChartValue; exports.sparklineToSvg = sparklineToSvg; exports.startChartPointDrag = startChartPointDrag; exports.stepDecimals = stepDecimals; exports.summarizeChart = summarizeChart; exports.summarizeChartSeries = summarizeChartSeries; exports.trendNumberText = trendNumberText; exports.uniqueChartSeriesId = _chunkNEOO6QJDcjs.uniqueChartSeriesId;
1802
+ exports.CHART_AXIS_KINDS = _chunkJOX6MJW4cjs.CHART_AXIS_KINDS; exports.CHART_COLOR_SCHEMES = _chunkGTZXF4BIcjs.CHART_COLOR_SCHEMES; exports.CHART_CURVES = _chunkJOX6MJW4cjs.CHART_CURVES; exports.CHART_DATE_STEPS = _chunkGTZXF4BIcjs.CHART_DATE_STEPS; exports.CHART_LABEL_POSITIONS = _chunkJOX6MJW4cjs.CHART_LABEL_POSITIONS; exports.CHART_LAYOUT_PRESETS = _chunkGTZXF4BIcjs.CHART_LAYOUT_PRESETS; exports.CHART_LEGEND_POSITIONS = _chunkJOX6MJW4cjs.CHART_LEGEND_POSITIONS; exports.CHART_MARKERS = _chunkJOX6MJW4cjs.CHART_MARKERS; exports.CHART_MERMAID_META_PREFIX = _chunkGTZXF4BIcjs.CHART_MERMAID_META_PREFIX; exports.CHART_NUMBER_STYLES = _chunkJOX6MJW4cjs.CHART_NUMBER_STYLES; exports.CHART_OOXML_CONTENT_TYPE = _chunk3JNRQVTScjs.CHART_OOXML_CONTENT_TYPE; exports.CHART_OOXML_NS = _chunk3JNRQVTScjs.CHART_OOXML_NS; exports.CHART_OOXML_RELATIONSHIP = _chunk3JNRQVTScjs.CHART_OOXML_RELATIONSHIP; exports.CHART_ORIENTATIONS = _chunkJOX6MJW4cjs.CHART_ORIENTATIONS; exports.CHART_PALETTE_SHADES = _chunkJOX6MJW4cjs.CHART_PALETTE_SHADES; exports.CHART_PRESENCE_COLORS = CHART_PRESENCE_COLORS; exports.CHART_SERIES_TYPES = _chunkJOX6MJW4cjs.CHART_SERIES_TYPES; exports.CHART_STACKINGS = _chunkJOX6MJW4cjs.CHART_STACKINGS; exports.CHART_TRENDLINE_TYPES = _chunkJOX6MJW4cjs.CHART_TRENDLINE_TYPES; exports.CHART_TYPES = _chunkJOX6MJW4cjs.CHART_TYPES; exports.CHART_TYPE_LABELS = _chunkJOX6MJW4cjs.CHART_TYPE_LABELS; exports.CSS_VARIABLE_CHART_THEME = _chunkJOX6MJW4cjs.CSS_VARIABLE_CHART_THEME; exports.ChartController = _chunkGTZXF4BIcjs.ChartController; exports.ChartDirector = ChartDirector; exports.ChartPresence = ChartPresence; exports.ChartStream = ChartStream; exports.DEFAULT_CHART_PALETTE = _chunkJOX6MJW4cjs.DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = _chunkJOX6MJW4cjs.DEFAULT_CHART_THEME; exports.MAX_CHART_DATA_LABELS = _chunkGTZXF4BIcjs.MAX_CHART_DATA_LABELS; exports.MAX_CHART_LINE_POINTS = _chunkGTZXF4BIcjs.MAX_CHART_LINE_POINTS; exports.MAX_CHART_MARKERS = _chunkGTZXF4BIcjs.MAX_CHART_MARKERS; exports.analyzeChartTable = analyzeChartTable; exports.blendChartScenes = blendChartScenes; exports.canDragChartPoint = canDragChartPoint; exports.chartBoxStats = _chunkGTZXF4BIcjs.chartBoxStats; exports.chartClientToScene = chartClientToScene; exports.chartColorDistance = _chunkJOX6MJW4cjs.chartColorDistance; exports.chartColorInputValue = _chunkJOX6MJW4cjs.chartColorInputValue; exports.chartColorsByCategory = _chunkJOX6MJW4cjs.chartColorsByCategory; exports.chartContrastRatio = _chunkJOX6MJW4cjs.chartContrastRatio; exports.chartDataFromTable = _chunkJOX6MJW4cjs.chartDataFromTable; exports.chartDataToTable = _chunkJOX6MJW4cjs.chartDataToTable; exports.chartDateLabels = _chunkGTZXF4BIcjs.chartDateLabels; exports.chartDateToSerial = _chunkGTZXF4BIcjs.chartDateToSerial; exports.chartFamily = _chunkJOX6MJW4cjs.chartFamily; exports.chartFormatToCode = _chunk3JNRQVTScjs.chartFormatToCode; exports.chartFromMermaid = _chunkGTZXF4BIcjs.chartFromMermaid; exports.chartFromOoxml = _chunk3JNRQVTScjs.chartFromOoxml; exports.chartFromTable = chartFromTable; exports.chartHistogram = _chunkGTZXF4BIcjs.chartHistogram; exports.chartHitTest = chartHitTest; exports.chartLuminance = _chunkJOX6MJW4cjs.chartLuminance; exports.chartMermaidFamily = _chunkGTZXF4BIcjs.chartMermaidFamily; exports.chartMovingAverage = _chunkGTZXF4BIcjs.chartMovingAverage; exports.chartPointAnchor = chartPointAnchor; exports.chartPointColor = _chunkJOX6MJW4cjs.chartPointColor; exports.chartPresetPatch = _chunkGTZXF4BIcjs.chartPresetPatch; exports.chartQuantile = _chunkGTZXF4BIcjs.chartQuantile; exports.chartRgbToHex = _chunkJOX6MJW4cjs.chartRgbToHex; exports.chartRgbToOklab = _chunkJOX6MJW4cjs.chartRgbToOklab; exports.chartSceneToDomSpec = _chunkGTZXF4BIcjs.chartSceneToDomSpec; exports.chartSceneToSvg = _chunkGTZXF4BIcjs.chartSceneToSvg; exports.chartSerialToDate = _chunkGTZXF4BIcjs.chartSerialToDate; exports.chartSeriesColor = _chunkJOX6MJW4cjs.chartSeriesColor; exports.chartSeriesType = _chunkJOX6MJW4cjs.chartSeriesType; exports.chartSliceColor = _chunkJOX6MJW4cjs.chartSliceColor; exports.chartSquarify = _chunkGTZXF4BIcjs.chartSquarify; exports.chartSupportsTrendlines = _chunkGTZXF4BIcjs.chartSupportsTrendlines; exports.chartTextBaseline = _chunkGTZXF4BIcjs.chartTextBaseline; exports.chartTextOn = _chunkJOX6MJW4cjs.chartTextOn; exports.chartTextTransform = _chunkGTZXF4BIcjs.chartTextTransform; exports.chartToMermaid = _chunkGTZXF4BIcjs.chartToMermaid; exports.chartToOoxml = _chunk3JNRQVTScjs.chartToOoxml; exports.chartToSvg = _chunkGTZXF4BIcjs.chartToSvg; exports.chartTrendlineName = _chunkGTZXF4BIcjs.chartTrendlineName; exports.chartValueAtPoint = _chunkGTZXF4BIcjs.chartValueAtPoint; exports.chartXAtPoint = _chunkGTZXF4BIcjs.chartXAtPoint; exports.checkChartColors = _chunkJOX6MJW4cjs.checkChartColors; exports.cloneChartSeries = _chunkJOX6MJW4cjs.cloneChartSeries; exports.cloneChartSpec = _chunkJOX6MJW4cjs.cloneChartSpec; exports.compileChartFormatCode = _chunkGTZXF4BIcjs.compileChartFormatCode; exports.contrastingTextColor = _chunkGTZXF4BIcjs.contrastingTextColor; exports.createChartCommands = createChartCommands; exports.createChartController = _chunkGTZXF4BIcjs.createChartController; exports.createChartSpec = _chunkJOX6MJW4cjs.createChartSpec; exports.createChartToolProvider = createChartToolProvider; exports.createInstantChartClock = createInstantChartClock; exports.cyclePaletteColor = _chunkJOX6MJW4cjs.cyclePaletteColor; exports.decimateChartPoints = _chunkGTZXF4BIcjs.decimateChartPoints; exports.defaultChartAxis = _chunkJOX6MJW4cjs.defaultChartAxis; exports.describeChart = _chunkGTZXF4BIcjs.describeChart; exports.describeChartSelection = describeChartSelection; exports.easeChartTween = easeChartTween; exports.estimateChartTextWidth = _chunkGTZXF4BIcjs.estimateChartTextWidth; exports.findMermaidCharts = _chunkGTZXF4BIcjs.findMermaidCharts; exports.fitChartTrendline = _chunkGTZXF4BIcjs.fitChartTrendline; exports.formatChartDate = _chunkGTZXF4BIcjs.formatChartDate; exports.formatChartNumber = _chunkGTZXF4BIcjs.formatChartNumber; exports.formatChartValueWithCode = _chunkGTZXF4BIcjs.formatChartValueWithCode; exports.handleChartKey = handleChartKey; exports.isCartesianChart = _chunkJOX6MJW4cjs.isCartesianChart; exports.isXyChart = _chunkJOX6MJW4cjs.isXyChart; exports.layoutChart = _chunkGTZXF4BIcjs.layoutChart; exports.layoutSparkline = _chunkGTZXF4BIcjs.layoutSparkline; exports.linearMap = _chunkGTZXF4BIcjs.linearMap; exports.monochromeChartPalette = _chunkGTZXF4BIcjs.monochromeChartPalette; exports.niceScale = _chunkGTZXF4BIcjs.niceScale; exports.niceStep = _chunkGTZXF4BIcjs.niceStep; exports.normalizeChartAxis = _chunkJOX6MJW4cjs.normalizeChartAxis; exports.normalizeChartSpec = _chunkJOX6MJW4cjs.normalizeChartSpec; exports.normalizeChartTrendline = _chunkJOX6MJW4cjs.normalizeChartTrendline; exports.normalizeChartValues = _chunkJOX6MJW4cjs.normalizeChartValues; exports.parseChartColor = _chunkJOX6MJW4cjs.parseChartColor; exports.parseChartDate = _chunkGTZXF4BIcjs.parseChartDate; exports.parseChartValue = _chunkJOX6MJW4cjs.parseChartValue; exports.parsePartialChartJson = parsePartialChartJson; exports.planChartCommand = planChartCommand; exports.realChartClock = realChartClock; exports.recommendChartTypes = recommendChartTypes; exports.recommendForShape = recommendForShape; exports.sameChartSelection = _chunkGTZXF4BIcjs.sameChartSelection; exports.shadeChartColor = _chunkJOX6MJW4cjs.shadeChartColor; exports.simulateChartVision = _chunkJOX6MJW4cjs.simulateChartVision; exports.snapChartDragValue = snapChartDragValue; exports.snapChartValue = _chunkGTZXF4BIcjs.snapChartValue; exports.sparklineToSvg = _chunkGTZXF4BIcjs.sparklineToSvg; exports.startChartPointDrag = startChartPointDrag; exports.stepDecimals = _chunkGTZXF4BIcjs.stepDecimals; exports.summarizeChart = _chunkGTZXF4BIcjs.summarizeChart; exports.summarizeChartSeries = _chunkGTZXF4BIcjs.summarizeChartSeries; exports.trendNumberText = _chunkGTZXF4BIcjs.trendNumberText; exports.uniqueChartSeriesId = _chunkJOX6MJW4cjs.uniqueChartSeriesId;
5128
1803
  //# sourceMappingURL=index.cjs.map