@pixerate/editor 0.162.0 → 0.163.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent/index.cjs +34 -34
- package/dist/agent/index.js +5 -5
- package/dist/animation-editor/index.cjs +57 -57
- package/dist/animation-editor/index.js +3 -3
- package/dist/{brushstrokeRender-Q4LI22QV.js → brushstrokeRender-7LXCU7PD.js} +2 -2
- package/dist/{brushstrokeRender-5WANQIG4.cjs → brushstrokeRender-VO4ZTWVA.cjs} +5 -5
- package/dist/canvas/index.cjs +14 -14
- package/dist/canvas/index.js +3 -3
- package/dist/chart/commands.d.cts +2 -1
- package/dist/chart/commands.d.ts +2 -1
- package/dist/chart/controller.d.cts +109 -1
- package/dist/chart/controller.d.ts +109 -1
- package/dist/chart/index.cjs +605 -130
- package/dist/chart/index.d.cts +1 -0
- package/dist/chart/index.d.ts +1 -0
- package/dist/chart/index.js +490 -15
- package/dist/chart/layout-annotations.d.cts +29 -0
- package/dist/chart/layout-annotations.d.ts +29 -0
- package/dist/chart/layout-families.d.cts +23 -0
- package/dist/chart/layout-families.d.ts +23 -0
- package/dist/chart/mermaid.d.cts +2 -1
- package/dist/chart/mermaid.d.ts +2 -1
- package/dist/chart/schemas.d.cts +13 -0
- package/dist/chart/schemas.d.ts +13 -0
- package/dist/chart/spec.d.cts +30 -5
- package/dist/chart/spec.d.ts +30 -5
- package/dist/chart/stats.d.cts +9 -1
- package/dist/chart/stats.d.ts +9 -1
- package/dist/chart/tools.d.cts +1 -1
- package/dist/chart/tools.d.ts +1 -1
- package/dist/chart/tree.d.cts +62 -0
- package/dist/chart/tree.d.ts +62 -0
- package/dist/chart/types.d.cts +77 -3
- package/dist/chart/types.d.ts +77 -3
- package/dist/{chunk-7YBDRJXT.cjs → chunk-22KLZZGH.cjs} +8 -8
- package/dist/{chunk-LQLZHP6F.js → chunk-36OKQDCF.js} +7 -4
- package/dist/{chunk-HLOKB7WW.js → chunk-3NEZJCBY.js} +366 -6
- package/dist/{chunk-GWV4T5NZ.js → chunk-3VLOOO3G.js} +1 -1
- package/dist/{chunk-3GJH2MGH.cjs → chunk-5AARIS3R.cjs} +35 -35
- package/dist/{chunk-EVPZ5IKN.js → chunk-5FNGLV2D.js} +65 -3
- package/dist/{chunk-EQ46F75O.cjs → chunk-D54JHQK2.cjs} +51 -51
- package/dist/{chunk-NO5QQDHZ.js → chunk-DAPQGA55.js} +2 -2
- package/dist/{chunk-3IHNXRUV.cjs → chunk-GKNEJ6EN.cjs} +399 -67
- package/dist/{chunk-236TKNUR.cjs → chunk-JCXMJUQO.cjs} +2 -2
- package/dist/{chunk-4NGVHHJB.cjs → chunk-NZD2MZJC.cjs} +80 -18
- package/dist/{chunk-CX6JLDFC.js → chunk-OXERWBKE.js} +3 -3
- package/dist/{chunk-32MMQYCQ.cjs → chunk-PA3IMPPS.cjs} +81 -81
- package/dist/{chunk-7CKPUUN4.js → chunk-POR54B55.js} +61 -10
- package/dist/{chunk-KGTF55R3.js → chunk-QY4KUDMY.js} +1 -1
- package/dist/{chunk-LL3H5XUH.cjs → chunk-R3P2M7HU.cjs} +367 -7
- package/dist/{chunk-HDGBM7EA.cjs → chunk-SBQVEBSU.cjs} +580 -53
- package/dist/{chunk-2TKHLX6H.js → chunk-SET6KJOP.js} +1 -1
- package/dist/{chunk-XDCFJEU7.js → chunk-SZA42R4N.js} +346 -14
- package/dist/{chunk-GLMP22FT.js → chunk-TALQONZ5.js} +3 -3
- package/dist/{chunk-GNK7SESQ.cjs → chunk-V7GWZIZK.cjs} +7 -4
- package/dist/{chunk-EYVVIZJ3.cjs → chunk-WTW7QRTS.cjs} +1 -1
- package/dist/{chunk-NA4UVVJ4.cjs → chunk-YGG7WDWT.cjs} +76 -25
- package/dist/{chunk-JGKCC5OF.cjs → chunk-YQ5C5BVK.cjs} +10 -9
- package/dist/{chunk-EY22AY6R.cjs → chunk-YSAGBIRW.cjs} +16 -16
- package/dist/{chunk-A5UCR2TO.js → chunk-YXKLVD56.js} +10 -9
- package/dist/{chunk-DTSTNRPH.js → chunk-Z4P2RBMJ.js} +536 -9
- package/dist/{chunk-45XXVHVG.js → chunk-ZZGPYNS2.js} +1 -1
- package/dist/export/index.cjs +4 -4
- package/dist/export/index.js +3 -3
- package/dist/extensions/index.cjs +7 -7
- package/dist/extensions/index.js +6 -6
- package/dist/image-editor/index.cjs +638 -638
- package/dist/image-editor/index.js +4 -4
- package/dist/index.cjs +13 -13
- package/dist/index.js +7 -7
- package/dist/paint/index.cjs +2 -2
- package/dist/paint/index.js +1 -1
- package/dist/paint-editor/index.cjs +129 -149
- package/dist/paint-editor/index.js +5 -25
- package/dist/vector/index.cjs +948 -948
- package/dist/vector/index.js +3 -3
- package/package.json +3 -3
- package/skills/pixerate-canvas/SKILL.md +16 -0
- package/skills/pixerate-chart/SKILL.md +92 -9
- package/skills/pixerate-paint-editor/SKILL.md +0 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkSBQVEBSUcjs = require('./chunk-SBQVEBSU.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
@@ -27,7 +27,16 @@ var _chunkHDGBM7EAcjs = require('./chunk-HDGBM7EA.cjs');
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
var _chunkR3P2M7HUcjs = require('./chunk-R3P2M7HU.cjs');
|
|
31
40
|
|
|
32
41
|
|
|
33
42
|
|
|
@@ -63,8 +72,8 @@ function splitOutside(text, sep) {
|
|
|
63
72
|
return out;
|
|
64
73
|
}
|
|
65
74
|
function chartMermaidFamily(spec) {
|
|
66
|
-
const family =
|
|
67
|
-
if (family === "pie" || family === "funnel" || family === "treemap") return "pie";
|
|
75
|
+
const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, spec);
|
|
76
|
+
if (family === "pie" || family === "funnel" || family === "treemap" || family === "parliament" || family === "sunburst") return "pie";
|
|
68
77
|
if (family === "radar") return "radar";
|
|
69
78
|
return "xychart";
|
|
70
79
|
}
|
|
@@ -227,8 +236,8 @@ function chartFromMermaid(text, options = {}) {
|
|
|
227
236
|
let title = _nullishCoalesce(frontTitle, () => ( ""));
|
|
228
237
|
const categories = [];
|
|
229
238
|
const series = [];
|
|
230
|
-
const xAxis =
|
|
231
|
-
const yAxis =
|
|
239
|
+
const xAxis = _chunkR3P2M7HUcjs.defaultChartAxis.call(void 0, false);
|
|
240
|
+
const yAxis = _chunkR3P2M7HUcjs.defaultChartAxis.call(void 0, true);
|
|
232
241
|
const radarAxes = [];
|
|
233
242
|
const pieSlices = [];
|
|
234
243
|
let legendShow = true;
|
|
@@ -388,7 +397,7 @@ function chartFromMermaid(text, options = {}) {
|
|
|
388
397
|
input.series = metaSeries.map((extra, i) => ({ ..._nullishCoalesce(base[i], () => ( {})), ..._nullishCoalesce(extra, () => ( {})) }));
|
|
389
398
|
}
|
|
390
399
|
}
|
|
391
|
-
const { spec, issues: specIssues } =
|
|
400
|
+
const { spec, issues: specIssues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
|
|
392
401
|
if (!family && !partial && !issues.length) issues.push({ path: "header", message: "The text is empty: expected a chart header (xychart-beta, pie or radar-beta)." });
|
|
393
402
|
return { spec, issues: [...issues, ...specIssues], family, hasMeta: !!meta };
|
|
394
403
|
}
|
|
@@ -427,11 +436,11 @@ function findMermaidCharts(text) {
|
|
|
427
436
|
}
|
|
428
437
|
|
|
429
438
|
// src/chart/summary.ts
|
|
430
|
-
function summarizeChart(spec, size = { width: 640, height: 400 }, scene =
|
|
439
|
+
function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunkSBQVEBSUcjs.layoutChart.call(void 0, spec, { ...size, selection: null })) {
|
|
431
440
|
const visible = spec.series.filter((s) => !s.hidden);
|
|
432
|
-
const series = visible.map((s) =>
|
|
433
|
-
const colors =
|
|
434
|
-
const check =
|
|
441
|
+
const series = visible.map((s) => _chunkSBQVEBSUcjs.summarizeChartSeries.call(void 0, s, spec.categories));
|
|
442
|
+
const colors = _chunkR3P2M7HUcjs.chartSpecColorsByCategory.call(void 0, spec) ? spec.categories.map((_, i) => _optionalChain([visible, 'access', _10 => _10[0], 'optionalAccess', _11 => _11.pointColors, 'optionalAccess', _12 => _12[i]]) || _chunkR3P2M7HUcjs.chartSliceColor.call(void 0, spec, i)) : visible.map((s) => _chunkR3P2M7HUcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s)));
|
|
443
|
+
const check = _chunkR3P2M7HUcjs.checkChartColors.call(void 0, colors, { surface: scene.theme.surface.startsWith("var(") ? "#ffffff" : scene.theme.surface });
|
|
435
444
|
const axis = (s, a) => s ? { min: s.domain[0], max: s.domain[1], ticks: [...s.ticks], ...s.logBase ? { logBase: s.logBase } : {}, ...a.reverse ? { reversed: true } : {} } : void 0;
|
|
436
445
|
return {
|
|
437
446
|
type: spec.type,
|
|
@@ -446,22 +455,58 @@ function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunk
|
|
|
446
455
|
description: describeChart(spec, series)
|
|
447
456
|
};
|
|
448
457
|
}
|
|
449
|
-
function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((s) =>
|
|
450
|
-
const kind =
|
|
458
|
+
function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((s) => _chunkSBQVEBSUcjs.summarizeChartSeries.call(void 0, s, spec.categories))) {
|
|
459
|
+
const kind = _chunkR3P2M7HUcjs.CHART_TYPE_LABELS[spec.type].toLowerCase();
|
|
451
460
|
const parts = [];
|
|
452
|
-
const family =
|
|
461
|
+
const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, spec);
|
|
453
462
|
const format = spec.yAxis.format;
|
|
454
|
-
const fmt = (v) => v === null ? "blank" :
|
|
463
|
+
const fmt = (v) => v === null ? "blank" : _chunkSBQVEBSUcjs.formatChartNumber.call(void 0, v, format);
|
|
455
464
|
const head = spec.title ? `${spec.title}: a ${kind} chart` : `A ${kind} chart`;
|
|
456
465
|
if (!series.length || series.every((s) => s.count === 0)) return `${head} with no data.`;
|
|
457
|
-
if (family === "pie" || family === "funnel" || family === "treemap") {
|
|
466
|
+
if (family === "pie" || family === "funnel" || family === "treemap" || family === "sunburst") {
|
|
458
467
|
const s = series[0];
|
|
459
468
|
const total = _nullishCoalesce(s.sum, () => ( 0));
|
|
460
469
|
const share = (v) => total && v !== null ? ` (${Math.round(v / total * 100)}%)` : "";
|
|
461
470
|
parts.push(`${head} of ${s.name} across ${spec.categories.length} categories, totalling ${fmt(s.sum)}.`);
|
|
462
471
|
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)}.`);
|
|
472
|
+
if (spec.tree.length) {
|
|
473
|
+
const depth = _chunkR3P2M7HUcjs.chartTreeDepth.call(void 0, spec.tree);
|
|
474
|
+
const items = _chunkR3P2M7HUcjs.chartTreeToRows.call(void 0, spec.tree).length;
|
|
475
|
+
parts.push(`The data is grouped ${depth} level${depth === 1 ? "" : "s"} deep with ${items} item${items === 1 ? "" : "s"}.`);
|
|
476
|
+
}
|
|
463
477
|
return parts.join(" ");
|
|
464
478
|
}
|
|
479
|
+
if (family === "parliament") {
|
|
480
|
+
const s = spec.series.find((x) => !x.hidden);
|
|
481
|
+
const seats = spec.categories.map((c, i) => ({ c, n: Math.max(0, Math.round(_nullishCoalesce(s.values[i], () => ( 0)))) }));
|
|
482
|
+
const total = seats.reduce((t, x) => t + x.n, 0);
|
|
483
|
+
const majority = _nullishCoalesce(spec.parliamentMajority, () => ( Math.floor(total / 2) + 1));
|
|
484
|
+
const largest = [...seats].sort((a, b) => b.n - a.n)[0];
|
|
485
|
+
const verdict = largest && largest.n >= majority ? `${largest.c} holds a majority with ${largest.n}` : `no group reaches the majority of ${majority}; the largest is ${_optionalChain([largest, 'optionalAccess', _13 => _13.c])} with ${_optionalChain([largest, 'optionalAccess', _14 => _14.n])}`;
|
|
486
|
+
return `${head} of ${total} seats across ${seats.length} groups: ${verdict}.`;
|
|
487
|
+
}
|
|
488
|
+
if (family === "slope") {
|
|
489
|
+
const [a, b] = spec.series.filter((x) => !x.hidden);
|
|
490
|
+
if (!b) return `${head} that needs a second series to compare against.`;
|
|
491
|
+
const moves = spec.categories.map((c, i) => ({ c, d: a.values[i] !== null && b.values[i] !== null ? b.values[i] - a.values[i] : null })).filter((m) => m.d !== null);
|
|
492
|
+
const up = moves.filter((m) => m.d > 0).length;
|
|
493
|
+
const down = moves.filter((m) => m.d < 0).length;
|
|
494
|
+
const top = [...moves].sort((x, y) => y.d - x.d);
|
|
495
|
+
const extremes = top.length ? ` The biggest rise is ${top[0].c} (${fmt(top[0].d)}); the biggest fall is ${top[top.length - 1].c} (${fmt(top[top.length - 1].d)}).` : "";
|
|
496
|
+
return `${head} from ${a.name} to ${b.name}: ${up} of ${moves.length} rose and ${down} fell.${extremes}`;
|
|
497
|
+
}
|
|
498
|
+
if (family === "likert") {
|
|
499
|
+
const answers = spec.series.filter((x) => !x.hidden);
|
|
500
|
+
const side = Math.floor(answers.length / 2);
|
|
501
|
+
const agree = spec.categories.map((c, i) => {
|
|
502
|
+
const vals = answers.map((x) => Math.max(0, _nullishCoalesce(x.values[i], () => ( 0))));
|
|
503
|
+
const total = vals.reduce((t, v) => t + v, 0);
|
|
504
|
+
return { c, share: total ? vals.slice(answers.length - side).reduce((t, v) => t + v, 0) / total : 0 };
|
|
505
|
+
});
|
|
506
|
+
const best = [...agree].sort((x, y) => y.share - x.share);
|
|
507
|
+
const pct = (v) => `${Math.round(v * 100)}%`;
|
|
508
|
+
return `${head} of ${spec.categories.length} questions with ${answers.length} answers from ${_optionalChain([answers, 'access', _15 => _15[0], 'optionalAccess', _16 => _16.name])} to ${_optionalChain([answers, 'access', _17 => _17[answers.length - 1], 'optionalAccess', _18 => _18.name])}. Most positive: ${_optionalChain([best, 'access', _19 => _19[0], 'optionalAccess', _20 => _20.c])} (${pct(_nullishCoalesce(_optionalChain([best, 'access', _21 => _21[0], 'optionalAccess', _22 => _22.share]), () => ( 0)))}); least: ${_optionalChain([best, 'access', _23 => _23[best.length - 1], 'optionalAccess', _24 => _24.c])} (${pct(_nullishCoalesce(_optionalChain([best, 'access', _25 => _25[best.length - 1], 'optionalAccess', _26 => _26.share]), () => ( 0)))}).`;
|
|
509
|
+
}
|
|
465
510
|
if (family === "waterfall") {
|
|
466
511
|
const s = spec.series.find((x) => !x.hidden);
|
|
467
512
|
const steps = s.values.filter((v, i) => v !== null && Number.isFinite(v) && !/\b(sub)?total\b/i.test(_nullishCoalesce(spec.categories[i], () => ( ""))));
|
|
@@ -499,7 +544,7 @@ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((
|
|
|
499
544
|
}
|
|
500
545
|
parts.push(...axes);
|
|
501
546
|
for (const s of spec.series.filter((x) => !x.hidden && (x.errorBars || x.xErrorBars)).slice(0, 8)) {
|
|
502
|
-
const bars = [s.errorBars ?
|
|
547
|
+
const bars = [s.errorBars ? _chunkR3P2M7HUcjs.describeChartErrorBars.call(void 0, s.errorBars) : "", s.xErrorBars ? `x ${_chunkR3P2M7HUcjs.describeChartErrorBars.call(void 0, s.xErrorBars)}` : ""].filter(Boolean).join(" and ");
|
|
503
548
|
parts.push(`${s.name} has ${bars}.`);
|
|
504
549
|
}
|
|
505
550
|
return parts.join(" ");
|
|
@@ -564,7 +609,7 @@ function chartSceneToSvg(scene, options = {}) {
|
|
|
564
609
|
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>`;
|
|
565
610
|
}
|
|
566
611
|
function chartToSvg(spec, options) {
|
|
567
|
-
const scene =
|
|
612
|
+
const scene = _chunkSBQVEBSUcjs.layoutChart.call(void 0, spec, { ...options, selection: null });
|
|
568
613
|
return chartSceneToSvg(scene, { ...options, ariaLabel: _nullishCoalesce(options.ariaLabel, () => ( (spec.title || void 0))), description: _nullishCoalesce(options.description, () => ( describeChart(spec))) });
|
|
569
614
|
}
|
|
570
615
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
@@ -602,10 +647,10 @@ var CHART_LAYOUT_PRESETS = [
|
|
|
602
647
|
];
|
|
603
648
|
function monochromeChartPalette(base, count = 6) {
|
|
604
649
|
const steps = count <= 1 ? [0] : Array.from({ length: count }, (_, i) => -0.45 + 1.05 * i / (count - 1));
|
|
605
|
-
return steps.map((t) =>
|
|
650
|
+
return steps.map((t) => _chunkR3P2M7HUcjs.shadeChartColor.call(void 0, base, t));
|
|
606
651
|
}
|
|
607
652
|
var CHART_COLOR_SCHEMES = [
|
|
608
|
-
{ id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette:
|
|
653
|
+
{ id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette: _chunkR3P2M7HUcjs.DEFAULT_CHART_PALETTE },
|
|
609
654
|
{ 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"] },
|
|
610
655
|
{ id: "office", label: "Office", description: "The six accent colours of the default Office theme.", palette: ["#4472c4", "#ed7d31", "#a5a5a5", "#ffc000", "#5b9bd5", "#70ad47"] },
|
|
611
656
|
{ id: "warm", label: "Warm", description: "Reds, oranges and yellows.", palette: ["#b2182b", "#d6604d", "#f4a582", "#e08214", "#fdb863", "#8c510a"] },
|
|
@@ -632,6 +677,10 @@ function chartPresetPatch(options) {
|
|
|
632
677
|
}
|
|
633
678
|
|
|
634
679
|
// src/chart/controller.ts
|
|
680
|
+
function pointLists(s) {
|
|
681
|
+
const lists = [s.values, s.x, s.sizes, s.pointColors, s.callouts, _optionalChain([s, 'access', _27 => _27.errorBars, 'optionalAccess', _28 => _28.plus]), _optionalChain([s, 'access', _29 => _29.errorBars, 'optionalAccess', _30 => _30.minus]), _optionalChain([s, 'access', _31 => _31.xErrorBars, 'optionalAccess', _32 => _32.plus]), _optionalChain([s, 'access', _33 => _33.xErrorBars, 'optionalAccess', _34 => _34.minus])];
|
|
682
|
+
return lists.filter((l) => Array.isArray(l));
|
|
683
|
+
}
|
|
635
684
|
function sameChartJson(a, b) {
|
|
636
685
|
if (a === b) return true;
|
|
637
686
|
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return Number.isNaN(a) && Number.isNaN(b);
|
|
@@ -664,14 +713,14 @@ var ChartController = (_class = class {
|
|
|
664
713
|
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);
|
|
665
714
|
this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkFJ2MSI43cjs.HistoryManager)()));
|
|
666
715
|
this.onChange = options.onChange;
|
|
667
|
-
const { spec, issues } =
|
|
716
|
+
const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, _nullishCoalesce(options.spec, () => ( {})));
|
|
668
717
|
this.spec = spec;
|
|
669
718
|
this.issues = issues;
|
|
670
719
|
this.state = this.computeState();
|
|
671
720
|
this.connect();
|
|
672
721
|
}
|
|
673
722
|
connect() {
|
|
674
|
-
_optionalChain([this, 'access',
|
|
723
|
+
_optionalChain([this, 'access', _35 => _35.unsubscribeHistory, 'optionalCall', _36 => _36()]);
|
|
675
724
|
this.unsubscribeHistory = this.history.subscribe((h) => {
|
|
676
725
|
const s = this.state;
|
|
677
726
|
if (this.applying || s.canUndo === h.canUndo && s.canRedo === h.canRedo && s.undoLabel === h.undoName && s.redoLabel === h.redoName) return;
|
|
@@ -701,12 +750,12 @@ var ChartController = (_class = class {
|
|
|
701
750
|
computeState() {
|
|
702
751
|
const h = this.history.getState();
|
|
703
752
|
const sel = this.selection;
|
|
704
|
-
const seriesId = _optionalChain([sel, 'optionalAccess',
|
|
753
|
+
const seriesId = _optionalChain([sel, 'optionalAccess', _37 => _37.kind]) === "series" || _optionalChain([sel, 'optionalAccess', _38 => _38.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _39 => _39.kind]) === "trendline" ? sel.seriesId : null;
|
|
705
754
|
return {
|
|
706
755
|
spec: this.spec,
|
|
707
756
|
selection: sel,
|
|
708
757
|
selectedSeries: seriesId ? _nullishCoalesce(this.spec.series.find((s) => s.id === seriesId), () => ( null)) : null,
|
|
709
|
-
selectedIndex: _optionalChain([sel, 'optionalAccess',
|
|
758
|
+
selectedIndex: _optionalChain([sel, 'optionalAccess', _40 => _40.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _41 => _41.kind]) === "category" ? sel.index : null,
|
|
710
759
|
issues: this.issues,
|
|
711
760
|
gesture: this.gestureKey,
|
|
712
761
|
canUndo: h.canUndo,
|
|
@@ -719,7 +768,7 @@ var ChartController = (_class = class {
|
|
|
719
768
|
notify(specChanged) {
|
|
720
769
|
this.revision++;
|
|
721
770
|
this.state = this.computeState();
|
|
722
|
-
if (specChanged) _optionalChain([this, 'access',
|
|
771
|
+
if (specChanged) _optionalChain([this, 'access', _42 => _42.onChange, 'optionalCall', _43 => _43(this.spec)]);
|
|
723
772
|
const state = this.state;
|
|
724
773
|
this.listeners.forEach((listener) => {
|
|
725
774
|
try {
|
|
@@ -743,7 +792,7 @@ var ChartController = (_class = class {
|
|
|
743
792
|
case "category":
|
|
744
793
|
return sel.index < spec.categories.length ? sel : null;
|
|
745
794
|
case "trendline":
|
|
746
|
-
return _optionalChain([spec, 'access',
|
|
795
|
+
return _optionalChain([spec, 'access', _44 => _44.series, 'access', _45 => _45.find, 'call', _46 => _46((s) => s.id === sel.seriesId), 'optionalAccess', _47 => _47.trendlines, 'optionalAccess', _48 => _48[sel.index]]) ? sel : null;
|
|
747
796
|
case "title":
|
|
748
797
|
return spec.title ? sel : null;
|
|
749
798
|
case "subtitle":
|
|
@@ -767,7 +816,7 @@ var ChartController = (_class = class {
|
|
|
767
816
|
const hadIssues = this.issues.length > 0;
|
|
768
817
|
this.issues = [];
|
|
769
818
|
if (sameChartJson(before, next)) {
|
|
770
|
-
const reselect = select !== void 0 && !
|
|
819
|
+
const reselect = select !== void 0 && !_chunkSBQVEBSUcjs.sameChartSelection.call(void 0, this.selection, select) && !(select === null && this.selection === null);
|
|
771
820
|
if (reselect) this.selection = select;
|
|
772
821
|
if (reselect || hadIssues) this.notify(false);
|
|
773
822
|
return;
|
|
@@ -790,7 +839,7 @@ var ChartController = (_class = class {
|
|
|
790
839
|
}
|
|
791
840
|
/** A copy of the spec with `edit` applied (series and categories copied as needed). */
|
|
792
841
|
edited(edit) {
|
|
793
|
-
const draft =
|
|
842
|
+
const draft = _chunkR3P2M7HUcjs.cloneChartSpec.call(void 0, this.spec);
|
|
794
843
|
edit(draft);
|
|
795
844
|
return draft;
|
|
796
845
|
}
|
|
@@ -820,7 +869,7 @@ var ChartController = (_class = class {
|
|
|
820
869
|
legend: patch.legend ? { ...s.legend, ...patch.legend } : s.legend,
|
|
821
870
|
version: 1
|
|
822
871
|
};
|
|
823
|
-
const { spec, issues } =
|
|
872
|
+
const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, merged);
|
|
824
873
|
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
825
874
|
if (JSON.stringify(spec) === JSON.stringify(s)) return { ok: true };
|
|
826
875
|
this.commit(_nullishCoalesce(options.label, () => ( updateLabel(patch))), spec);
|
|
@@ -861,17 +910,20 @@ var ChartController = (_class = class {
|
|
|
861
910
|
* to the categories; all-or-nothing like `update`.
|
|
862
911
|
*/
|
|
863
912
|
setData(data, options = {}) {
|
|
864
|
-
|
|
913
|
+
const clear = (data.categories || data.series) && this.spec.tree.length ? { tree: [] } : {};
|
|
914
|
+
return this.update({ ...data.categories ? { categories: data.categories } : {}, ...data.series ? { series: data.series } : {}, ...clear }, { label: _nullishCoalesce(options.label, () => ( "Edit chart data")) });
|
|
865
915
|
}
|
|
866
916
|
/**
|
|
867
917
|
* Sets one value (numbers, numeric text such as `1,200` or `12%`, or blank for a gap).
|
|
868
918
|
* One undo step, or part of the current gesture.
|
|
869
919
|
*/
|
|
870
920
|
setValue(seriesId, index, value, options = {}) {
|
|
921
|
+
const grouped = this.treeLocked();
|
|
922
|
+
if (grouped) return grouped;
|
|
871
923
|
const series = this.getSeries(seriesId);
|
|
872
924
|
if (!series) return this.unknownSeries(seriesId);
|
|
873
925
|
if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
|
|
874
|
-
const parsed =
|
|
926
|
+
const parsed = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, value);
|
|
875
927
|
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.` }]);
|
|
876
928
|
if (series.values[index] === parsed) {
|
|
877
929
|
if (this.issues.length) {
|
|
@@ -888,13 +940,15 @@ var ChartController = (_class = class {
|
|
|
888
940
|
}
|
|
889
941
|
/** Several values as one undo step (all-or-nothing). */
|
|
890
942
|
setValues(cells, options = {}) {
|
|
943
|
+
const grouped = this.treeLocked();
|
|
944
|
+
if (grouped) return grouped;
|
|
891
945
|
const issues = [];
|
|
892
946
|
const parsed = [];
|
|
893
947
|
for (const cell of cells) {
|
|
894
948
|
if (!this.getSeries(cell.seriesId)) issues.push({ path: cell.seriesId, message: this.unknownSeries(cell.seriesId).message });
|
|
895
949
|
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 });
|
|
896
950
|
else {
|
|
897
|
-
const value =
|
|
951
|
+
const value = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, cell.value);
|
|
898
952
|
if (value === void 0) issues.push({ path: `${cell.seriesId}[${cell.index}]`, message: `"${String(cell.value)}" is not a number.` });
|
|
899
953
|
else parsed.push({ seriesId: cell.seriesId, index: cell.index, value });
|
|
900
954
|
}
|
|
@@ -908,12 +962,12 @@ var ChartController = (_class = class {
|
|
|
908
962
|
}
|
|
909
963
|
/** Adds a series (values padded to the categories) and selects it. Returns its id. */
|
|
910
964
|
addSeries(input = {}, options = {}) {
|
|
911
|
-
const id = input.id && !this.getSeries(input.id) ? input.id :
|
|
965
|
+
const id = input.id && !this.getSeries(input.id) ? input.id : _chunkR3P2M7HUcjs.uniqueChartSeriesId.call(void 0, this.spec.series);
|
|
912
966
|
const name = _nullishCoalesce(input.name, () => ( `Series ${this.spec.series.length + 1}`));
|
|
913
967
|
const at = Math.max(0, Math.min(this.spec.series.length, _nullishCoalesce(options.at, () => ( this.spec.series.length))));
|
|
914
968
|
const series = [...this.spec.series];
|
|
915
969
|
series.splice(at, 0, { ...input, id, name, values: _nullishCoalesce(input.values, () => ( [])) });
|
|
916
|
-
const { spec, issues } =
|
|
970
|
+
const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, series });
|
|
917
971
|
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
918
972
|
this.commit(`Add series "${name}"`, spec, { kind: "series", seriesId: id });
|
|
919
973
|
return { ok: true, id };
|
|
@@ -925,6 +979,7 @@ var ChartController = (_class = class {
|
|
|
925
979
|
`Delete series "${series.name}"`,
|
|
926
980
|
this.edited((d) => {
|
|
927
981
|
d.series = d.series.filter((s) => s.id !== id);
|
|
982
|
+
d.highlight = d.highlight.filter((h) => h !== id && (h !== series.name || d.series.some((s) => s.name === h) || d.categories.includes(h)));
|
|
928
983
|
})
|
|
929
984
|
);
|
|
930
985
|
return { ok: true };
|
|
@@ -932,7 +987,7 @@ var ChartController = (_class = class {
|
|
|
932
987
|
updateSeries(id, patch) {
|
|
933
988
|
const series = this.getSeries(id);
|
|
934
989
|
if (!series) return this.unknownSeries(id);
|
|
935
|
-
const next =
|
|
990
|
+
const next = _chunkR3P2M7HUcjs.cloneChartSeries.call(void 0, series);
|
|
936
991
|
if (patch.name !== void 0) next.name = String(patch.name);
|
|
937
992
|
if (patch.color === null || patch.color === "") delete next.color;
|
|
938
993
|
else if (patch.color !== void 0) next.color = patch.color;
|
|
@@ -942,7 +997,7 @@ var ChartController = (_class = class {
|
|
|
942
997
|
if (patch.hidden) next.hidden = true;
|
|
943
998
|
else delete next.hidden;
|
|
944
999
|
}
|
|
945
|
-
const resettable = ["axis", "x", "sizes", "pointColors", "marker", "curve", "dataLabels", "format", "errorBars", "xErrorBars"];
|
|
1000
|
+
const resettable = ["axis", "x", "sizes", "pointColors", "callouts", "marker", "curve", "dataLabels", "format", "errorBars", "xErrorBars"];
|
|
946
1001
|
for (const key of resettable) {
|
|
947
1002
|
if (!(key in patch) || patch[key] === void 0) continue;
|
|
948
1003
|
if (patch[key] === null) delete next[key];
|
|
@@ -950,7 +1005,9 @@ var ChartController = (_class = class {
|
|
|
950
1005
|
}
|
|
951
1006
|
if (next.axis === "primary") delete next.axis;
|
|
952
1007
|
const series2 = this.spec.series.map((s) => s.id === id ? next : s);
|
|
953
|
-
const
|
|
1008
|
+
const renamed = next.name !== series.name && this.spec.highlight.includes(series.name) && !this.spec.categories.includes(series.name);
|
|
1009
|
+
const highlight = renamed ? this.spec.highlight.map((h) => h === series.name ? next.name : h) : this.spec.highlight;
|
|
1010
|
+
const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, series: series2, highlight });
|
|
954
1011
|
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
955
1012
|
if (JSON.stringify(spec.series) === JSON.stringify(this.spec.series)) return { ok: true };
|
|
956
1013
|
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}"`;
|
|
@@ -979,41 +1036,52 @@ var ChartController = (_class = class {
|
|
|
979
1036
|
}
|
|
980
1037
|
/** Inserts a category (with gaps in every series) at `at` (default: the end). Returns its index. */
|
|
981
1038
|
addCategory(label, options = {}) {
|
|
1039
|
+
const grouped = this.treeLocked();
|
|
1040
|
+
if (grouped) return grouped;
|
|
982
1041
|
const at = Math.max(0, Math.min(this.spec.categories.length, _nullishCoalesce(options.at, () => ( this.spec.categories.length))));
|
|
983
1042
|
const name = _nullishCoalesce(label, () => ( `${this.spec.categories.length + 1}`));
|
|
984
1043
|
this.commit(
|
|
985
1044
|
`Add category "${name}"`,
|
|
986
1045
|
this.edited((d) => {
|
|
987
1046
|
d.categories.splice(at, 0, name);
|
|
988
|
-
for (const s of d.series) s.
|
|
1047
|
+
for (const s of d.series) for (const list of pointLists(s)) list.splice(at, 0, null);
|
|
989
1048
|
}),
|
|
990
1049
|
{ kind: "category", index: at }
|
|
991
1050
|
);
|
|
992
1051
|
return { ok: true, index: at };
|
|
993
1052
|
}
|
|
994
1053
|
removeCategory(index) {
|
|
1054
|
+
const grouped = this.treeLocked();
|
|
1055
|
+
if (grouped) return grouped;
|
|
995
1056
|
if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
|
|
996
1057
|
this.commit(
|
|
997
1058
|
`Delete category "${this.spec.categories[index]}"`,
|
|
998
1059
|
this.edited((d) => {
|
|
999
|
-
d.categories.splice(index, 1);
|
|
1000
|
-
for (const s of d.series) s.
|
|
1060
|
+
const [label] = d.categories.splice(index, 1);
|
|
1061
|
+
for (const s of d.series) for (const list of pointLists(s)) list.splice(index, 1);
|
|
1062
|
+
if (!d.categories.includes(label)) d.highlight = d.highlight.filter((h) => h !== label);
|
|
1001
1063
|
})
|
|
1002
1064
|
);
|
|
1003
1065
|
return { ok: true };
|
|
1004
1066
|
}
|
|
1005
1067
|
renameCategory(index, label) {
|
|
1068
|
+
const grouped = this.treeLocked();
|
|
1069
|
+
if (grouped) return grouped;
|
|
1006
1070
|
if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
|
|
1007
1071
|
if (this.spec.categories[index] === label) return { ok: true };
|
|
1008
1072
|
this.commit(
|
|
1009
1073
|
"Rename category",
|
|
1010
1074
|
this.edited((d) => {
|
|
1075
|
+
const before = d.categories[index];
|
|
1011
1076
|
d.categories[index] = String(label);
|
|
1077
|
+
if (d.highlight.includes(before) && !d.categories.includes(before)) d.highlight = d.highlight.map((h) => h === before ? String(label) : h);
|
|
1012
1078
|
})
|
|
1013
1079
|
);
|
|
1014
1080
|
return { ok: true };
|
|
1015
1081
|
}
|
|
1016
1082
|
moveCategory(from, to) {
|
|
1083
|
+
const grouped = this.treeLocked();
|
|
1084
|
+
if (grouped) return grouped;
|
|
1017
1085
|
if (!Number.isInteger(from) || from < 0 || from >= this.spec.categories.length) return this.badIndex(from);
|
|
1018
1086
|
const target = Math.max(0, Math.min(this.spec.categories.length - 1, to));
|
|
1019
1087
|
if (target === from) return { ok: true };
|
|
@@ -1025,7 +1093,7 @@ var ChartController = (_class = class {
|
|
|
1025
1093
|
"Reorder categories",
|
|
1026
1094
|
this.edited((d) => {
|
|
1027
1095
|
move(d.categories);
|
|
1028
|
-
for (const s of d.series)
|
|
1096
|
+
for (const s of d.series) for (const list of pointLists(s)) move(list);
|
|
1029
1097
|
})
|
|
1030
1098
|
);
|
|
1031
1099
|
return { ok: true };
|
|
@@ -1036,6 +1104,8 @@ var ChartController = (_class = class {
|
|
|
1036
1104
|
* grid grows to fit. Non-numeric value cells become gaps and are reported in `issues`.
|
|
1037
1105
|
*/
|
|
1038
1106
|
pasteCells(row, column, cells) {
|
|
1107
|
+
const grouped = this.treeLocked();
|
|
1108
|
+
if (grouped) return grouped;
|
|
1039
1109
|
const rows = typeof cells === "string" ? cells.includes(" ") ? _chunkN3KJFGXTcjs.parseTsv.call(void 0, cells) : _chunkN3KJFGXTcjs.parseCsv.call(void 0, cells) : cells.map((r) => [...r]);
|
|
1040
1110
|
if (!rows.length) return { ok: true };
|
|
1041
1111
|
const issues = [];
|
|
@@ -1043,7 +1113,7 @@ var ChartController = (_class = class {
|
|
|
1043
1113
|
const width = Math.max(...rows.map((r) => r.length));
|
|
1044
1114
|
const lastSeries = column + width - 1;
|
|
1045
1115
|
while (d.series.length <= lastSeries) {
|
|
1046
|
-
const id =
|
|
1116
|
+
const id = _chunkR3P2M7HUcjs.uniqueChartSeriesId.call(void 0, d.series);
|
|
1047
1117
|
d.series.push({ id, name: `Series ${d.series.length + 1}`, values: d.categories.map(() => null) });
|
|
1048
1118
|
}
|
|
1049
1119
|
const lastRow = row + rows.length - 1;
|
|
@@ -1057,7 +1127,7 @@ var ChartController = (_class = class {
|
|
|
1057
1127
|
const index = row + r;
|
|
1058
1128
|
if (col < 0) d.categories[index] = cell === null || cell === void 0 ? "" : String(cell).trim();
|
|
1059
1129
|
else {
|
|
1060
|
-
const parsed =
|
|
1130
|
+
const parsed = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, cell);
|
|
1061
1131
|
if (parsed === void 0) issues.push({ path: `${d.series[col].id}[${index}]`, message: `"${String(cell)}" is not a number; it was left blank.` });
|
|
1062
1132
|
d.series[col].values[index] = _nullishCoalesce(parsed, () => ( null));
|
|
1063
1133
|
}
|
|
@@ -1076,14 +1146,14 @@ var ChartController = (_class = class {
|
|
|
1076
1146
|
* colours and types are kept by name.
|
|
1077
1147
|
*/
|
|
1078
1148
|
importTable(rows, options = {}) {
|
|
1079
|
-
const data =
|
|
1149
|
+
const data = _chunkR3P2M7HUcjs.chartDataFromTable.call(void 0, rows, options);
|
|
1080
1150
|
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.");
|
|
1081
1151
|
const byName = new Map(this.spec.series.map((s) => [s.name, s]));
|
|
1082
1152
|
const series = data.series.map((s) => {
|
|
1083
1153
|
const old = byName.get(s.name);
|
|
1084
|
-
return { ...s, ..._optionalChain([old, 'optionalAccess',
|
|
1154
|
+
return { ...s, ..._optionalChain([old, 'optionalAccess', _49 => _49.color]) ? { color: old.color } : {}, ..._optionalChain([old, 'optionalAccess', _50 => _50.type]) ? { type: old.type } : {}, ...old ? { id: old.id } : {} };
|
|
1085
1155
|
});
|
|
1086
|
-
const { spec } =
|
|
1156
|
+
const { spec } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, categories: data.categories, series, tree: [] });
|
|
1087
1157
|
this.commit("Import data", spec);
|
|
1088
1158
|
if (data.issues.length) {
|
|
1089
1159
|
this.issues = data.issues;
|
|
@@ -1098,18 +1168,264 @@ var ChartController = (_class = class {
|
|
|
1098
1168
|
return this.importTable(_chunkN3KJFGXTcjs.parseCsv.call(void 0, text, { delimiter }), options);
|
|
1099
1169
|
}
|
|
1100
1170
|
// -------------------------------------------------------------------------
|
|
1171
|
+
// Grouped data (tree)
|
|
1172
|
+
// -------------------------------------------------------------------------
|
|
1173
|
+
/** A refusal while the data is a tree (cell edits would be overwritten by its totals), else null. */
|
|
1174
|
+
treeLocked() {
|
|
1175
|
+
if (!this.spec.tree.length) return null;
|
|
1176
|
+
return this.reject(
|
|
1177
|
+
"This chart's data is grouped (a tree): its categories and values are the top-level groups and their totals. Change it with setTree / the tree node edits (set_chart_tree, add_chart_tree_node, update_chart_tree_node, remove_chart_tree_node), or replace it with new data."
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
/** Replaces the grouped data (an empty list goes back to the table, keeping the totals as values). One undo step. */
|
|
1181
|
+
setTree(tree, options = {}) {
|
|
1182
|
+
const issues = [];
|
|
1183
|
+
const next = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, tree, issues);
|
|
1184
|
+
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1185
|
+
return this.update({ tree: next }, { label: _nullishCoalesce(options.label, () => ( (next.length ? "Replace grouped data" : "Ungroup data"))) });
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Replaces the grouped data from rows of names and a value (group, …, item, value), as the
|
|
1189
|
+
* data grid edits it; colours of nodes whose path is unchanged are kept. All-or-nothing.
|
|
1190
|
+
*/
|
|
1191
|
+
setTreeRows(rows, options = {}) {
|
|
1192
|
+
const issues = [];
|
|
1193
|
+
const next = _chunkR3P2M7HUcjs.chartTreeFromRows.call(void 0, rows, issues);
|
|
1194
|
+
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1195
|
+
const keepColors = (list, prefix) => {
|
|
1196
|
+
for (const n of list) {
|
|
1197
|
+
const old = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, [...prefix, n.name]);
|
|
1198
|
+
if (_optionalChain([old, 'optionalAccess', _51 => _51.color])) n.color = old.color;
|
|
1199
|
+
if (n.children) keepColors(n.children, [...prefix, n.name]);
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
keepColors(next, []);
|
|
1203
|
+
return this.update({ tree: next }, { label: _nullishCoalesce(options.label, () => ( "Edit grouped data")) });
|
|
1204
|
+
}
|
|
1205
|
+
/** Replaces the data with a table of names and values (group, …, item, value); see `chartTreeFromTable`. */
|
|
1206
|
+
importTreeTable(rows, options = {}) {
|
|
1207
|
+
const issues = [];
|
|
1208
|
+
const next = _chunkR3P2M7HUcjs.chartTreeFromTable.call(void 0, rows, options, issues);
|
|
1209
|
+
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1210
|
+
if (!next.length) return this.reject('There is no grouped data to import: expected rows of names followed by a value, e.g. "Europe,France,40".');
|
|
1211
|
+
return this.update({ tree: next }, { label: "Import grouped data" });
|
|
1212
|
+
}
|
|
1213
|
+
nodeAt(path) {
|
|
1214
|
+
const node = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path);
|
|
1215
|
+
if (node) return node;
|
|
1216
|
+
const known = path.length > 1 ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path.slice(0, -1)) : null;
|
|
1217
|
+
const siblings = _nullishCoalesce((path.length > 1 ? _optionalChain([known, 'optionalAccess', _52 => _52.children]) : this.spec.tree), () => ( []));
|
|
1218
|
+
return fail(
|
|
1219
|
+
`There is no node ${JSON.stringify(path)}. ${siblings.length ? `${path.length > 1 && known ? `"${known.name}" contains` : "The top level has"} ${siblings.map((n) => `"${n.name}"`).slice(0, 20).join(", ")}.` : "The chart has no grouped data yet; add nodes with add_chart_tree_node or set_chart_tree."}`
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
/** Adds a node under the group at `parent` ([] for the top level) at `at` (default: the end). Returns its path. */
|
|
1223
|
+
addTreeNode(parent, input, options = {}) {
|
|
1224
|
+
let siblings = this.spec.tree;
|
|
1225
|
+
if (parent.length) {
|
|
1226
|
+
const group = this.nodeAt(parent);
|
|
1227
|
+
if ("ok" in group) return group;
|
|
1228
|
+
if (!group.children) return this.reject(`"${group.name}" is an item with its own value, not a group; add the node next to it, or turn it into a group by replacing the tree with set_chart_tree.`);
|
|
1229
|
+
siblings = group.children;
|
|
1230
|
+
}
|
|
1231
|
+
const issues = [];
|
|
1232
|
+
const [node] = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, [input], issues, "node");
|
|
1233
|
+
if (!node || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The node is not valid.", issues);
|
|
1234
|
+
if (siblings.some((n) => n.name === node.name)) return this.reject(`"${node.name}" is already there; names under one group must be unique.`);
|
|
1235
|
+
const at = Math.max(0, Math.min(siblings.length, _nullishCoalesce(options.at, () => ( siblings.length))));
|
|
1236
|
+
const tree = _chunkR3P2M7HUcjs.cloneChartTree.call(void 0, this.spec.tree);
|
|
1237
|
+
const list = parent.length ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, tree, parent).children : tree;
|
|
1238
|
+
list.splice(at, 0, node);
|
|
1239
|
+
const result = this.update({ tree }, { label: `Add "${node.name}"` });
|
|
1240
|
+
if (!result.ok) return result;
|
|
1241
|
+
return { ok: true, path: [...parent, node.name] };
|
|
1242
|
+
}
|
|
1243
|
+
/** Renames, revalues (items only) or recolours a node; `color: null` goes back to the palette. Returns its path. */
|
|
1244
|
+
updateTreeNode(path, patch) {
|
|
1245
|
+
const node = this.nodeAt(path);
|
|
1246
|
+
if ("ok" in node) return node;
|
|
1247
|
+
if (patch.value !== void 0 && node.children) return this.reject(`"${node.name}" is a group: its value is the sum of its items. Change the items instead.`);
|
|
1248
|
+
const name = patch.name !== void 0 ? String(patch.name).trim() : node.name;
|
|
1249
|
+
const siblings = (path.length > 1 ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path.slice(0, -1)).children : this.spec.tree).filter((n) => n !== node);
|
|
1250
|
+
if (siblings.some((n) => n.name === name)) return this.reject(`There is already a "${name}" next to "${node.name}"; names under one group must be unique.`);
|
|
1251
|
+
const tree = _chunkR3P2M7HUcjs.cloneChartTree.call(void 0, this.spec.tree);
|
|
1252
|
+
const target = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, tree, path);
|
|
1253
|
+
const merged = { ...target, name };
|
|
1254
|
+
if (patch.value !== void 0) merged.value = patch.value;
|
|
1255
|
+
if (patch.color === null) delete merged.color;
|
|
1256
|
+
else if (patch.color !== void 0) merged.color = patch.color;
|
|
1257
|
+
const issues = [];
|
|
1258
|
+
const [checked] = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, [merged], issues, "node");
|
|
1259
|
+
if (!checked || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1260
|
+
Object.assign(target, checked);
|
|
1261
|
+
if (patch.color === null) delete target.color;
|
|
1262
|
+
const result = this.update({ tree }, { label: patch.name !== void 0 && patch.name !== node.name ? "Rename group" : `Change "${node.name}"` });
|
|
1263
|
+
if (!result.ok) return result;
|
|
1264
|
+
return { ok: true, path: [...path.slice(0, -1), name] };
|
|
1265
|
+
}
|
|
1266
|
+
/** Removes a node (with everything under it). A group left empty becomes an item with value 0. */
|
|
1267
|
+
removeTreeNode(path) {
|
|
1268
|
+
const node = this.nodeAt(path);
|
|
1269
|
+
if ("ok" in node) return node;
|
|
1270
|
+
const tree = _chunkR3P2M7HUcjs.cloneChartTree.call(void 0, this.spec.tree);
|
|
1271
|
+
const parent = path.length > 1 ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, tree, path.slice(0, -1)) : null;
|
|
1272
|
+
const list = parent ? parent.children : tree;
|
|
1273
|
+
list.splice(
|
|
1274
|
+
list.findIndex((n) => n.name === node.name),
|
|
1275
|
+
1
|
|
1276
|
+
);
|
|
1277
|
+
if (parent && !parent.children.length) {
|
|
1278
|
+
delete parent.children;
|
|
1279
|
+
parent.value = 0;
|
|
1280
|
+
}
|
|
1281
|
+
return this.update({ tree }, { label: `Delete "${node.name}"` });
|
|
1282
|
+
}
|
|
1283
|
+
// -------------------------------------------------------------------------
|
|
1284
|
+
// Annotations
|
|
1285
|
+
// -------------------------------------------------------------------------
|
|
1286
|
+
/** Sets the note written under the chart ("" removes it). */
|
|
1287
|
+
setNote(note) {
|
|
1288
|
+
return this.update({ note }, { label: note ? "Edit note" : "Remove note" });
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Draws the named categories (labels) and series (names or ids) normally and mutes the
|
|
1292
|
+
* rest; an empty list shows everything. Unknown names change nothing. Returns the category
|
|
1293
|
+
* indexes and series ids that matched.
|
|
1294
|
+
*/
|
|
1295
|
+
setHighlight(names) {
|
|
1296
|
+
const s = this.spec;
|
|
1297
|
+
const list = [...new Set(names.map(String))];
|
|
1298
|
+
const unknown = list.filter((n) => !s.categories.includes(n) && !s.series.some((x) => x.id === n || x.name === n));
|
|
1299
|
+
if (unknown.length)
|
|
1300
|
+
return this.reject(
|
|
1301
|
+
`${unknown.map((u) => `"${u}"`).join(", ")} ${unknown.length === 1 ? "is" : "are"} neither a category nor a series. Categories: ${s.categories.slice(0, 20).map((c) => `"${c}"`).join(", ") || "(none)"}; series: ${s.series.map((x) => `"${x.name}"`).join(", ") || "(none)"}.`
|
|
1302
|
+
);
|
|
1303
|
+
const result = this.update({ highlight: list }, { label: list.length ? "Highlight" : "Clear highlight" });
|
|
1304
|
+
if (!result.ok) return result;
|
|
1305
|
+
return {
|
|
1306
|
+
ok: true,
|
|
1307
|
+
categories: s.categories.flatMap((c, i) => list.includes(c) ? [i] : []),
|
|
1308
|
+
series: s.series.filter((x) => list.includes(x.id) || list.includes(x.name)).map((x) => x.id)
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
/** Why a reference on `axis` at `values` cannot be drawn on this chart, or null. */
|
|
1312
|
+
referenceProblem(axis, values) {
|
|
1313
|
+
const s = this.spec;
|
|
1314
|
+
const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, s);
|
|
1315
|
+
if (family !== "cartesian" && family !== "xy") return `Reference lines and bands are drawn on bar, line, area, scatter and bubble charts; this is a ${s.type} chart.`;
|
|
1316
|
+
if (axis === "x" && family !== "xy") return 'axis "x" needs a scatter or bubble chart with numeric x values; use "y" for the value axis.';
|
|
1317
|
+
if (axis === "y2" && (family !== "cartesian" || !s.series.some((x) => !x.hidden && x.axis === "secondary")))
|
|
1318
|
+
return 'axis "y2" needs a visible series on the secondary axis (set one with update_chart_series axis "secondary"), or use "y".';
|
|
1319
|
+
const scale = (axis === "x" ? s.xAxis : axis === "y2" ? s.yAxis2 : s.yAxis).scale;
|
|
1320
|
+
if (scale === "log" && values.some((v) => !(v > 0))) return "That axis is logarithmic, so the values must be above 0.";
|
|
1321
|
+
return null;
|
|
1322
|
+
}
|
|
1323
|
+
editReferences(kind, label, edit, select) {
|
|
1324
|
+
this.commit(
|
|
1325
|
+
label,
|
|
1326
|
+
this.edited((d) => edit(d[kind])),
|
|
1327
|
+
select
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
/** Adds a reference line (a target, floor or average). Returns its index. */
|
|
1331
|
+
addReferenceLine(input) {
|
|
1332
|
+
const issues = [];
|
|
1333
|
+
const line = _chunkR3P2M7HUcjs.normalizeChartReferenceLine.call(void 0, input, "referenceLine", issues);
|
|
1334
|
+
if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1335
|
+
const problem = this.referenceProblem(line.axis, [line.value]);
|
|
1336
|
+
if (problem) return this.reject(problem);
|
|
1337
|
+
const index = this.spec.referenceLines.length;
|
|
1338
|
+
this.editReferences("referenceLines", `Add reference line${line.label ? ` "${line.label}"` : ""}`, (list) => list.push(line));
|
|
1339
|
+
return { ok: true, index };
|
|
1340
|
+
}
|
|
1341
|
+
/** Changes a reference line (all-or-nothing); `null` removes its label, colour or axis. */
|
|
1342
|
+
updateReferenceLine(index, patch) {
|
|
1343
|
+
const current = this.spec.referenceLines[index];
|
|
1344
|
+
if (!current) return fail(this.noReference("reference line", this.spec.referenceLines.length, index));
|
|
1345
|
+
const merged = { ...current, ...patch };
|
|
1346
|
+
for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
|
|
1347
|
+
const issues = [];
|
|
1348
|
+
const line = _chunkR3P2M7HUcjs.normalizeChartReferenceLine.call(void 0, merged, "referenceLine", issues);
|
|
1349
|
+
if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1350
|
+
const problem = this.referenceProblem(line.axis, [line.value]);
|
|
1351
|
+
if (problem) return this.reject(problem);
|
|
1352
|
+
this.editReferences("referenceLines", "Change reference line", (list) => list[index] = line);
|
|
1353
|
+
return { ok: true };
|
|
1354
|
+
}
|
|
1355
|
+
removeReferenceLine(index) {
|
|
1356
|
+
if (!this.spec.referenceLines[index]) return fail(this.noReference("reference line", this.spec.referenceLines.length, index));
|
|
1357
|
+
this.editReferences("referenceLines", "Delete reference line", (list) => list.splice(index, 1));
|
|
1358
|
+
return { ok: true };
|
|
1359
|
+
}
|
|
1360
|
+
/** Adds a reference band (a target range). Returns its index. */
|
|
1361
|
+
addReferenceBand(input) {
|
|
1362
|
+
const issues = [];
|
|
1363
|
+
const band = _chunkR3P2M7HUcjs.normalizeChartReferenceBand.call(void 0, input, "referenceBand", issues);
|
|
1364
|
+
if (!band || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1365
|
+
const problem = this.referenceProblem(band.axis, [band.from, band.to]);
|
|
1366
|
+
if (problem) return this.reject(problem);
|
|
1367
|
+
const index = this.spec.referenceBands.length;
|
|
1368
|
+
this.editReferences("referenceBands", `Add reference band${band.label ? ` "${band.label}"` : ""}`, (list) => list.push(band));
|
|
1369
|
+
return { ok: true, index };
|
|
1370
|
+
}
|
|
1371
|
+
/** Changes a reference band (all-or-nothing); `null` removes its label, colour or axis. */
|
|
1372
|
+
updateReferenceBand(index, patch) {
|
|
1373
|
+
const current = this.spec.referenceBands[index];
|
|
1374
|
+
if (!current) return fail(this.noReference("reference band", this.spec.referenceBands.length, index));
|
|
1375
|
+
const merged = { ...current, ...patch };
|
|
1376
|
+
for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
|
|
1377
|
+
const issues = [];
|
|
1378
|
+
const band = _chunkR3P2M7HUcjs.normalizeChartReferenceBand.call(void 0, merged, "referenceBand", issues);
|
|
1379
|
+
if (!band || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1380
|
+
const problem = this.referenceProblem(band.axis, [band.from, band.to]);
|
|
1381
|
+
if (problem) return this.reject(problem);
|
|
1382
|
+
this.editReferences("referenceBands", "Change reference band", (list) => list[index] = band);
|
|
1383
|
+
return { ok: true };
|
|
1384
|
+
}
|
|
1385
|
+
removeReferenceBand(index) {
|
|
1386
|
+
if (!this.spec.referenceBands[index]) return fail(this.noReference("reference band", this.spec.referenceBands.length, index));
|
|
1387
|
+
this.editReferences("referenceBands", "Delete reference band", (list) => list.splice(index, 1));
|
|
1388
|
+
return { ok: true };
|
|
1389
|
+
}
|
|
1390
|
+
noReference(what, count, index) {
|
|
1391
|
+
return `There is no ${what} ${index}; ${count ? `expected 0 to ${count - 1}` : `the chart has none yet`}.`;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Pins a label to one bar or point (`null` or "" removes it) and selects the point. The
|
|
1395
|
+
* point must have a value, on a bar, line, area, scatter or bubble chart.
|
|
1396
|
+
*/
|
|
1397
|
+
setCallout(seriesId, index, label) {
|
|
1398
|
+
const series = this.getSeries(seriesId);
|
|
1399
|
+
if (!series) return this.unknownSeries(seriesId);
|
|
1400
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
|
|
1401
|
+
const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, this.spec);
|
|
1402
|
+
const text = label === null ? "" : String(label).trim();
|
|
1403
|
+
if (text && family !== "cartesian" && family !== "xy") return this.reject(`Callouts are drawn on bar, line, area, scatter and bubble charts; this is a ${this.spec.type} chart.`);
|
|
1404
|
+
if (text && (series.values[index] === null || series.values[index] === void 0))
|
|
1405
|
+
return this.reject(`"${series.name}" has no value at "${this.spec.categories[index]}", so there is nothing to point at; set a value first.`);
|
|
1406
|
+
const next = this.edited((d) => {
|
|
1407
|
+
const s = d.series.find((x) => x.id === seriesId);
|
|
1408
|
+
const labels = s.callouts ? [...s.callouts] : d.categories.map(() => null);
|
|
1409
|
+
labels[index] = text || null;
|
|
1410
|
+
if (labels.some((l) => l)) s.callouts = labels;
|
|
1411
|
+
else delete s.callouts;
|
|
1412
|
+
});
|
|
1413
|
+
this.commit(text ? "Add callout" : "Remove callout", next, { kind: "point", seriesId, index });
|
|
1414
|
+
return { ok: true };
|
|
1415
|
+
}
|
|
1416
|
+
// -------------------------------------------------------------------------
|
|
1101
1417
|
// Trendlines
|
|
1102
1418
|
// -------------------------------------------------------------------------
|
|
1103
1419
|
/** Adds a trendline to a series and selects it. Returns its index (and the fit, when it can be computed). */
|
|
1104
1420
|
addTrendline(seriesId, input) {
|
|
1105
1421
|
const series = this.getSeries(seriesId);
|
|
1106
1422
|
if (!series) return this.unknownSeries(seriesId);
|
|
1107
|
-
if (!
|
|
1423
|
+
if (!_chunkSBQVEBSUcjs.chartSupportsTrendlines.call(void 0, this.spec.type, this.spec.stacking))
|
|
1108
1424
|
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.`);
|
|
1109
1425
|
const issues = [];
|
|
1110
|
-
const line =
|
|
1426
|
+
const line = _chunkR3P2M7HUcjs.normalizeChartTrendline.call(void 0, input, "trendline", issues);
|
|
1111
1427
|
if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The trendline is not valid.", issues);
|
|
1112
|
-
const index = _nullishCoalesce(_optionalChain([series, 'access',
|
|
1428
|
+
const index = _nullishCoalesce(_optionalChain([series, 'access', _53 => _53.trendlines, 'optionalAccess', _54 => _54.length]), () => ( 0));
|
|
1113
1429
|
const next = this.edited((d) => {
|
|
1114
1430
|
const s = d.series.find((x) => x.id === seriesId);
|
|
1115
1431
|
s.trendlines = [..._nullishCoalesce(s.trendlines, () => ( [])), line];
|
|
@@ -1121,12 +1437,12 @@ var ChartController = (_class = class {
|
|
|
1121
1437
|
updateTrendline(seriesId, index, patch) {
|
|
1122
1438
|
const series = this.getSeries(seriesId);
|
|
1123
1439
|
if (!series) return this.unknownSeries(seriesId);
|
|
1124
|
-
const current = _optionalChain([series, 'access',
|
|
1125
|
-
if (!current) return fail(`"${series.name}" has no trendline ${index}; ${_optionalChain([series, 'access',
|
|
1440
|
+
const current = _optionalChain([series, 'access', _55 => _55.trendlines, 'optionalAccess', _56 => _56[index]]);
|
|
1441
|
+
if (!current) return fail(`"${series.name}" has no trendline ${index}; ${_optionalChain([series, 'access', _57 => _57.trendlines, 'optionalAccess', _58 => _58.length]) ? `expected 0 to ${series.trendlines.length - 1}` : "it has none yet"}.`);
|
|
1126
1442
|
const issues = [];
|
|
1127
1443
|
const merged = { ...current, ...patch };
|
|
1128
1444
|
for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
|
|
1129
|
-
const line =
|
|
1445
|
+
const line = _chunkR3P2M7HUcjs.normalizeChartTrendline.call(void 0, merged, "trendline", issues);
|
|
1130
1446
|
if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1131
1447
|
this.commit(
|
|
1132
1448
|
"Change trendline",
|
|
@@ -1139,7 +1455,7 @@ var ChartController = (_class = class {
|
|
|
1139
1455
|
removeTrendline(seriesId, index) {
|
|
1140
1456
|
const series = this.getSeries(seriesId);
|
|
1141
1457
|
if (!series) return this.unknownSeries(seriesId);
|
|
1142
|
-
if (!_optionalChain([series, 'access',
|
|
1458
|
+
if (!_optionalChain([series, 'access', _59 => _59.trendlines, 'optionalAccess', _60 => _60[index]])) return fail(`"${series.name}" has no trendline ${index}.`);
|
|
1143
1459
|
this.commit(
|
|
1144
1460
|
"Delete trendline",
|
|
1145
1461
|
this.edited((d) => {
|
|
@@ -1154,25 +1470,25 @@ var ChartController = (_class = class {
|
|
|
1154
1470
|
trendlinePoints(seriesId) {
|
|
1155
1471
|
const series = this.getSeries(seriesId);
|
|
1156
1472
|
if (!series) return [];
|
|
1157
|
-
const xy =
|
|
1473
|
+
const xy = _chunkR3P2M7HUcjs.chartFamily.call(void 0, this.spec) === "xy";
|
|
1158
1474
|
const out = [];
|
|
1159
1475
|
series.values.forEach((v, i) => {
|
|
1160
|
-
const x = xy ? _nullishCoalesce(_optionalChain([series, 'access',
|
|
1476
|
+
const x = xy ? _nullishCoalesce(_optionalChain([series, 'access', _61 => _61.x, 'optionalAccess', _62 => _62[i]]), () => ( (this.spec.type === "bubble" ? i + 1 : null))) : i + 1;
|
|
1161
1477
|
if (v !== null && x !== null && Number.isFinite(v) && Number.isFinite(x)) out.push([x, v]);
|
|
1162
1478
|
});
|
|
1163
1479
|
return out;
|
|
1164
1480
|
}
|
|
1165
1481
|
/** The fitted coefficients, R² and equation of a trendline (null for moving averages or unfittable data). */
|
|
1166
1482
|
trendlineFit(seriesId, index) {
|
|
1167
|
-
const line = _optionalChain([this, 'access',
|
|
1483
|
+
const line = _optionalChain([this, 'access', _63 => _63.getSeries, 'call', _64 => _64(seriesId), 'optionalAccess', _65 => _65.trendlines, 'optionalAccess', _66 => _66[index]]);
|
|
1168
1484
|
if (!line) return null;
|
|
1169
|
-
return
|
|
1485
|
+
return _chunkSBQVEBSUcjs.fitChartTrendline.call(void 0, line, this.trendlinePoints(seriesId));
|
|
1170
1486
|
}
|
|
1171
1487
|
/** The moving-average points of a trendline (empty for other kinds). */
|
|
1172
1488
|
trendlineMovingAverage(seriesId, index) {
|
|
1173
|
-
const line = _optionalChain([this, 'access',
|
|
1489
|
+
const line = _optionalChain([this, 'access', _67 => _67.getSeries, 'call', _68 => _68(seriesId), 'optionalAccess', _69 => _69.trendlines, 'optionalAccess', _70 => _70[index]]);
|
|
1174
1490
|
if (!line || line.type !== "moving-average") return [];
|
|
1175
|
-
return
|
|
1491
|
+
return _chunkSBQVEBSUcjs.chartMovingAverage.call(void 0, this.trendlinePoints(seriesId), _nullishCoalesce(line.period, () => ( 2)));
|
|
1176
1492
|
}
|
|
1177
1493
|
// -------------------------------------------------------------------------
|
|
1178
1494
|
// Reshaping
|
|
@@ -1182,6 +1498,8 @@ var ChartController = (_class = class {
|
|
|
1182
1498
|
* undo step). Series colours, types and other per-series settings are dropped.
|
|
1183
1499
|
*/
|
|
1184
1500
|
transpose() {
|
|
1501
|
+
const grouped = this.treeLocked();
|
|
1502
|
+
if (grouped) return grouped;
|
|
1185
1503
|
const s = this.spec;
|
|
1186
1504
|
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.");
|
|
1187
1505
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -1191,7 +1509,7 @@ var ChartController = (_class = class {
|
|
|
1191
1509
|
used.add(id);
|
|
1192
1510
|
return { id, name, values: s.series.map((x) => _nullishCoalesce(x.values[i], () => ( null))) };
|
|
1193
1511
|
});
|
|
1194
|
-
const { spec } =
|
|
1512
|
+
const { spec } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...s, categories: s.series.map((x) => x.name), series });
|
|
1195
1513
|
this.commit("Switch rows and columns", spec, null);
|
|
1196
1514
|
return { ok: true };
|
|
1197
1515
|
}
|
|
@@ -1201,7 +1519,7 @@ var ChartController = (_class = class {
|
|
|
1201
1519
|
/** Selects a chart element (view state; not an undo step). */
|
|
1202
1520
|
select(selection) {
|
|
1203
1521
|
const next = this.validSelection(selection, this.spec);
|
|
1204
|
-
if (
|
|
1522
|
+
if (_chunkSBQVEBSUcjs.sameChartSelection.call(void 0, next, this.selection) || next === null && this.selection === null) return;
|
|
1205
1523
|
this.selection = next;
|
|
1206
1524
|
this.notify(false);
|
|
1207
1525
|
}
|
|
@@ -1235,6 +1553,8 @@ var ChartController = (_class = class {
|
|
|
1235
1553
|
}
|
|
1236
1554
|
/** Adds `delta` to a value (a gap counts as 0). */
|
|
1237
1555
|
nudgeValue(seriesId, index, delta) {
|
|
1556
|
+
const grouped = this.treeLocked();
|
|
1557
|
+
if (grouped) return grouped;
|
|
1238
1558
|
const series = this.getSeries(seriesId);
|
|
1239
1559
|
if (!series) return this.unknownSeries(seriesId);
|
|
1240
1560
|
const current = _nullishCoalesce(series.values[index], () => ( 0));
|
|
@@ -1276,14 +1596,14 @@ var ChartController = (_class = class {
|
|
|
1276
1596
|
// -------------------------------------------------------------------------
|
|
1277
1597
|
/** The spec, for saving (a copy). */
|
|
1278
1598
|
toJSON() {
|
|
1279
|
-
return
|
|
1599
|
+
return _chunkR3P2M7HUcjs.cloneChartSpec.call(void 0, this.spec);
|
|
1280
1600
|
}
|
|
1281
1601
|
/**
|
|
1282
1602
|
* Replaces the chart without an undo step (e.g. when opening a document). Problems are
|
|
1283
1603
|
* fixed with defaults and reported in `state.issues` (and returned).
|
|
1284
1604
|
*/
|
|
1285
1605
|
load(input, options = {}) {
|
|
1286
|
-
const { spec, issues } =
|
|
1606
|
+
const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
|
|
1287
1607
|
this.spec = spec;
|
|
1288
1608
|
this.issues = issues;
|
|
1289
1609
|
this.selection = this.validSelection(this.selection, spec);
|
|
@@ -1303,7 +1623,7 @@ var ChartController = (_class = class {
|
|
|
1303
1623
|
* nothing changes and every problem is returned (and shown in `state.issues`).
|
|
1304
1624
|
*/
|
|
1305
1625
|
replace(input, options = {}) {
|
|
1306
|
-
const { spec, issues } =
|
|
1626
|
+
const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
|
|
1307
1627
|
if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
|
|
1308
1628
|
this.commit(_nullishCoalesce(options.label, () => ( "Replace chart")), spec, this.validSelection(this.selection, spec));
|
|
1309
1629
|
return { ok: true };
|
|
@@ -1318,7 +1638,7 @@ var ChartController = (_class = class {
|
|
|
1318
1638
|
}
|
|
1319
1639
|
/** Stops listening to the history (reconnected by the next `subscribe`). */
|
|
1320
1640
|
destroy() {
|
|
1321
|
-
_optionalChain([this, 'access',
|
|
1641
|
+
_optionalChain([this, 'access', _71 => _71.unsubscribeHistory, 'optionalCall', _72 => _72()]);
|
|
1322
1642
|
this.unsubscribeHistory = void 0;
|
|
1323
1643
|
this.listeners.clear();
|
|
1324
1644
|
}
|
|
@@ -1343,6 +1663,18 @@ function updateLabel(patch) {
|
|
|
1343
1663
|
overlap: "Change bar overlap",
|
|
1344
1664
|
bins: "Change histogram bins",
|
|
1345
1665
|
showTotal: "Toggle waterfall total",
|
|
1666
|
+
note: "Edit note",
|
|
1667
|
+
highlight: "Change highlight",
|
|
1668
|
+
referenceLines: "Change reference lines",
|
|
1669
|
+
referenceBands: "Change reference bands",
|
|
1670
|
+
varyColors: "Toggle colour by category",
|
|
1671
|
+
likertNeutral: "Change neutral answer",
|
|
1672
|
+
likertSort: "Sort questions",
|
|
1673
|
+
parliamentArc: "Change hemicycle sweep",
|
|
1674
|
+
parliamentMajority: "Change majority",
|
|
1675
|
+
parliamentLabel: "Edit seat caption",
|
|
1676
|
+
sunburstLabel: "Edit centre caption",
|
|
1677
|
+
tree: "Replace grouped data",
|
|
1346
1678
|
radarTicks: "Change radar rings",
|
|
1347
1679
|
radarGraticule: "Change radar grid",
|
|
1348
1680
|
legend: "Change legend",
|
|
@@ -1365,7 +1697,7 @@ function layoutSparkline(values, options) {
|
|
|
1365
1697
|
const h = Number.isFinite(options.height) ? Math.max(1, options.height) : 1;
|
|
1366
1698
|
const color = _nullishCoalesce(options.color, () => ( "#4269d0"));
|
|
1367
1699
|
const negative = _nullishCoalesce(options.negativeColor, () => ( "#e5484d"));
|
|
1368
|
-
const theme = { ...
|
|
1700
|
+
const theme = { ..._chunkR3P2M7HUcjs.DEFAULT_CHART_THEME, background: "transparent" };
|
|
1369
1701
|
const marks = [];
|
|
1370
1702
|
const scene = { width: w, height: h, plot: { x: 0, y: 0, width: w, height: h }, marks, percent: false, theme, warnings: [] };
|
|
1371
1703
|
const vals = values.slice(0, MAX_POINTS).map((v) => v !== null && Number.isFinite(v) ? Math.max(-1e300, Math.min(1e300, v)) : null);
|
|
@@ -1398,7 +1730,7 @@ function layoutSparkline(values, options) {
|
|
|
1398
1730
|
const flush = () => {
|
|
1399
1731
|
if (run.length >= 2) {
|
|
1400
1732
|
const pts = run.length > 4e3 ? run.filter((_, i) => i % (Math.floor(run.length / 2e3) + 1) === 0) : run;
|
|
1401
|
-
d += pts.map(([x, y], i) => `${i ? "L" : "M"}${
|
|
1733
|
+
d += pts.map(([x, y], i) => `${i ? "L" : "M"}${_chunkSBQVEBSUcjs.r2.call(void 0, x)},${_chunkSBQVEBSUcjs.r2.call(void 0, y)}`).join("");
|
|
1402
1734
|
}
|
|
1403
1735
|
run = [];
|
|
1404
1736
|
};
|