@pixerate/editor 0.162.1 → 0.164.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/displacement.d.cts +34 -2
- package/dist/canvas/displacement.d.ts +34 -2
- package/dist/canvas/explosion-tools.d.cts +43 -0
- package/dist/canvas/explosion-tools.d.ts +43 -0
- package/dist/canvas/explosionLayout.d.cts +50 -0
- package/dist/canvas/explosionLayout.d.ts +50 -0
- package/dist/canvas/explosionState.d.cts +52 -0
- package/dist/canvas/explosionState.d.ts +52 -0
- package/dist/canvas/index.cjs +430 -88
- package/dist/canvas/index.d.cts +3 -0
- package/dist/canvas/index.d.ts +3 -0
- package/dist/canvas/index.js +425 -83
- package/dist/canvas/types.d.cts +27 -2
- package/dist/canvas/types.d.ts +27 -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/README.md +12 -0
- package/skills/pixerate-agent-tools/SKILL.md +34 -1
- package/skills/pixerate-canvas/SKILL.md +16 -0
- package/skills/pixerate-chart/SKILL.md +41 -9
- package/skills/pixerate-image-editor/SKILL.md +2 -0
- package/skills/pixerate-paint-editor/SKILL.md +2 -0
- package/skills/pixerate-tokens/SKILL.md +5 -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 (series?.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 = spec.series[seriesIndex]?.pointColors?.[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,206 @@ 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) : 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 = list?.find((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: 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 = 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
|
+
|
|
776
1112
|
export {
|
|
777
1113
|
parseChartColor,
|
|
778
1114
|
chartRgbToHex,
|
|
@@ -795,6 +1131,22 @@ export {
|
|
|
795
1131
|
chartErrorBarsOfType,
|
|
796
1132
|
formatChartAmountList,
|
|
797
1133
|
parseChartAmountList,
|
|
1134
|
+
MAX_CHART_TREE_DEPTH,
|
|
1135
|
+
MAX_CHART_TREE_NODES,
|
|
1136
|
+
normalizeChartTree,
|
|
1137
|
+
chartTreeTotal,
|
|
1138
|
+
chartTreeDepth,
|
|
1139
|
+
findChartTreeNode,
|
|
1140
|
+
chartTreeToRows,
|
|
1141
|
+
chartTreeFromRows,
|
|
1142
|
+
chartTreeFromTable,
|
|
1143
|
+
chartTreeFromSeries,
|
|
1144
|
+
cloneChartTree,
|
|
1145
|
+
chartTreeColumnLabels,
|
|
1146
|
+
setChartTreeRowName,
|
|
1147
|
+
setChartTreeRowValue,
|
|
1148
|
+
addChartTreeRow,
|
|
1149
|
+
removeChartTreeRow,
|
|
798
1150
|
CHART_TYPES,
|
|
799
1151
|
CHART_MARKERS,
|
|
800
1152
|
CHART_TRENDLINE_TYPES,
|
|
@@ -805,6 +1157,9 @@ export {
|
|
|
805
1157
|
CHART_STACKINGS,
|
|
806
1158
|
CHART_CURVES,
|
|
807
1159
|
CHART_RADAR_GRATICULES,
|
|
1160
|
+
CHART_LIKERT_NEUTRALS,
|
|
1161
|
+
CHART_LIKERT_SORTS,
|
|
1162
|
+
CHART_REFERENCE_AXES,
|
|
808
1163
|
CHART_ORIENTATIONS,
|
|
809
1164
|
CHART_LEGEND_POSITIONS,
|
|
810
1165
|
CHART_NUMBER_STYLES,
|
|
@@ -816,16 +1171,21 @@ export {
|
|
|
816
1171
|
isXyChart,
|
|
817
1172
|
chartFamily,
|
|
818
1173
|
chartColorsByCategory,
|
|
1174
|
+
chartSpecColorsByCategory,
|
|
819
1175
|
defaultChartAxis,
|
|
820
1176
|
createChartSpec,
|
|
821
1177
|
chartSeriesColor,
|
|
1178
|
+
chartLikertColor,
|
|
822
1179
|
chartSliceColor,
|
|
1180
|
+
chartVariesColors,
|
|
823
1181
|
chartPointColor,
|
|
824
1182
|
chartSeriesType,
|
|
825
1183
|
uniqueChartSeriesId,
|
|
826
1184
|
parseChartValue,
|
|
827
1185
|
normalizeChartAxis,
|
|
828
1186
|
normalizeChartValues,
|
|
1187
|
+
normalizeChartReferenceLine,
|
|
1188
|
+
normalizeChartReferenceBand,
|
|
829
1189
|
normalizeChartErrorBars,
|
|
830
1190
|
normalizeChartTrendline,
|
|
831
1191
|
normalizeChartSpec,
|
|
@@ -6,15 +6,18 @@ import {
|
|
|
6
6
|
CHART_ERROR_BAR_TYPES,
|
|
7
7
|
CHART_LABEL_POSITIONS,
|
|
8
8
|
CHART_LEGEND_POSITIONS,
|
|
9
|
+
CHART_LIKERT_NEUTRALS,
|
|
10
|
+
CHART_LIKERT_SORTS,
|
|
9
11
|
CHART_MARKERS,
|
|
10
12
|
CHART_NUMBER_STYLES,
|
|
11
13
|
CHART_ORIENTATIONS,
|
|
12
14
|
CHART_RADAR_GRATICULES,
|
|
15
|
+
CHART_REFERENCE_AXES,
|
|
13
16
|
CHART_SERIES_TYPES,
|
|
14
17
|
CHART_STACKINGS,
|
|
15
18
|
CHART_TRENDLINE_TYPES,
|
|
16
19
|
CHART_TYPES
|
|
17
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-3NEZJCBY.js";
|
|
18
21
|
|
|
19
22
|
// src/chart/schemas.ts
|
|
20
23
|
var VALUE = { type: ["number", "string", "null"], description: 'A number, numeric text ("1,200", "12%", "$40", "(3)") or null for a gap.' };
|
|
@@ -69,6 +72,46 @@ var TRENDLINE_PROPS = {
|
|
|
69
72
|
name: { type: "string", description: 'Legend name (default e.g. "Linear (Sales)").' },
|
|
70
73
|
color: { type: "string", description: "CSS colour (default: the series colour)." }
|
|
71
74
|
};
|
|
75
|
+
var REFERENCE_COMMON = {
|
|
76
|
+
label: { type: "string", description: 'Text written on it, e.g. "Target" (default none).' },
|
|
77
|
+
axis: {
|
|
78
|
+
type: "string",
|
|
79
|
+
enum: [...CHART_REFERENCE_AXES],
|
|
80
|
+
description: "Axis it is measured on: y (default) is the value axis, y2 the secondary value axis (needs a series there), x the numeric x axis of a scatter or bubble chart."
|
|
81
|
+
},
|
|
82
|
+
color: { type: "string", description: "CSS colour (default: the text colour)." }
|
|
83
|
+
};
|
|
84
|
+
var REFERENCE_LINE_PROPS = {
|
|
85
|
+
value: { type: "number", description: "Where the line crosses its axis, in data units." },
|
|
86
|
+
...REFERENCE_COMMON
|
|
87
|
+
};
|
|
88
|
+
var REFERENCE_BAND_PROPS = {
|
|
89
|
+
from: { type: "number", description: "One end of the band on its axis, in data units." },
|
|
90
|
+
to: { type: "number", description: "The other end of the band, in data units (ends may come in either order)." },
|
|
91
|
+
...REFERENCE_COMMON
|
|
92
|
+
};
|
|
93
|
+
var REFERENCE_COMMON_PATCH = {
|
|
94
|
+
label: { type: ["string", "null"], description: "Text written on it; null removes it." },
|
|
95
|
+
axis: { type: ["string", "null"], enum: [...CHART_REFERENCE_AXES, null], description: "Axis it is measured on (y, y2 or x); null goes back to y." },
|
|
96
|
+
color: { type: ["string", "null"], description: "CSS colour; null goes back to the text colour." }
|
|
97
|
+
};
|
|
98
|
+
var REFERENCE_LINE_PATCH = { value: REFERENCE_LINE_PROPS.value, ...REFERENCE_COMMON_PATCH };
|
|
99
|
+
var REFERENCE_BAND_PATCH = { from: REFERENCE_BAND_PROPS.from, to: REFERENCE_BAND_PROPS.to, ...REFERENCE_COMMON_PATCH };
|
|
100
|
+
var REFERENCE_INDEX = (what) => ({ type: "integer", minimum: 0, description: `${what} index (0 = first), as get_chart lists them in spec.${what === "Reference line" ? "referenceLines" : "referenceBands"}.` });
|
|
101
|
+
var TREE_NODE = {
|
|
102
|
+
type: "object",
|
|
103
|
+
description: 'An item ({"name", "value"}) or a group ({"name", "children": [nodes]}, whose value is the sum of its items).',
|
|
104
|
+
properties: {
|
|
105
|
+
name: { type: "string", description: "Label; unique among its siblings." },
|
|
106
|
+
value: { type: "number", minimum: 0, description: "Items only: the amount, 0 or more." },
|
|
107
|
+
children: { type: "array", items: { $ref: "#/$defs/chartTreeNode" }, description: "Groups only: the nodes inside it (up to 6 levels in all)." },
|
|
108
|
+
color: { type: "string", description: "CSS colour (default: the palette colour of its top-level group, lighter further in)." }
|
|
109
|
+
},
|
|
110
|
+
required: ["name"],
|
|
111
|
+
additionalProperties: false
|
|
112
|
+
};
|
|
113
|
+
var TREE_DEFS = { chartTreeNode: TREE_NODE };
|
|
114
|
+
var TREE_PATH = { type: "array", items: { type: "string" }, minItems: 1, description: 'Names from the top level down to the node, e.g. ["Europe", "France"] (from get_chart treeTable or spec.tree).' };
|
|
72
115
|
var ERROR_BARS = (what) => ({
|
|
73
116
|
type: ["object", "null"],
|
|
74
117
|
description: `${what} null removes them.`,
|
|
@@ -97,6 +140,7 @@ var SERIES_PROPS = {
|
|
|
97
140
|
x: { type: ["array", "null"], items: VALUE, description: "Numeric x per category, for scatter and bubble charts." },
|
|
98
141
|
sizes: { type: ["array", "null"], items: VALUE, description: "Bubble sizes per category (area is proportional to size)." },
|
|
99
142
|
pointColors: { type: ["array", "null"], items: { type: ["string", "null"] }, description: "Colour per category (null keeps the series colour)." },
|
|
143
|
+
callouts: { type: ["array", "null"], items: { type: ["string", "null"] }, description: "A label pinned to each point that matters, one per category (null: none); null removes them all. Bar, line, area and scatter charts. set_chart_callout sets one." },
|
|
100
144
|
marker: { type: ["string", "null"], enum: [...CHART_MARKERS, null], description: "Point marker shape for line, area and scatter series." },
|
|
101
145
|
curve: { type: ["string", "null"], enum: [...CHART_CURVES, null], description: "Line shape for this series: linear, smooth or step." },
|
|
102
146
|
dataLabels: { type: ["boolean", "null"], description: "Value labels for this series (null follows the chart)." },
|
|
@@ -105,7 +149,7 @@ var SERIES_PROPS = {
|
|
|
105
149
|
xErrorBars: ERROR_BARS("Error bars along the x axis (scatter and bubble charts with numeric x values; amounts in x units).")
|
|
106
150
|
};
|
|
107
151
|
var CHART_UPDATE_PROPERTIES = {
|
|
108
|
-
type: { type: "string", enum: [...CHART_TYPES], description: "Chart type." },
|
|
152
|
+
type: { type: "string", enum: [...CHART_TYPES], description: "Chart type. slope joins each category from the first series (before) to the second (after); likert reads each category as a question and the series as answers from most negative to most positive; parliament draws the first series as seats; sunburst draws the grouped data (set_chart_tree) as rings, and a treemap with grouped data nests its groups." },
|
|
109
153
|
title: { type: "string", description: 'Title ("" for none).' },
|
|
110
154
|
subtitle: { type: "string", description: 'Subtitle ("" for none).' },
|
|
111
155
|
xAxis: AXIS("Category axis (or numeric x axis of scatter / bubble charts)."),
|
|
@@ -130,7 +174,18 @@ var CHART_UPDATE_PROPERTIES = {
|
|
|
130
174
|
bins: { type: ["integer", "null"], minimum: 1, maximum: 500, description: "Histogram bin count, or null for \u221An." },
|
|
131
175
|
showTotal: { type: "boolean", description: "Waterfall: append a total bar." },
|
|
132
176
|
radarTicks: { type: ["integer", "null"], minimum: 1, maximum: 50, description: "Radar: number of evenly spaced rings from the value axis min to max, or null for round-number rings (default null)." },
|
|
133
|
-
radarGraticule: { type: "string", enum: [...CHART_RADAR_GRATICULES], description: "Radar: draw rings as polygons through the spokes or as circles (default polygon)." }
|
|
177
|
+
radarGraticule: { type: "string", enum: [...CHART_RADAR_GRATICULES], description: "Radar: draw rings as polygons through the spokes or as circles (default polygon)." },
|
|
178
|
+
note: { type: "string", description: 'A source or footnote written under the chart ("" for none).' },
|
|
179
|
+
highlight: { type: "array", items: { type: "string" }, description: "Category labels and series names (or ids) to draw normally while the rest are muted; [] shows everything. highlight_chart checks the names." },
|
|
180
|
+
referenceLines: { type: "array", items: { type: "object", properties: REFERENCE_LINE_PROPS, required: ["value"], additionalProperties: false }, description: "Replaces every reference line (targets, floors, averages across the plot). add_chart_reference_line adds one." },
|
|
181
|
+
referenceBands: { type: "array", items: { type: "object", properties: REFERENCE_BAND_PROPS, required: ["from", "to"], additionalProperties: false }, description: "Replaces every reference band (target ranges across the plot). add_chart_reference_band adds one." },
|
|
182
|
+
varyColors: { type: "boolean", description: "A one-series bar, line, area or scatter chart colours each category from the palette, and its legend lists the categories (default false)." },
|
|
183
|
+
likertNeutral: { type: "string", enum: [...CHART_LIKERT_NEUTRALS], description: "Likert with an odd number of answers: split (default) puts the middle answer across the centre line; separate draws it in its own column on the right." },
|
|
184
|
+
likertSort: { type: "string", enum: [...CHART_LIKERT_SORTS], description: "Likert: order the questions by agreement (positive), by disagreement (negative) or as given (none, default)." },
|
|
185
|
+
parliamentArc: { type: "number", minimum: 90, maximum: 360, description: "Parliament: sweep of the hemicycle in degrees (default 180)." },
|
|
186
|
+
parliamentMajority: { type: ["integer", "null"], minimum: 1, description: "Parliament: seats needed for a majority, drawn as a dashed line (null: half of the seats plus one)." },
|
|
187
|
+
parliamentLabel: { type: "string", description: 'Parliament: caption under the seat total ("" writes "seats").' },
|
|
188
|
+
sunburstLabel: { type: "string", description: 'Sunburst: caption under the total in the centre ("" for none).' }
|
|
134
189
|
};
|
|
135
190
|
|
|
136
191
|
export {
|
|
@@ -140,6 +195,13 @@ export {
|
|
|
140
195
|
WIDTH,
|
|
141
196
|
HEIGHT,
|
|
142
197
|
TRENDLINE_PROPS,
|
|
198
|
+
REFERENCE_LINE_PROPS,
|
|
199
|
+
REFERENCE_BAND_PROPS,
|
|
200
|
+
REFERENCE_LINE_PATCH,
|
|
201
|
+
REFERENCE_BAND_PATCH,
|
|
202
|
+
REFERENCE_INDEX,
|
|
203
|
+
TREE_DEFS,
|
|
204
|
+
TREE_PATH,
|
|
143
205
|
SERIES_PROPS,
|
|
144
206
|
CHART_UPDATE_PROPERTIES
|
|
145
207
|
};
|