@pixerate/editor 0.162.1 → 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/canvas/index.cjs +6 -6
- package/dist/canvas/index.js +2 -2
- 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-HLOKB7WW.js → chunk-3NEZJCBY.js} +366 -6
- 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-4NGVHHJB.cjs → chunk-NZD2MZJC.cjs} +80 -18
- package/dist/{chunk-CX6JLDFC.js → chunk-OXERWBKE.js} +3 -3
- package/dist/{chunk-7CKPUUN4.js → chunk-POR54B55.js} +61 -10
- package/dist/{chunk-LL3H5XUH.cjs → chunk-R3P2M7HU.cjs} +367 -7
- package/dist/{chunk-HDGBM7EA.cjs → chunk-SBQVEBSU.cjs} +580 -53
- package/dist/{chunk-XDCFJEU7.js → chunk-SZA42R4N.js} +346 -14
- package/dist/{chunk-GLMP22FT.js → chunk-TALQONZ5.js} +3 -3
- package/dist/{chunk-NA4UVVJ4.cjs → chunk-YGG7WDWT.cjs} +76 -25
- package/dist/{chunk-EY22AY6R.cjs → chunk-YSAGBIRW.cjs} +16 -16
- package/dist/{chunk-DTSTNRPH.js → chunk-Z4P2RBMJ.js} +536 -9
- 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/index.cjs +13 -13
- package/dist/index.js +7 -7
- package/dist/paint-editor/index.cjs +0 -20
- package/dist/paint-editor/index.js +0 -20
- package/package.json +1 -1
- package/skills/pixerate-canvas/SKILL.md +16 -0
|
@@ -224,7 +224,7 @@ function parseChartAmountList(text2) {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// src/chart/spec.ts
|
|
227
|
-
var CHART_TYPES = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap"];
|
|
227
|
+
var CHART_TYPES = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap", "sunburst", "slope", "likert", "parliament"];
|
|
228
228
|
var CHART_MARKERS = ["circle", "square", "diamond", "triangle", "cross", "none"];
|
|
229
229
|
var CHART_TRENDLINE_TYPES = ["linear", "exponential", "logarithmic", "power", "polynomial", "moving-average"];
|
|
230
230
|
var CHART_LABEL_POSITIONS = ["auto", "inside", "outside", "center"];
|
|
@@ -234,6 +234,9 @@ var CHART_SERIES_TYPES = ["bar", "line", "area", "scatter"];
|
|
|
234
234
|
var CHART_STACKINGS = ["none", "stacked", "percent"];
|
|
235
235
|
var CHART_CURVES = ["linear", "smooth", "step"];
|
|
236
236
|
var CHART_RADAR_GRATICULES = ["polygon", "circle"];
|
|
237
|
+
var CHART_LIKERT_NEUTRALS = ["split", "separate"];
|
|
238
|
+
var CHART_LIKERT_SORTS = ["none", "positive", "negative"];
|
|
239
|
+
var CHART_REFERENCE_AXES = ["y", "y2", "x"];
|
|
237
240
|
var CHART_ORIENTATIONS = ["vertical", "horizontal"];
|
|
238
241
|
var CHART_LEGEND_POSITIONS = ["top", "bottom", "left", "right"];
|
|
239
242
|
var CHART_NUMBER_STYLES = ["number", "percent", "currency", "compact"];
|
|
@@ -250,7 +253,11 @@ var CHART_TYPE_LABELS = {
|
|
|
250
253
|
histogram: "Histogram",
|
|
251
254
|
box: "Box plot",
|
|
252
255
|
funnel: "Funnel",
|
|
253
|
-
treemap: "Treemap"
|
|
256
|
+
treemap: "Treemap",
|
|
257
|
+
slope: "Slope",
|
|
258
|
+
likert: "Likert",
|
|
259
|
+
parliament: "Parliament",
|
|
260
|
+
sunburst: "Sunburst"
|
|
254
261
|
};
|
|
255
262
|
var DEFAULT_CHART_PALETTE = ["#4269d0", "#efb118", "#ff725c", "#6cc5b0", "#3ca951", "#ff8ab7", "#a463f2", "#97bbf5", "#9c6b4e", "#9498a0"];
|
|
256
263
|
var DEFAULT_CHART_THEME = {
|
|
@@ -297,6 +304,10 @@ function chartFamily(spec) {
|
|
|
297
304
|
case "box":
|
|
298
305
|
case "funnel":
|
|
299
306
|
case "treemap":
|
|
307
|
+
case "slope":
|
|
308
|
+
case "likert":
|
|
309
|
+
case "parliament":
|
|
310
|
+
case "sunburst":
|
|
300
311
|
return spec.type;
|
|
301
312
|
case "bubble":
|
|
302
313
|
return "xy";
|
|
@@ -305,7 +316,10 @@ function chartFamily(spec) {
|
|
|
305
316
|
}
|
|
306
317
|
}
|
|
307
318
|
function chartColorsByCategory(type) {
|
|
308
|
-
return type === "pie" || type === "donut" || type === "funnel" || type === "treemap";
|
|
319
|
+
return type === "pie" || type === "donut" || type === "funnel" || type === "treemap" || type === "slope" || type === "parliament" || type === "sunburst";
|
|
320
|
+
}
|
|
321
|
+
function chartSpecColorsByCategory(spec) {
|
|
322
|
+
return chartColorsByCategory(spec.type) || chartVariesColors(spec);
|
|
309
323
|
}
|
|
310
324
|
function defaultChartAxis(value) {
|
|
311
325
|
return { show: true, title: "", min: null, max: null, step: null, gridlines: value, format: {} };
|
|
@@ -316,17 +330,37 @@ function createChartSpec(partial = {}) {
|
|
|
316
330
|
function chartSeriesColor(spec, seriesIndex) {
|
|
317
331
|
const series = spec.series[seriesIndex];
|
|
318
332
|
if (_optionalChain([series, 'optionalAccess', _10 => _10.color])) return series.color;
|
|
333
|
+
if (spec.type === "likert") return chartLikertColor(spec.series.length, seriesIndex);
|
|
319
334
|
return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, seriesIndex);
|
|
320
335
|
}
|
|
336
|
+
var LIKERT_NEGATIVE = [["#e66101"], ["#e66101", "#fdb863"], ["#b35806", "#f1a340", "#fee0b6"], ["#b35806", "#e08214", "#fdb863", "#fee0b6"]];
|
|
337
|
+
var LIKERT_POSITIVE = [["#5e3c99"], ["#b2abd2", "#5e3c99"], ["#d8daeb", "#998ec3", "#542788"], ["#d8daeb", "#b2abd2", "#8073ac", "#542788"]];
|
|
338
|
+
var LIKERT_NEUTRAL = "#d4d4d8";
|
|
339
|
+
function chartLikertColor(count, index) {
|
|
340
|
+
const side = Math.floor(count / 2);
|
|
341
|
+
if (count % 2 === 1 && index === side) return LIKERT_NEUTRAL;
|
|
342
|
+
if (!side) return LIKERT_POSITIVE[0][0];
|
|
343
|
+
const ramp = (sets) => sets[Math.min(side, sets.length) - 1];
|
|
344
|
+
const pick2 = (list, k) => list[Math.min(list.length - 1, Math.floor(k * list.length / side))];
|
|
345
|
+
if (index < side) return pick2(ramp(LIKERT_NEGATIVE), index);
|
|
346
|
+
return pick2(ramp(LIKERT_POSITIVE), index - (count - side));
|
|
347
|
+
}
|
|
321
348
|
function chartSliceColor(spec, index) {
|
|
322
349
|
return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, index);
|
|
323
350
|
}
|
|
351
|
+
function chartVariesColors(spec) {
|
|
352
|
+
return !!spec.varyColors && isCartesianChart(spec.type) && spec.series.filter((s) => !s.hidden).length === 1;
|
|
353
|
+
}
|
|
324
354
|
function chartPointColor(spec, seriesIndex, index) {
|
|
325
|
-
|
|
355
|
+
const own = _optionalChain([spec, 'access', _11 => _11.series, 'access', _12 => _12[seriesIndex], 'optionalAccess', _13 => _13.pointColors, 'optionalAccess', _14 => _14[index]]);
|
|
356
|
+
if (own) return own;
|
|
357
|
+
if (spec.type && chartVariesColors(spec)) return chartSliceColor(spec, index);
|
|
358
|
+
return chartSeriesColor(spec, seriesIndex);
|
|
326
359
|
}
|
|
327
360
|
function chartSeriesType(spec, series) {
|
|
328
361
|
if (series.type) return series.type;
|
|
329
362
|
if (spec.type === "bubble") return "scatter";
|
|
363
|
+
if (spec.type === "slope") return "line";
|
|
330
364
|
return isCartesianChart(spec.type) ? spec.type : "bar";
|
|
331
365
|
}
|
|
332
366
|
function uniqueChartSeriesId(series, base = "series") {
|
|
@@ -524,6 +558,16 @@ function normalizeSeries(value, length, used, index, issues) {
|
|
|
524
558
|
if (colors.some((c) => c !== null)) series.pointColors = colors;
|
|
525
559
|
}
|
|
526
560
|
}
|
|
561
|
+
if (value.callouts !== void 0 && value.callouts !== null) {
|
|
562
|
+
if (!Array.isArray(value.callouts)) issues.push({ path: `${path}.callouts`, message: `${path}.callouts must be an array of labels or nulls, one per category.` });
|
|
563
|
+
else {
|
|
564
|
+
const labels = Array.from({ length }, (_, i) => {
|
|
565
|
+
const c = value.callouts[i];
|
|
566
|
+
return typeof c === "string" && c.trim() ? c : typeof c === "number" ? String(c) : null;
|
|
567
|
+
});
|
|
568
|
+
if (labels.some((c) => c !== null)) series.callouts = labels;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
527
571
|
if (value.marker !== void 0 && value.marker !== null) series.marker = pick(value.marker, CHART_MARKERS, "circle", `${path}.marker`, issues);
|
|
528
572
|
if (value.curve !== void 0 && value.curve !== null) series.curve = pick(value.curve, CHART_CURVES, "linear", `${path}.curve`, issues);
|
|
529
573
|
if (value.dataLabels !== void 0 && value.dataLabels !== null) series.dataLabels = flag(value.dataLabels, false, `${path}.dataLabels`, issues);
|
|
@@ -546,6 +590,49 @@ function normalizeSeries(value, length, used, index, issues) {
|
|
|
546
590
|
return series;
|
|
547
591
|
}
|
|
548
592
|
var key = (value, name) => value[name] !== void 0 && value[name] !== null;
|
|
593
|
+
function referenceCommon(value, path, issues) {
|
|
594
|
+
const out = {};
|
|
595
|
+
const label = text(value.label, "", `${path}.label`, issues);
|
|
596
|
+
if (label) out.label = label;
|
|
597
|
+
if (key(value, "axis")) {
|
|
598
|
+
const axis = pick(value.axis, CHART_REFERENCE_AXES, "y", `${path}.axis`, issues);
|
|
599
|
+
if (axis !== "y") out.axis = axis;
|
|
600
|
+
}
|
|
601
|
+
if (typeof value.color === "string" && value.color.trim()) out.color = value.color.trim();
|
|
602
|
+
else if (key(value, "color")) issues.push({ path: `${path}.color`, message: `${path}.color must be a CSS colour.` });
|
|
603
|
+
return out;
|
|
604
|
+
}
|
|
605
|
+
var finiteNumber = (value) => {
|
|
606
|
+
const n = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
607
|
+
return typeof n === "number" && Number.isFinite(n) ? n : null;
|
|
608
|
+
};
|
|
609
|
+
function normalizeChartReferenceLine(value, path, issues = []) {
|
|
610
|
+
if (!isRecord(value)) {
|
|
611
|
+
issues.push({ path, message: `${path} must be an object with a value, e.g. {"value": 100, "label": "Target"}.` });
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
const at = finiteNumber(value.value);
|
|
615
|
+
if (at === null) {
|
|
616
|
+
issues.push({ path: `${path}.value`, message: `${path}.value must be a number (where the line crosses the axis).` });
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
for (const k of Object.keys(value)) if (!["value", "label", "axis", "color"].includes(k)) issues.push({ path: `${path}.${k}`, message: `${path} has no "${k}"; it takes value, label, axis and color.` });
|
|
620
|
+
return { value: at, ...referenceCommon(value, path, issues) };
|
|
621
|
+
}
|
|
622
|
+
function normalizeChartReferenceBand(value, path, issues = []) {
|
|
623
|
+
if (!isRecord(value)) {
|
|
624
|
+
issues.push({ path, message: `${path} must be an object with from and to, e.g. {"from": 80, "to": 120, "label": "Target range"}.` });
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
const from = finiteNumber(value.from);
|
|
628
|
+
const to = finiteNumber(value.to);
|
|
629
|
+
if (from === null || to === null) {
|
|
630
|
+
issues.push({ path, message: `${path} needs numbers for from and to (the ends of the band on its axis).` });
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
for (const k of Object.keys(value)) if (!["from", "to", "label", "axis", "color"].includes(k)) issues.push({ path: `${path}.${k}`, message: `${path} has no "${k}"; it takes from, to, label, axis and color.` });
|
|
634
|
+
return { from: Math.min(from, to), to: Math.max(from, to), ...referenceCommon(value, path, issues) };
|
|
635
|
+
}
|
|
549
636
|
function normalizeChartErrorBars(value, length, path, issues = []) {
|
|
550
637
|
if (!isRecord(value)) {
|
|
551
638
|
issues.push({ path, message: `${path} must be an object with a type (${CHART_ERROR_BAR_TYPES.join(", ")}), or null for none.` });
|
|
@@ -631,8 +718,14 @@ function normalizeChartSpec(input) {
|
|
|
631
718
|
const longest = rawSeries.reduce((n, s) => Math.max(n, isRecord(s) && Array.isArray(s.values) ? s.values.length : 0), 0);
|
|
632
719
|
categories = Array.from({ length: longest }, (_, i) => `${i + 1}`);
|
|
633
720
|
}
|
|
721
|
+
const tree = normalizeChartTree(value.tree, issues);
|
|
722
|
+
if (tree.length) categories = tree.map((n) => n.name);
|
|
634
723
|
const used = /* @__PURE__ */ new Set();
|
|
635
724
|
const series = rawSeries.map((s, i) => normalizeSeries(s, categories.length, used, i, issues)).filter((s) => s !== null);
|
|
725
|
+
if (tree.length) {
|
|
726
|
+
if (!series.length) series.push({ id: uniqueChartSeriesId(series), name: "Values", values: [] });
|
|
727
|
+
series[0] = { ...series[0], values: tree.map(chartTreeTotal) };
|
|
728
|
+
}
|
|
636
729
|
let palette = [...DEFAULT_CHART_PALETTE];
|
|
637
730
|
if (Array.isArray(value.palette)) {
|
|
638
731
|
const colors = value.palette.filter((c) => typeof c === "string" && c.trim() !== "");
|
|
@@ -655,6 +748,32 @@ function normalizeChartSpec(input) {
|
|
|
655
748
|
if (Number.isInteger(b) && b >= 1 && b <= 500) bins = b;
|
|
656
749
|
else issues.push({ path: "bins", message: "bins must be a whole number from 1 to 500, or null for automatic." });
|
|
657
750
|
}
|
|
751
|
+
const highlight = [];
|
|
752
|
+
if (Array.isArray(value.highlight)) {
|
|
753
|
+
for (const h of value.highlight) {
|
|
754
|
+
if (typeof h === "string" || typeof h === "number") {
|
|
755
|
+
const name = String(h);
|
|
756
|
+
if (!highlight.includes(name)) highlight.push(name);
|
|
757
|
+
} else issues.push({ path: "highlight", message: "highlight must list category labels or series names." });
|
|
758
|
+
}
|
|
759
|
+
} else if (value.highlight !== void 0 && value.highlight !== null) issues.push({ path: "highlight", message: "highlight must be an array of category labels or series names." });
|
|
760
|
+
const listOf = (name, read) => {
|
|
761
|
+
const raw = value[name];
|
|
762
|
+
if (raw === void 0 || raw === null) return [];
|
|
763
|
+
if (!Array.isArray(raw)) {
|
|
764
|
+
issues.push({ path: name, message: `${name} must be an array.` });
|
|
765
|
+
return [];
|
|
766
|
+
}
|
|
767
|
+
return raw.map((item, i) => read(item, `${name}[${i}]`, issues)).filter((x) => x !== null);
|
|
768
|
+
};
|
|
769
|
+
const referenceLines = listOf("referenceLines", normalizeChartReferenceLine);
|
|
770
|
+
const referenceBands = listOf("referenceBands", normalizeChartReferenceBand);
|
|
771
|
+
let parliamentMajority = null;
|
|
772
|
+
if (value.parliamentMajority !== void 0 && value.parliamentMajority !== null) {
|
|
773
|
+
const m = Number(value.parliamentMajority);
|
|
774
|
+
if (Number.isInteger(m) && m >= 1) parliamentMajority = m;
|
|
775
|
+
else issues.push({ path: "parliamentMajority", message: "parliamentMajority must be a whole number of seats, 1 or more, or null for half plus one." });
|
|
776
|
+
}
|
|
658
777
|
let radarTicks = null;
|
|
659
778
|
if (value.radarTicks !== void 0 && value.radarTicks !== null) {
|
|
660
779
|
const t = Number(value.radarTicks);
|
|
@@ -685,7 +804,19 @@ function normalizeChartSpec(input) {
|
|
|
685
804
|
bins,
|
|
686
805
|
showTotal: flag(value.showTotal, true, "showTotal", issues),
|
|
687
806
|
radarTicks,
|
|
688
|
-
radarGraticule: pick(value.radarGraticule, CHART_RADAR_GRATICULES, "polygon", "radarGraticule", issues)
|
|
807
|
+
radarGraticule: pick(value.radarGraticule, CHART_RADAR_GRATICULES, "polygon", "radarGraticule", issues),
|
|
808
|
+
note: text(value.note, "", "note", issues),
|
|
809
|
+
highlight,
|
|
810
|
+
referenceLines,
|
|
811
|
+
referenceBands,
|
|
812
|
+
varyColors: flag(value.varyColors, false, "varyColors", issues),
|
|
813
|
+
likertNeutral: pick(value.likertNeutral, CHART_LIKERT_NEUTRALS, "split", "likertNeutral", issues),
|
|
814
|
+
likertSort: pick(value.likertSort, CHART_LIKERT_SORTS, "none", "likertSort", issues),
|
|
815
|
+
parliamentArc: fraction("parliamentArc", 180, 90, 360),
|
|
816
|
+
parliamentMajority,
|
|
817
|
+
parliamentLabel: text(value.parliamentLabel, "", "parliamentLabel", issues),
|
|
818
|
+
tree,
|
|
819
|
+
sunburstLabel: text(value.sunburstLabel, "", "sunburstLabel", issues)
|
|
689
820
|
};
|
|
690
821
|
if (spec.stacking === "percent")
|
|
691
822
|
for (const name of ["yAxis", "yAxis2"]) {
|
|
@@ -705,7 +836,11 @@ function cloneChartSpec(spec) {
|
|
|
705
836
|
yAxis: { ...spec.yAxis, format: { ...spec.yAxis.format } },
|
|
706
837
|
yAxis2: { ...spec.yAxis2, format: { ...spec.yAxis2.format } },
|
|
707
838
|
legend: { ...spec.legend },
|
|
708
|
-
palette: [...spec.palette]
|
|
839
|
+
palette: [...spec.palette],
|
|
840
|
+
highlight: [...spec.highlight],
|
|
841
|
+
referenceLines: spec.referenceLines.map((l) => ({ ...l })),
|
|
842
|
+
referenceBands: spec.referenceBands.map((b) => ({ ...b })),
|
|
843
|
+
tree: cloneChartTree(spec.tree)
|
|
709
844
|
};
|
|
710
845
|
}
|
|
711
846
|
function cloneChartSeries(series) {
|
|
@@ -713,6 +848,7 @@ function cloneChartSeries(series) {
|
|
|
713
848
|
if (series.x) copy.x = [...series.x];
|
|
714
849
|
if (series.sizes) copy.sizes = [...series.sizes];
|
|
715
850
|
if (series.pointColors) copy.pointColors = [...series.pointColors];
|
|
851
|
+
if (series.callouts) copy.callouts = [...series.callouts];
|
|
716
852
|
if (series.format) copy.format = { ...series.format };
|
|
717
853
|
if (series.trendlines) copy.trendlines = series.trendlines.map((t) => ({ ...t }));
|
|
718
854
|
for (const name of ["errorBars", "xErrorBars"]) {
|
|
@@ -773,6 +909,230 @@ function chartColorInputValue(color) {
|
|
|
773
909
|
return "#000000";
|
|
774
910
|
}
|
|
775
911
|
|
|
912
|
+
// src/chart/tree.ts
|
|
913
|
+
var MAX_CHART_TREE_DEPTH = 6;
|
|
914
|
+
var MAX_CHART_TREE_NODES = 5e3;
|
|
915
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
916
|
+
function normalizeChartTree(value, issues = [], path = "tree") {
|
|
917
|
+
if (value === void 0 || value === null) return [];
|
|
918
|
+
if (!Array.isArray(value)) {
|
|
919
|
+
issues.push({ path, message: `${path} must be an array of nodes such as {"name": "Europe", "children": [{"name": "France", "value": 40}]}.` });
|
|
920
|
+
return [];
|
|
921
|
+
}
|
|
922
|
+
let count = 0;
|
|
923
|
+
const read = (list, at, depth) => {
|
|
924
|
+
const out = [];
|
|
925
|
+
const names = /* @__PURE__ */ new Set();
|
|
926
|
+
list.forEach((raw, i) => {
|
|
927
|
+
const where = `${at}[${i}]`;
|
|
928
|
+
if (!isRecord2(raw)) {
|
|
929
|
+
issues.push({ path: where, message: `${where} must be an object with a name and a value or children.` });
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
const name = typeof raw.name === "number" ? String(raw.name) : typeof raw.name === "string" ? raw.name.trim() : "";
|
|
933
|
+
if (!name) {
|
|
934
|
+
issues.push({ path: `${where}.name`, message: `${where} needs a name.` });
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (names.has(name)) {
|
|
938
|
+
issues.push({ path: `${where}.name`, message: `"${name}" appears twice under the same group in ${at}; sibling names must be unique, so the second was left out.` });
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (++count > MAX_CHART_TREE_NODES) {
|
|
942
|
+
if (count === MAX_CHART_TREE_NODES + 1) issues.push({ path, message: `The tree has more than ${MAX_CHART_TREE_NODES} nodes; the rest were left out.` });
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
names.add(name);
|
|
946
|
+
for (const k of Object.keys(raw)) if (!["name", "value", "children", "color"].includes(k)) issues.push({ path: `${where}.${k}`, message: `${where} has no "${k}"; a node takes name, value, children and color.` });
|
|
947
|
+
const node = { name };
|
|
948
|
+
if (typeof raw.color === "string" && raw.color.trim()) node.color = raw.color.trim();
|
|
949
|
+
if (Array.isArray(raw.children) && raw.children.length) {
|
|
950
|
+
if (depth >= MAX_CHART_TREE_DEPTH) {
|
|
951
|
+
issues.push({ path: `${where}.children`, message: `${where} is more than ${MAX_CHART_TREE_DEPTH} levels deep; its children were left out.` });
|
|
952
|
+
node.value = 0;
|
|
953
|
+
} else {
|
|
954
|
+
if (raw.value !== void 0 && raw.value !== null) issues.push({ path: `${where}.value`, message: `"${name}" is a group: its value is the sum of its children, so the value given was ignored.` });
|
|
955
|
+
const children = read(raw.children, `${where}.children`, depth + 1);
|
|
956
|
+
if (children.length) node.children = children;
|
|
957
|
+
else node.value = 0;
|
|
958
|
+
}
|
|
959
|
+
} else {
|
|
960
|
+
if (raw.children !== void 0 && raw.children !== null && !Array.isArray(raw.children)) issues.push({ path: `${where}.children`, message: `${where}.children must be an array of nodes.` });
|
|
961
|
+
const v = parseChartValue(raw.value);
|
|
962
|
+
if (raw.value === void 0 || raw.value === null) node.value = 0;
|
|
963
|
+
else if (typeof v === "number" && v >= 0) node.value = v;
|
|
964
|
+
else {
|
|
965
|
+
issues.push({ path: `${where}.value`, message: `"${name}" needs a value of 0 or more; got ${JSON.stringify(raw.value)}.` });
|
|
966
|
+
node.value = 0;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
out.push(node);
|
|
970
|
+
});
|
|
971
|
+
return out;
|
|
972
|
+
};
|
|
973
|
+
return read(value, path, 1);
|
|
974
|
+
}
|
|
975
|
+
function chartTreeTotal(node) {
|
|
976
|
+
return node.children ? node.children.reduce((t, c) => t + chartTreeTotal(c), 0) : _nullishCoalesce(node.value, () => ( 0));
|
|
977
|
+
}
|
|
978
|
+
function chartTreeDepth(tree) {
|
|
979
|
+
return tree.reduce((d, n) => Math.max(d, 1 + (n.children ? chartTreeDepth(n.children) : 0)), 0);
|
|
980
|
+
}
|
|
981
|
+
function findChartTreeNode(tree, path) {
|
|
982
|
+
let list = tree;
|
|
983
|
+
let node;
|
|
984
|
+
for (const name of path) {
|
|
985
|
+
node = _optionalChain([list, 'optionalAccess', _18 => _18.find, 'call', _19 => _19((n) => n.name === name)]);
|
|
986
|
+
if (!node) return void 0;
|
|
987
|
+
list = node.children;
|
|
988
|
+
}
|
|
989
|
+
return node;
|
|
990
|
+
}
|
|
991
|
+
function chartTreeToRows(tree) {
|
|
992
|
+
const out = [];
|
|
993
|
+
const walk = (list, prefix) => {
|
|
994
|
+
for (const n of list) {
|
|
995
|
+
if (n.children) walk(n.children, [...prefix, n.name]);
|
|
996
|
+
else out.push({ path: [...prefix, n.name], value: _nullishCoalesce(n.value, () => ( 0)) });
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
walk(tree, []);
|
|
1000
|
+
return out;
|
|
1001
|
+
}
|
|
1002
|
+
function chartTreeFromRows(rows, issues = []) {
|
|
1003
|
+
const tree = [];
|
|
1004
|
+
rows.forEach((row, r) => {
|
|
1005
|
+
const path = [];
|
|
1006
|
+
for (const cell of row.path) {
|
|
1007
|
+
const name = cell === null || cell === void 0 ? "" : String(cell).trim();
|
|
1008
|
+
if (!name) break;
|
|
1009
|
+
path.push(name);
|
|
1010
|
+
}
|
|
1011
|
+
if (!path.length) return;
|
|
1012
|
+
if (path.length > MAX_CHART_TREE_DEPTH) {
|
|
1013
|
+
issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} is ${path.length} levels deep; the tree keeps at most ${MAX_CHART_TREE_DEPTH}, so the row was left out.` });
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
const v = parseChartValue(row.value);
|
|
1017
|
+
if (row.value !== null && row.value !== void 0 && String(row.value).trim() !== "" && !(typeof v === "number" && v >= 0)) {
|
|
1018
|
+
issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} (${path.join(" / ")}) needs a value of 0 or more; got ${JSON.stringify(row.value)}. It was counted as 0.` });
|
|
1019
|
+
}
|
|
1020
|
+
const value = typeof v === "number" && v >= 0 ? v : 0;
|
|
1021
|
+
let list = tree;
|
|
1022
|
+
for (let k = 0; k < path.length; k++) {
|
|
1023
|
+
const last = k === path.length - 1;
|
|
1024
|
+
let node = list.find((n) => n.name === path[k]);
|
|
1025
|
+
if (!node) {
|
|
1026
|
+
node = last ? { name: path[k], value } : { name: path[k], children: [] };
|
|
1027
|
+
list.push(node);
|
|
1028
|
+
if (last) return;
|
|
1029
|
+
} else if (last) {
|
|
1030
|
+
issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} (${path.join(" / ")}) ${node.children ? "names a group that already has items" : "repeats an earlier row"}; it was left out.` });
|
|
1031
|
+
return;
|
|
1032
|
+
} else if (!node.children) {
|
|
1033
|
+
issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} puts items under "${path.slice(0, k + 1).join(" / ")}", which an earlier row made an item with its own value; it was left out.` });
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
list = node.children;
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
return tree;
|
|
1040
|
+
}
|
|
1041
|
+
function chartTreeFromTable(rows, options = {}, issues = []) {
|
|
1042
|
+
const grid = rows.filter((r) => r.some((c) => c !== null && c !== void 0 && String(c).trim() !== ""));
|
|
1043
|
+
if (!grid.length) return [];
|
|
1044
|
+
const width = Math.max(...grid.map((r) => r.length));
|
|
1045
|
+
if (width < 2) {
|
|
1046
|
+
issues.push({ path: "rows", message: "A tree table needs at least two columns: names, then values." });
|
|
1047
|
+
return [];
|
|
1048
|
+
}
|
|
1049
|
+
const header = _nullishCoalesce(options.header, () => ( "auto"));
|
|
1050
|
+
const skip = header === true || header === "auto" && typeof parseChartValue(grid[0][width - 1]) !== "number";
|
|
1051
|
+
const body = skip ? grid.slice(1) : grid;
|
|
1052
|
+
let above = [];
|
|
1053
|
+
return chartTreeFromRows(
|
|
1054
|
+
body.map((r) => {
|
|
1055
|
+
const cells = Array.from({ length: width - 1 }, (_, k) => r[k] === null || r[k] === void 0 ? "" : String(r[k]).trim());
|
|
1056
|
+
const first = cells.findIndex((c) => c !== "");
|
|
1057
|
+
if (first < 0) return { path: [], value: r[width - 1] };
|
|
1058
|
+
const own = [];
|
|
1059
|
+
for (const c of cells.slice(first)) {
|
|
1060
|
+
if (!c) break;
|
|
1061
|
+
own.push(c);
|
|
1062
|
+
}
|
|
1063
|
+
const path = [...above.slice(0, first), ...own];
|
|
1064
|
+
above = path;
|
|
1065
|
+
return { path, value: r[width - 1] };
|
|
1066
|
+
}),
|
|
1067
|
+
issues
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
function chartTreeFromSeries(categories, values) {
|
|
1071
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1072
|
+
const out = [];
|
|
1073
|
+
categories.forEach((c, i) => {
|
|
1074
|
+
const name = c.trim() || `${i + 1}`;
|
|
1075
|
+
if (seen.has(name)) return;
|
|
1076
|
+
seen.add(name);
|
|
1077
|
+
const v = values[i];
|
|
1078
|
+
out.push({ name, value: v !== null && v !== void 0 && Number.isFinite(v) && v > 0 ? v : 0 });
|
|
1079
|
+
});
|
|
1080
|
+
return out;
|
|
1081
|
+
}
|
|
1082
|
+
function cloneChartTree(tree) {
|
|
1083
|
+
return tree.map((n) => ({ ...n, ...n.children ? { children: cloneChartTree(n.children) } : {} }));
|
|
1084
|
+
}
|
|
1085
|
+
function chartTreeColumnLabels(depth) {
|
|
1086
|
+
if (depth <= 1) return ["Item"];
|
|
1087
|
+
return Array.from({ length: depth }, (_, k) => k === 0 ? "Group" : k === depth - 1 ? "Item" : `Level ${k + 1}`);
|
|
1088
|
+
}
|
|
1089
|
+
function setChartTreeRowName(rows, row, level, name) {
|
|
1090
|
+
return rows.map((r, i) => {
|
|
1091
|
+
if (i !== row) return { path: [...r.path], value: r.value };
|
|
1092
|
+
const path = [...r.path];
|
|
1093
|
+
while (path.length <= level) path.push("");
|
|
1094
|
+
path[level] = name.trim();
|
|
1095
|
+
return { path, value: r.value };
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
function setChartTreeRowValue(rows, row, value) {
|
|
1099
|
+
return rows.map((r, i) => ({ path: [...r.path], value: i === row ? value : r.value }));
|
|
1100
|
+
}
|
|
1101
|
+
function addChartTreeRow(rows) {
|
|
1102
|
+
const parent = rows.length ? rows[rows.length - 1].path.slice(0, -1) : [];
|
|
1103
|
+
const taken = new Set(rows.filter((r) => r.path.length === parent.length + 1 && parent.every((p, k) => r.path[k] === p)).map((r) => r.path[parent.length]));
|
|
1104
|
+
let n = rows.length + 1;
|
|
1105
|
+
while (taken.has(`Item ${n}`)) n++;
|
|
1106
|
+
return [...rows.map((r) => ({ path: [...r.path], value: r.value })), { path: [...parent, `Item ${n}`], value: 0 }];
|
|
1107
|
+
}
|
|
1108
|
+
function removeChartTreeRow(rows, row) {
|
|
1109
|
+
return rows.filter((_, i) => i !== row).map((r) => ({ path: [...r.path], value: r.value }));
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
776
1136
|
|
|
777
1137
|
|
|
778
1138
|
|
|
@@ -834,4 +1194,4 @@ function chartColorInputValue(color) {
|
|
|
834
1194
|
|
|
835
1195
|
|
|
836
1196
|
|
|
837
|
-
exports.parseChartColor = parseChartColor; exports.chartRgbToHex = chartRgbToHex; exports.shadeChartColor = shadeChartColor; exports.CHART_PALETTE_SHADES = CHART_PALETTE_SHADES; exports.cyclePaletteColor = cyclePaletteColor; exports.chartLuminance = chartLuminance; exports.chartContrastRatio = chartContrastRatio; exports.chartTextOn = chartTextOn; exports.chartRgbToOklab = chartRgbToOklab; exports.chartColorDistance = chartColorDistance; exports.simulateChartVision = simulateChartVision; exports.checkChartColors = checkChartColors; exports.CHART_ERROR_BAR_TYPES = CHART_ERROR_BAR_TYPES; exports.CHART_ERROR_BAR_DIRECTIONS = CHART_ERROR_BAR_DIRECTIONS; exports.CHART_ERROR_BAR_LABELS = CHART_ERROR_BAR_LABELS; exports.defaultChartErrorBarValue = defaultChartErrorBarValue; exports.chartErrorAmounts = chartErrorAmounts; exports.describeChartErrorBars = describeChartErrorBars; exports.chartErrorBarsOfType = chartErrorBarsOfType; exports.formatChartAmountList = formatChartAmountList; exports.parseChartAmountList = parseChartAmountList; exports.CHART_TYPES = CHART_TYPES; exports.CHART_MARKERS = CHART_MARKERS; exports.CHART_TRENDLINE_TYPES = CHART_TRENDLINE_TYPES; exports.CHART_LABEL_POSITIONS = CHART_LABEL_POSITIONS; exports.CHART_AXIS_KINDS = CHART_AXIS_KINDS; exports.CHART_AXIS_SCALES = CHART_AXIS_SCALES; exports.CHART_SERIES_TYPES = CHART_SERIES_TYPES; exports.CHART_STACKINGS = CHART_STACKINGS; exports.CHART_CURVES = CHART_CURVES; exports.CHART_RADAR_GRATICULES = CHART_RADAR_GRATICULES; exports.CHART_ORIENTATIONS = CHART_ORIENTATIONS; exports.CHART_LEGEND_POSITIONS = CHART_LEGEND_POSITIONS; exports.CHART_NUMBER_STYLES = CHART_NUMBER_STYLES; exports.CHART_TYPE_LABELS = CHART_TYPE_LABELS; exports.DEFAULT_CHART_PALETTE = DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = DEFAULT_CHART_THEME; exports.CSS_VARIABLE_CHART_THEME = CSS_VARIABLE_CHART_THEME; exports.isCartesianChart = isCartesianChart; exports.isXyChart = isXyChart; exports.chartFamily = chartFamily; exports.chartColorsByCategory = chartColorsByCategory; exports.defaultChartAxis = defaultChartAxis; exports.createChartSpec = createChartSpec; exports.chartSeriesColor = chartSeriesColor; exports.chartSliceColor = chartSliceColor; exports.chartPointColor = chartPointColor; exports.chartSeriesType = chartSeriesType; exports.uniqueChartSeriesId = uniqueChartSeriesId; exports.parseChartValue = parseChartValue; exports.normalizeChartAxis = normalizeChartAxis; exports.normalizeChartValues = normalizeChartValues; exports.normalizeChartErrorBars = normalizeChartErrorBars; exports.normalizeChartTrendline = normalizeChartTrendline; exports.normalizeChartSpec = normalizeChartSpec; exports.cloneChartSpec = cloneChartSpec; exports.cloneChartSeries = cloneChartSeries; exports.chartDataFromTable = chartDataFromTable; exports.chartDataToTable = chartDataToTable; exports.chartColorInputValue = chartColorInputValue;
|
|
1197
|
+
exports.parseChartColor = parseChartColor; exports.chartRgbToHex = chartRgbToHex; exports.shadeChartColor = shadeChartColor; exports.CHART_PALETTE_SHADES = CHART_PALETTE_SHADES; exports.cyclePaletteColor = cyclePaletteColor; exports.chartLuminance = chartLuminance; exports.chartContrastRatio = chartContrastRatio; exports.chartTextOn = chartTextOn; exports.chartRgbToOklab = chartRgbToOklab; exports.chartColorDistance = chartColorDistance; exports.simulateChartVision = simulateChartVision; exports.checkChartColors = checkChartColors; exports.CHART_ERROR_BAR_TYPES = CHART_ERROR_BAR_TYPES; exports.CHART_ERROR_BAR_DIRECTIONS = CHART_ERROR_BAR_DIRECTIONS; exports.CHART_ERROR_BAR_LABELS = CHART_ERROR_BAR_LABELS; exports.defaultChartErrorBarValue = defaultChartErrorBarValue; exports.chartErrorAmounts = chartErrorAmounts; exports.describeChartErrorBars = describeChartErrorBars; exports.chartErrorBarsOfType = chartErrorBarsOfType; exports.formatChartAmountList = formatChartAmountList; exports.parseChartAmountList = parseChartAmountList; exports.MAX_CHART_TREE_DEPTH = MAX_CHART_TREE_DEPTH; exports.MAX_CHART_TREE_NODES = MAX_CHART_TREE_NODES; exports.normalizeChartTree = normalizeChartTree; exports.chartTreeTotal = chartTreeTotal; exports.chartTreeDepth = chartTreeDepth; exports.findChartTreeNode = findChartTreeNode; exports.chartTreeToRows = chartTreeToRows; exports.chartTreeFromRows = chartTreeFromRows; exports.chartTreeFromTable = chartTreeFromTable; exports.chartTreeFromSeries = chartTreeFromSeries; exports.cloneChartTree = cloneChartTree; exports.chartTreeColumnLabels = chartTreeColumnLabels; exports.setChartTreeRowName = setChartTreeRowName; exports.setChartTreeRowValue = setChartTreeRowValue; exports.addChartTreeRow = addChartTreeRow; exports.removeChartTreeRow = removeChartTreeRow; exports.CHART_TYPES = CHART_TYPES; exports.CHART_MARKERS = CHART_MARKERS; exports.CHART_TRENDLINE_TYPES = CHART_TRENDLINE_TYPES; exports.CHART_LABEL_POSITIONS = CHART_LABEL_POSITIONS; exports.CHART_AXIS_KINDS = CHART_AXIS_KINDS; exports.CHART_AXIS_SCALES = CHART_AXIS_SCALES; exports.CHART_SERIES_TYPES = CHART_SERIES_TYPES; exports.CHART_STACKINGS = CHART_STACKINGS; exports.CHART_CURVES = CHART_CURVES; exports.CHART_RADAR_GRATICULES = CHART_RADAR_GRATICULES; exports.CHART_LIKERT_NEUTRALS = CHART_LIKERT_NEUTRALS; exports.CHART_LIKERT_SORTS = CHART_LIKERT_SORTS; exports.CHART_REFERENCE_AXES = CHART_REFERENCE_AXES; exports.CHART_ORIENTATIONS = CHART_ORIENTATIONS; exports.CHART_LEGEND_POSITIONS = CHART_LEGEND_POSITIONS; exports.CHART_NUMBER_STYLES = CHART_NUMBER_STYLES; exports.CHART_TYPE_LABELS = CHART_TYPE_LABELS; exports.DEFAULT_CHART_PALETTE = DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = DEFAULT_CHART_THEME; exports.CSS_VARIABLE_CHART_THEME = CSS_VARIABLE_CHART_THEME; exports.isCartesianChart = isCartesianChart; exports.isXyChart = isXyChart; exports.chartFamily = chartFamily; exports.chartColorsByCategory = chartColorsByCategory; exports.chartSpecColorsByCategory = chartSpecColorsByCategory; exports.defaultChartAxis = defaultChartAxis; exports.createChartSpec = createChartSpec; exports.chartSeriesColor = chartSeriesColor; exports.chartLikertColor = chartLikertColor; exports.chartSliceColor = chartSliceColor; exports.chartVariesColors = chartVariesColors; exports.chartPointColor = chartPointColor; exports.chartSeriesType = chartSeriesType; exports.uniqueChartSeriesId = uniqueChartSeriesId; exports.parseChartValue = parseChartValue; exports.normalizeChartAxis = normalizeChartAxis; exports.normalizeChartValues = normalizeChartValues; exports.normalizeChartReferenceLine = normalizeChartReferenceLine; exports.normalizeChartReferenceBand = normalizeChartReferenceBand; exports.normalizeChartErrorBars = normalizeChartErrorBars; exports.normalizeChartTrendline = normalizeChartTrendline; exports.normalizeChartSpec = normalizeChartSpec; exports.cloneChartSpec = cloneChartSpec; exports.cloneChartSeries = cloneChartSeries; exports.chartDataFromTable = chartDataFromTable; exports.chartDataToTable = chartDataToTable; exports.chartColorInputValue = chartColorInputValue;
|