@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
|
@@ -2,11 +2,13 @@ import {
|
|
|
2
2
|
chartFamily,
|
|
3
3
|
chartRgbToHex,
|
|
4
4
|
chartSeriesType,
|
|
5
|
+
chartTreeFromRows,
|
|
6
|
+
chartVariesColors,
|
|
5
7
|
defaultChartAxis,
|
|
6
8
|
isCartesianChart,
|
|
7
9
|
normalizeChartSpec,
|
|
8
10
|
parseChartColor
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-3NEZJCBY.js";
|
|
10
12
|
|
|
11
13
|
// src/chart/ooxml.ts
|
|
12
14
|
var CHART_OOXML_NS = "http://schemas.openxmlformats.org/drawingml/2006/chart";
|
|
@@ -295,7 +297,7 @@ function chartFromOoxml(xml, options = {}) {
|
|
|
295
297
|
input.orientation = orientation;
|
|
296
298
|
input.dataLabels = dataLabels;
|
|
297
299
|
input.points = points || first !== "line";
|
|
298
|
-
if (bool(val(groups[0], "varyColors")) &&
|
|
300
|
+
if (bool(val(groups[0], "varyColors")) && !combo && isCartesianChart(first) && series.length === 1) input.varyColors = true;
|
|
299
301
|
const readAxis = (a, fallback) => {
|
|
300
302
|
const axis = { ...fallback, format: {} };
|
|
301
303
|
if (!a) return axis;
|
|
@@ -340,6 +342,29 @@ function readChartex(root, issues, unsupported) {
|
|
|
340
342
|
const numDim = kids(d, "numDim")[0];
|
|
341
343
|
const lvl = (dim) => kids(dim, "lvl")[0];
|
|
342
344
|
const cats = kids(lvl(strDim), "pt").map((p) => p.textContent ?? "");
|
|
345
|
+
const levels = kids(strDim, "lvl").map((l) => {
|
|
346
|
+
const out = [];
|
|
347
|
+
for (const p of kids(l, "pt")) out[Number(p.getAttribute("idx") ?? out.length)] = (p.textContent ?? "").trim();
|
|
348
|
+
return out;
|
|
349
|
+
});
|
|
350
|
+
let paths;
|
|
351
|
+
if (levels.length > 1) {
|
|
352
|
+
const carried = [];
|
|
353
|
+
paths = levels[0].map((_, i) => {
|
|
354
|
+
const path2 = [];
|
|
355
|
+
for (let k = levels.length - 1; k >= 1; k--) {
|
|
356
|
+
const name = levels[k][i];
|
|
357
|
+
if (name) {
|
|
358
|
+
carried[k] = name;
|
|
359
|
+
carried.length = Math.max(carried.length, k + 1);
|
|
360
|
+
for (let j = 1; j < k; j++) carried[j] = "";
|
|
361
|
+
}
|
|
362
|
+
if (carried[k]) path2.push(carried[k]);
|
|
363
|
+
}
|
|
364
|
+
if (levels[0][i]) path2.push(levels[0][i]);
|
|
365
|
+
return path2;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
343
368
|
const values = [];
|
|
344
369
|
const nl = lvl(numDim);
|
|
345
370
|
for (const p of kids(nl, "pt")) {
|
|
@@ -347,19 +372,18 @@ function readChartex(root, issues, unsupported) {
|
|
|
347
372
|
while (values.length < i) values.push(null);
|
|
348
373
|
values[i] = numberOf((p.textContent ?? "").trim());
|
|
349
374
|
}
|
|
350
|
-
data.set(id, { categories: cats, values, code: nl?.getAttribute("formatCode") ?? void 0 });
|
|
375
|
+
data.set(id, { categories: cats, values, code: nl?.getAttribute("formatCode") ?? void 0, paths });
|
|
351
376
|
}
|
|
352
377
|
const chart = kid(root, "chart");
|
|
353
378
|
const region = path(chart, "plotArea", "plotAreaRegion");
|
|
354
379
|
const seriesEls = kids(region, "series");
|
|
355
|
-
const layouts = { waterfall: "waterfall", funnel: "funnel", treemap: "treemap", sunburst: "
|
|
380
|
+
const layouts = { waterfall: "waterfall", funnel: "funnel", treemap: "treemap", sunburst: "sunburst", boxWhisker: "box", clusteredColumn: "histogram", paretoLine: "histogram" };
|
|
356
381
|
const layout = seriesEls[0]?.getAttribute("layoutId") ?? "";
|
|
357
382
|
const type = layouts[layout];
|
|
358
383
|
if (!type) {
|
|
359
384
|
issues.push({ path: "plotArea", message: `The chart layout "${layout || "unknown"}" is not supported.` });
|
|
360
385
|
return { spec: normalizeChartSpec({}).spec, issues, unsupported: [layout || "unknown chartex layout"], lossless: false };
|
|
361
386
|
}
|
|
362
|
-
if (layout === "sunburst") unsupported.push("sunburst (drawn as a treemap of the innermost level)");
|
|
363
387
|
if (layout === "paretoLine") unsupported.push("pareto line");
|
|
364
388
|
const series = [];
|
|
365
389
|
let categories = [];
|
|
@@ -382,6 +406,12 @@ function readChartex(root, issues, unsupported) {
|
|
|
382
406
|
categories: categories.length >= longest ? categories : Array.from({ length: longest }, (_, i) => categories[i] ?? `${i + 1}`)
|
|
383
407
|
};
|
|
384
408
|
if (type === "waterfall") input.showTotal = false;
|
|
409
|
+
const first = data.get(kid(seriesEls[0], "dataId")?.getAttribute("val") ?? "0");
|
|
410
|
+
if ((type === "treemap" || type === "sunburst") && first?.paths) {
|
|
411
|
+
const treeIssues = [];
|
|
412
|
+
input.tree = chartTreeFromRows(first.paths.map((path2, i) => ({ path: path2, value: first.values[i] ?? 0 })), treeIssues);
|
|
413
|
+
for (const t of treeIssues) issues.push({ path: "chartData", message: t.message });
|
|
414
|
+
}
|
|
385
415
|
const { spec, issues: specIssues } = normalizeChartSpec(input);
|
|
386
416
|
issues.push(...specIssues);
|
|
387
417
|
return { spec, issues, unsupported, lossless: unsupported.length === 0 && specIssues.length === 0 };
|
|
@@ -440,10 +470,30 @@ function chartToOoxml(spec) {
|
|
|
440
470
|
issues.push(`${spec.type} charts are written as bar charts: DrawingML has no ${spec.type} type (Office 2016 stores it as chartex).`);
|
|
441
471
|
type = "bar";
|
|
442
472
|
} else if (family === "treemap") {
|
|
443
|
-
issues.push(
|
|
473
|
+
issues.push(`Treemaps are written as pie charts${spec.tree.length ? " of the top-level group totals" : ""}: DrawingML has no treemap type.`);
|
|
444
474
|
type = "pie";
|
|
475
|
+
} else if (family === "sunburst") {
|
|
476
|
+
issues.push(`Sunburst charts are written as doughnut charts of the ${spec.tree.length ? "top-level group totals" : "values"}: DrawingML has no sunburst type (Office 2016 stores it as chartex).`);
|
|
477
|
+
type = "donut";
|
|
478
|
+
} else if (family === "parliament") {
|
|
479
|
+
issues.push("Parliament charts are written as doughnut charts of the seats: DrawingML has no parliament type.");
|
|
480
|
+
type = "donut";
|
|
481
|
+
} else if (family === "slope") {
|
|
482
|
+
issues.push("Slope charts are written as line charts with the two series as lines over the categories: DrawingML has no slope type.");
|
|
483
|
+
type = "line";
|
|
484
|
+
} else if (family === "likert") {
|
|
485
|
+
issues.push("Likert charts are written as 100% stacked horizontal bars: DrawingML has no diverging bar.");
|
|
486
|
+
spec = { ...spec, type: "bar", stacking: "percent", orientation: "horizontal" };
|
|
487
|
+
type = "bar";
|
|
445
488
|
}
|
|
446
489
|
const visible = spec.series.filter((s) => !s.hidden);
|
|
490
|
+
const annotations = [
|
|
491
|
+
spec.referenceLines.length || spec.referenceBands.length ? "reference lines and bands" : "",
|
|
492
|
+
spec.series.some((s) => s.callouts) ? "callouts" : "",
|
|
493
|
+
spec.highlight.length ? "the highlight" : "",
|
|
494
|
+
spec.note ? "the note" : ""
|
|
495
|
+
].filter(Boolean);
|
|
496
|
+
if (annotations.length) issues.push(`${annotations.join(", ").replace(/^./, (c) => c.toUpperCase())} ${annotations.length === 1 && !annotations[0].endsWith("s") ? "is" : "are"} not written: DrawingML has no equivalent.`);
|
|
447
497
|
if (visible.length < spec.series.length) issues.push(`${spec.series.length - visible.length} hidden series ${spec.series.length - visible.length === 1 ? "is" : "are"} left out.`);
|
|
448
498
|
const grouping = spec.stacking === "stacked" ? "stacked" : spec.stacking === "percent" ? "percentStacked" : "standard";
|
|
449
499
|
const ids = { cat: 500000001, val: 500000002, cat2: 500000003, val2: 500000004 };
|
|
@@ -512,6 +562,7 @@ function chartToOoxml(spec) {
|
|
|
512
562
|
return `<c:ser>${parts.join("")}</c:ser>`;
|
|
513
563
|
};
|
|
514
564
|
const dLbls = `<c:dLbls><c:showLegendKey val="0"/><c:showVal val="${spec.dataLabels ? 1 : 0}"/><c:showCatName val="0"/><c:showSerName val="0"/><c:showPercent val="0"/><c:showBubbleSize val="0"/></c:dLbls>`;
|
|
565
|
+
const vary = chartVariesColors(spec) ? 1 : 0;
|
|
515
566
|
const groupXml = groups.map((g) => {
|
|
516
567
|
const axes2 = g.secondary ? `<c:axId val="${ids.cat2}"/><c:axId val="${ids.val2}"/>` : `<c:axId val="${ids.cat}"/><c:axId val="${ids.val}"/>`;
|
|
517
568
|
const sers = g.series.map(({ s, index }) => serXml(g.kind, s, index)).join("");
|
|
@@ -521,14 +572,14 @@ function chartToOoxml(spec) {
|
|
|
521
572
|
const barsWidth = spec.stacking === "none" ? n - (n - 1) * spec.overlap : 1;
|
|
522
573
|
const gapPct = Math.round(Math.min(500, spec.gapWidth / Math.max(0.01, 1 - spec.gapWidth) * barsWidth * 100));
|
|
523
574
|
const overlapPct = spec.stacking === "none" ? Math.round(spec.overlap * 100) : 100;
|
|
524
|
-
return `<c:barChart><c:barDir val="${spec.orientation === "horizontal" ? "bar" : "col"}"/><c:grouping val="${spec.stacking === "none" ? "clustered" : grouping}"/><c:varyColors val="
|
|
575
|
+
return `<c:barChart><c:barDir val="${spec.orientation === "horizontal" ? "bar" : "col"}"/><c:grouping val="${spec.stacking === "none" ? "clustered" : grouping}"/><c:varyColors val="${vary}"/>${sers}${dLbls}<c:gapWidth val="${gapPct}"/><c:overlap val="${overlapPct}"/>${axes2}</c:barChart>`;
|
|
525
576
|
}
|
|
526
577
|
case "line":
|
|
527
|
-
return `<c:lineChart><c:grouping val="${spec.stacking === "none" ? "standard" : "standard"}"/><c:varyColors val="
|
|
578
|
+
return `<c:lineChart><c:grouping val="${spec.stacking === "none" ? "standard" : "standard"}"/><c:varyColors val="${vary}"/>${sers}${dLbls}<c:marker val="1"/>${axes2}</c:lineChart>`;
|
|
528
579
|
case "area":
|
|
529
|
-
return `<c:areaChart><c:grouping val="${grouping}"/><c:varyColors val="
|
|
580
|
+
return `<c:areaChart><c:grouping val="${grouping}"/><c:varyColors val="${vary}"/>${sers}${dLbls}${axes2}</c:areaChart>`;
|
|
530
581
|
case "scatter":
|
|
531
|
-
return `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="
|
|
582
|
+
return `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="${vary}"/>${sers}${dLbls}${axes2}</c:scatterChart>`;
|
|
532
583
|
case "bubble":
|
|
533
584
|
return `<c:bubbleChart><c:varyColors val="0"/>${sers}${dLbls}<c:bubbleScale val="100"/>${axes2}</c:bubbleChart>`;
|
|
534
585
|
case "radar":
|
|
@@ -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;
|