@skdx/angular-charts 0.39.0 → 0.41.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 +2 -3
- package/fesm2022/skdx-angular-charts-candlestick.mjs +9 -2
- package/fesm2022/skdx-angular-charts-candlestick.mjs.map +1 -1
- package/fesm2022/skdx-angular-charts-internal.mjs +360 -130
- package/fesm2022/skdx-angular-charts-internal.mjs.map +1 -1
- package/fesm2022/skdx-angular-charts.mjs.map +1 -1
- package/package.json +4 -3
- package/types/skdx-angular-charts-candlestick.d.ts +5 -2
- package/types/skdx-angular-charts-internal.d.ts +23 -9
- package/types/skdx-angular-charts.d.ts +1 -1
|
@@ -470,6 +470,16 @@ const legendTop = (input, items, width) => {
|
|
|
470
470
|
};
|
|
471
471
|
/** Average glyph width at the chart font size, for text-width estimates. */
|
|
472
472
|
const CHAR = 6.5;
|
|
473
|
+
/** Fit visible chart text while callers keep the complete string as a title or item label. */
|
|
474
|
+
function fitText(text, width) {
|
|
475
|
+
const chars = Array.from(text);
|
|
476
|
+
const capacity = Math.max(0, Math.floor(width / CHAR));
|
|
477
|
+
return chars.length <= capacity
|
|
478
|
+
? text
|
|
479
|
+
: capacity === 0
|
|
480
|
+
? ''
|
|
481
|
+
: `${chars.slice(0, capacity - 1).join('')}…`;
|
|
482
|
+
}
|
|
473
483
|
/** The series color for index `i`: an explicit override, else the chart palette, else the tokens. */
|
|
474
484
|
const colorOf = (input, i, override) => override ??
|
|
475
485
|
(input.palette && input.palette.length > 0
|
|
@@ -625,9 +635,29 @@ function placeLegend(layout) {
|
|
|
625
635
|
}
|
|
626
636
|
/** A tooltip box next to the pointer, kept inside the canvas; one line per entry. */
|
|
627
637
|
function tooltipShapes(x, y, text, width, height, placement = 'auto') {
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
const
|
|
638
|
+
const original = Array.isArray(text) ? text : [text];
|
|
639
|
+
const capacity = Math.max(1, Math.floor((width - 12) / CHAR));
|
|
640
|
+
const wrapped = original.flatMap((line) => {
|
|
641
|
+
const result = [];
|
|
642
|
+
let rest = Array.from(line);
|
|
643
|
+
while (rest.length > capacity) {
|
|
644
|
+
let end = rest.slice(0, capacity + 1).lastIndexOf(' ');
|
|
645
|
+
if (end < 1)
|
|
646
|
+
end = capacity;
|
|
647
|
+
result.push(rest.slice(0, end).join(''));
|
|
648
|
+
rest = rest.slice(end);
|
|
649
|
+
if (rest[0] === ' ')
|
|
650
|
+
rest.shift();
|
|
651
|
+
}
|
|
652
|
+
result.push(rest.join(''));
|
|
653
|
+
return result;
|
|
654
|
+
});
|
|
655
|
+
const maxLines = Math.max(1, Math.floor((height - 6) / 16));
|
|
656
|
+
const lines = wrapped.slice(0, maxLines);
|
|
657
|
+
if (wrapped.length > maxLines)
|
|
658
|
+
lines[maxLines - 1] = fitText(`${lines[maxLines - 1]}…`, width - 12);
|
|
659
|
+
const w = Math.min(width, Math.max(0, ...lines.map((l) => Array.from(l).length)) * CHAR + 12);
|
|
660
|
+
const h = Math.min(height, 6 + lines.length * 16);
|
|
631
661
|
// `auto` sits above-right of the anchor and slides inside the canvas; a fixed placement
|
|
632
662
|
// centres the box on the named side and is only clamped.
|
|
633
663
|
const wanted = placement === 'top'
|
|
@@ -645,13 +675,14 @@ function tooltipShapes(x, y, text, width, height, placement = 'auto') {
|
|
|
645
675
|
{
|
|
646
676
|
kind: 'rect',
|
|
647
677
|
part: 'tooltip',
|
|
678
|
+
title: original.join('\n'),
|
|
648
679
|
x: px(bx),
|
|
649
680
|
y: px(by),
|
|
650
681
|
width: px(w),
|
|
651
682
|
height: h,
|
|
652
683
|
fill: 'var(--skdx-color-surface-raised)',
|
|
653
684
|
stroke: CHART_COLORS.axis,
|
|
654
|
-
rx:
|
|
685
|
+
rx: 8,
|
|
655
686
|
},
|
|
656
687
|
...lines.map((line, i) => ({
|
|
657
688
|
kind: 'text',
|
|
@@ -783,7 +814,7 @@ function stateCanvas(input, empty, w, h) {
|
|
|
783
814
|
width,
|
|
784
815
|
height,
|
|
785
816
|
fill: 'var(--skdx-color-surface-sunken)',
|
|
786
|
-
rx:
|
|
817
|
+
rx: 8,
|
|
787
818
|
});
|
|
788
819
|
shapes.push({
|
|
789
820
|
kind: 'text',
|
|
@@ -850,7 +881,7 @@ function frameShapes(frame, options = {}) {
|
|
|
850
881
|
baseline: 'middle',
|
|
851
882
|
rotate: rot,
|
|
852
883
|
})
|
|
853
|
-
:
|
|
884
|
+
: boundedLabel(x, y, text, frame.width, { part, anchor: tickAnchor(x, text, frame.width) });
|
|
854
885
|
// Short marks across an axis line at the ticks.
|
|
855
886
|
const marks = (ticks, along, at, dir, size) => {
|
|
856
887
|
for (const t of ticks)
|
|
@@ -1034,6 +1065,54 @@ function frameShapes(frame, options = {}) {
|
|
|
1034
1065
|
return shapes;
|
|
1035
1066
|
}
|
|
1036
1067
|
const label = (x, y, text, extra = {}) => ({ kind: 'text', part: 'label', x, y, text, fill: CHART_COLORS.label, ...extra });
|
|
1068
|
+
/** A label that stays inside the SVG, with the full wording available as its native title. */
|
|
1069
|
+
function boundedLabel(x, y, text, width, extra = {}) {
|
|
1070
|
+
const at = Math.max(4, Math.min(width - 4, x));
|
|
1071
|
+
const anchor = extra.anchor ?? 'start';
|
|
1072
|
+
const available = anchor === 'middle'
|
|
1073
|
+
? 2 * Math.min(at - 4, width - at - 4)
|
|
1074
|
+
: anchor === 'end'
|
|
1075
|
+
? at - 4
|
|
1076
|
+
: width - at - 4;
|
|
1077
|
+
const visible = fitText(text, available);
|
|
1078
|
+
return {
|
|
1079
|
+
kind: 'text',
|
|
1080
|
+
part: 'label',
|
|
1081
|
+
x: at,
|
|
1082
|
+
y,
|
|
1083
|
+
fill: CHART_COLORS.label,
|
|
1084
|
+
...extra,
|
|
1085
|
+
text: visible,
|
|
1086
|
+
title: visible === text ? extra.title : text,
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
/** Keep inside and reference labels readable over arbitrary series colours. */
|
|
1090
|
+
function withLabelSurfaces(shapes) {
|
|
1091
|
+
return shapes.flatMap((shape) => {
|
|
1092
|
+
if (shape.kind !== 'text' ||
|
|
1093
|
+
(shape.fill !== 'var(--skdx-color-text-on-accent)' && shape.part !== 'reference-label'))
|
|
1094
|
+
return [shape];
|
|
1095
|
+
const width = shape.text.length * CHAR + 8;
|
|
1096
|
+
const x = shape.x - (shape.anchor === 'middle' ? width / 2 : shape.anchor === 'end' ? width - 4 : 4);
|
|
1097
|
+
const y = shape.y - (shape.baseline === 'hanging' ? 2 : shape.baseline === 'middle' ? 9 : 14);
|
|
1098
|
+
return [
|
|
1099
|
+
{
|
|
1100
|
+
kind: 'rect',
|
|
1101
|
+
part: 'label-background',
|
|
1102
|
+
x,
|
|
1103
|
+
y,
|
|
1104
|
+
width,
|
|
1105
|
+
height: 18,
|
|
1106
|
+
rx: 8,
|
|
1107
|
+
fill: 'var(--skdx-color-surface-raised)',
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
...shape,
|
|
1111
|
+
fill: shape.part === 'reference-label' ? shape.fill : 'var(--skdx-color-text-default)',
|
|
1112
|
+
},
|
|
1113
|
+
];
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1037
1116
|
/** A dot with its native tooltip. */
|
|
1038
1117
|
const point$1 = (cx, cy, r, fill, title, item) => ({ kind: 'circle', part: 'point', cx, cy, r, fill, title, item });
|
|
1039
1118
|
|
|
@@ -1753,25 +1832,39 @@ function layoutPoints(input, options) {
|
|
|
1753
1832
|
const legendRoom = input.colorScale
|
|
1754
1833
|
? colorLegendRoom(input.colorLegend)
|
|
1755
1834
|
: { bottom: 0, right: 0, options: {} };
|
|
1835
|
+
const legend = input.series.map((s, i) => ({ name: s.name, color: colorOf(input, i, s.color) }));
|
|
1756
1836
|
const plot = plotBox(width, height, {
|
|
1757
1837
|
...MARGIN$1,
|
|
1758
|
-
top: MARGIN$1.top + legendTop(input) + (input.yAxis?.label ? 12 : 0),
|
|
1838
|
+
top: MARGIN$1.top + legendTop(input, legend, width) + (input.yAxis?.label ? 12 : 0),
|
|
1759
1839
|
right: MARGIN$1.right + legendRoom.right,
|
|
1760
1840
|
bottom: MARGIN$1.bottom + (input.xAxis?.label ? 14 : 0) + legendRoom.bottom,
|
|
1761
1841
|
});
|
|
1762
1842
|
const markerSize = input.markerSize ?? 3;
|
|
1763
1843
|
const hitRadius = Math.max(0, input.hitRadius ?? 0);
|
|
1764
|
-
const
|
|
1844
|
+
const requestedJitter = Math.max(0, input.jitter ?? 0);
|
|
1845
|
+
const sizes = minMax(dots.map((p) => p.size));
|
|
1846
|
+
const extentFactor = (symbol) => symbol === 'diamond' ? 1.3 : symbol === 'triangle' ? 1.2 : 1;
|
|
1847
|
+
const requestedRadius = (dot, sized) => Math.max(0, sized ? options.radius(dot.size, sizes) : markerSize);
|
|
1848
|
+
let largestExtent = 0;
|
|
1849
|
+
for (const series of shown) {
|
|
1850
|
+
const sized = series.data.some((dot) => dot.size !== undefined);
|
|
1851
|
+
const factor = extentFactor(series.symbol);
|
|
1852
|
+
for (const dot of series.data)
|
|
1853
|
+
largestExtent = Math.max(largestExtent, requestedRadius(dot, sized) * factor);
|
|
1854
|
+
}
|
|
1855
|
+
// Scale visible extents together only when a tiny plot cannot contain the requested size.
|
|
1856
|
+
// Keep data domains intact and use the same inset scales for marks/references/trends.
|
|
1857
|
+
const extentScale = Math.min(1, (Math.min(plot.width, plot.height) * 0.45) / Math.max(1, largestExtent + requestedJitter));
|
|
1858
|
+
const jitter = requestedJitter * extentScale;
|
|
1859
|
+
const inset = largestExtent * extentScale + jitter;
|
|
1765
1860
|
// Duplicates at one pixel are spread deterministically on a ring around it.
|
|
1766
1861
|
const seen = new Map();
|
|
1767
1862
|
// A color scale maps each dot's `value`; dots without one keep their series color.
|
|
1768
1863
|
const colors = input.colorScale
|
|
1769
1864
|
? makeColorScale(input.colorScale, dots.map((d) => d.value), colorOf(input, 0), undefined, makeFormatter(input.format))
|
|
1770
1865
|
: undefined;
|
|
1771
|
-
const x = axis(extent(dots.map((p) => p.x), false), [plot.x, plot.x + plot.width], input.xAxis ?? {}, input.format);
|
|
1772
|
-
const y = axis(extent(dots.map((p) => p.y), false), [plot.y + plot.height, plot.y], input.yAxis ?? {}, input.format);
|
|
1773
|
-
const sizes = minMax(dots.map((p) => p.size));
|
|
1774
|
-
const legend = input.series.map((s, i) => ({ name: s.name, color: colorOf(input, i, s.color) }));
|
|
1866
|
+
const x = axis(extent(dots.map((p) => p.x), false), [plot.x + inset, plot.x + plot.width - inset], input.xAxis ?? {}, input.format);
|
|
1867
|
+
const y = axis(extent(dots.map((p) => p.y), false), [plot.y + plot.height - inset, plot.y + inset], input.yAxis ?? {}, input.format);
|
|
1775
1868
|
const c = canvas(input, width, height, legend);
|
|
1776
1869
|
const marks = [];
|
|
1777
1870
|
const texts = [];
|
|
@@ -1783,7 +1876,7 @@ function layoutPoints(input, options) {
|
|
|
1783
1876
|
for (const dot of s.data) {
|
|
1784
1877
|
const di = dot.index;
|
|
1785
1878
|
const title = options.describe(s.name, dot, x, y);
|
|
1786
|
-
const r =
|
|
1879
|
+
const r = requestedRadius(dot, sized) * extentScale;
|
|
1787
1880
|
let cx = px(x.scale(dot.x));
|
|
1788
1881
|
let cy = px(y.scale(dot.y));
|
|
1789
1882
|
if (jitter > 0) {
|
|
@@ -1875,7 +1968,29 @@ function layoutPoints(input, options) {
|
|
|
1875
1968
|
}
|
|
1876
1969
|
}
|
|
1877
1970
|
}
|
|
1878
|
-
|
|
1971
|
+
// Check the final edge anchors as well as average tick spacing.
|
|
1972
|
+
let tickRight = -Infinity;
|
|
1973
|
+
const candidates = thinTicks(x.ticks, Math.max(1, plot.width - 2 * inset));
|
|
1974
|
+
const kept = new Set();
|
|
1975
|
+
for (const tick of [...candidates].sort((a, b) => a.pos - b.pos)) {
|
|
1976
|
+
const textWidth = tick.label.length * CHAR;
|
|
1977
|
+
const rotation = input.xAxis?.tickRotation ?? 0;
|
|
1978
|
+
const anchor = rotation
|
|
1979
|
+
? rotation < 0
|
|
1980
|
+
? 'end'
|
|
1981
|
+
: 'start'
|
|
1982
|
+
: tickAnchor(tick.pos, tick.label, width);
|
|
1983
|
+
const left = -(anchor === 'end' ? textWidth : anchor === 'middle' ? textWidth / 2 : 0);
|
|
1984
|
+
const angle = (rotation * Math.PI) / 180;
|
|
1985
|
+
const corners = [left, left + textWidth].flatMap((x) => [-7, 7].map((y) => tick.pos + x * Math.cos(angle) - y * Math.sin(angle)));
|
|
1986
|
+
const start = Math.min(...corners), end = Math.max(...corners);
|
|
1987
|
+
if (start < tickRight + 4)
|
|
1988
|
+
continue;
|
|
1989
|
+
tickRight = end;
|
|
1990
|
+
kept.add(tick);
|
|
1991
|
+
}
|
|
1992
|
+
const xTicks = candidates.filter((tick) => kept.has(tick));
|
|
1993
|
+
const frame = { ...c, plot, xTicks, yTicks: y.ticks, baseline: y.zero };
|
|
1879
1994
|
const scales = {
|
|
1880
1995
|
plot,
|
|
1881
1996
|
x: (v) => x.scale(categoryValue(v)),
|
|
@@ -1901,7 +2016,20 @@ function layoutPoints(input, options) {
|
|
|
1901
2016
|
return {
|
|
1902
2017
|
...c,
|
|
1903
2018
|
shapes: [
|
|
1904
|
-
...frameShapes(frame,
|
|
2019
|
+
...frameShapes({ ...frame, height: frame.height - legendRoom.bottom }, {
|
|
2020
|
+
xLabel: input.xAxis?.label,
|
|
2021
|
+
x: input.xAxis,
|
|
2022
|
+
// Frame axes spread decoration fields; never forward a second title through y.
|
|
2023
|
+
y: {
|
|
2024
|
+
showLine: input.yAxis?.showLine,
|
|
2025
|
+
showTicks: input.yAxis?.showTicks,
|
|
2026
|
+
tickSize: input.yAxis?.tickSize,
|
|
2027
|
+
tickRotation: input.yAxis?.tickRotation,
|
|
2028
|
+
},
|
|
2029
|
+
}),
|
|
2030
|
+
...(input.yAxis?.label
|
|
2031
|
+
? [label(4, plot.y - 14, input.yAxis.label, { part: 'axis-title', anchor: 'start' })]
|
|
2032
|
+
: []),
|
|
1905
2033
|
...references,
|
|
1906
2034
|
...(opacity !== undefined && marks.some((m) => m.part === options.part)
|
|
1907
2035
|
? marks.map((m) => (m.kind === 'circle' || m.kind === 'path') && m.part !== 'hit' ? { ...m, opacity } : m)
|
|
@@ -2392,8 +2520,12 @@ function layoutCartesian(input, defaultType) {
|
|
|
2392
2520
|
}
|
|
2393
2521
|
// The default bottom margin already holds the first bottom axis.
|
|
2394
2522
|
const firstBottom = shownAxes.find((a) => sideOf(a) === 'bottom');
|
|
2523
|
+
const legend = all.map((s) => ({ name: s.name, color: s.color }));
|
|
2395
2524
|
const margin = {
|
|
2396
|
-
top: MARGIN$1.top +
|
|
2525
|
+
top: MARGIN$1.top +
|
|
2526
|
+
legendTop(input, legend, width) +
|
|
2527
|
+
(defs.some((a) => a.label) ? 12 : 0) +
|
|
2528
|
+
room.top,
|
|
2397
2529
|
right: horizontal
|
|
2398
2530
|
? rtl
|
|
2399
2531
|
? Math.max(MARGIN$1.left, widestCategory + 16)
|
|
@@ -2461,7 +2593,7 @@ function layoutCartesian(input, defaultType) {
|
|
|
2461
2593
|
: plot.width /
|
|
2462
2594
|
Math.max(0.2, Math.abs(Math.cos(((input.xAxis?.tickRotation ?? 0) * Math.PI) / 180))));
|
|
2463
2595
|
const frame = {
|
|
2464
|
-
...canvas(input, width, height,
|
|
2596
|
+
...canvas(input, width, height, legend),
|
|
2465
2597
|
plot,
|
|
2466
2598
|
xTicks: categoryTicks,
|
|
2467
2599
|
yTicks: horizontal ? thinTicks(left.ticks, plot.width) : left.ticks,
|
|
@@ -2516,7 +2648,10 @@ function layoutCartesian(input, defaultType) {
|
|
|
2516
2648
|
},
|
|
2517
2649
|
y: (v, a) => value(v, a),
|
|
2518
2650
|
};
|
|
2519
|
-
|
|
2651
|
+
const references = referenceShapes(input.references, scales);
|
|
2652
|
+
shapes.push(...references.filter((shape) => shape.part !== 'reference-label'));
|
|
2653
|
+
// The reference geometry stays behind data, but its label must survive overlapping marks.
|
|
2654
|
+
const referenceLabels = withLabelSurfaces(references.filter((shape) => shape.part === 'reference-label'));
|
|
2520
2655
|
// One slot per plain bar series and one per bar stack group, side by side inside the band.
|
|
2521
2656
|
const slots = [];
|
|
2522
2657
|
const slotOf = new Map();
|
|
@@ -2909,7 +3044,7 @@ function layoutCartesian(input, defaultType) {
|
|
|
2909
3044
|
width: 6,
|
|
2910
3045
|
height: box.height - 16,
|
|
2911
3046
|
fill: CHART_COLORS.axis,
|
|
2912
|
-
rx:
|
|
3047
|
+
rx: 8,
|
|
2913
3048
|
}, {
|
|
2914
3049
|
kind: 'rect',
|
|
2915
3050
|
part: 'brush-handle',
|
|
@@ -2918,7 +3053,7 @@ function layoutCartesian(input, defaultType) {
|
|
|
2918
3053
|
width: 6,
|
|
2919
3054
|
height: box.height - 16,
|
|
2920
3055
|
fill: CHART_COLORS.axis,
|
|
2921
|
-
rx:
|
|
3056
|
+
rx: 8,
|
|
2922
3057
|
});
|
|
2923
3058
|
hit.brush = { box, window };
|
|
2924
3059
|
}
|
|
@@ -2932,6 +3067,7 @@ function layoutCartesian(input, defaultType) {
|
|
|
2932
3067
|
...errorMarks,
|
|
2933
3068
|
...points,
|
|
2934
3069
|
...texts,
|
|
3070
|
+
...referenceLabels,
|
|
2935
3071
|
...annotationShapes(input.annotations, scales),
|
|
2936
3072
|
...brush,
|
|
2937
3073
|
...frame.shapes,
|
|
@@ -3412,7 +3548,8 @@ function layoutPieChart(input) {
|
|
|
3412
3548
|
: (p) => `${Math.round(p * 100)}%`;
|
|
3413
3549
|
const cornerRadius = Math.max(0, input.cornerRadius ?? 0);
|
|
3414
3550
|
const { width, height } = size(input, 300, 300);
|
|
3415
|
-
const
|
|
3551
|
+
const legend = input.data.map((d, i) => ({ name: d.name, color: colorOf(input, i, d.color) }));
|
|
3552
|
+
const top = legendTop(input, legend, width);
|
|
3416
3553
|
const start = ((input.startAngle ?? 0) * Math.PI) / 180;
|
|
3417
3554
|
const end = ((input.endAngle ?? (input.startAngle ?? 0) + 360) * Math.PI) / 180;
|
|
3418
3555
|
const sweep = Math.max(0, Math.min(TAU$1, end - start));
|
|
@@ -3502,7 +3639,7 @@ function layoutPieChart(input) {
|
|
|
3502
3639
|
y2: px(cy - (r + 12) * Math.cos(mid)),
|
|
3503
3640
|
stroke: CHART_COLORS.axis,
|
|
3504
3641
|
});
|
|
3505
|
-
labels.push(
|
|
3642
|
+
labels.push(boundedLabel(px(cx + (r + 16) * sin), ly, text, width, {
|
|
3506
3643
|
part: 'slice-label',
|
|
3507
3644
|
anchor: sin > 0.1 ? 'start' : sin < -0.1 ? 'end' : 'middle',
|
|
3508
3645
|
baseline: 'middle',
|
|
@@ -3512,7 +3649,7 @@ function layoutPieChart(input) {
|
|
|
3512
3649
|
}
|
|
3513
3650
|
else if (percent > 0.03) {
|
|
3514
3651
|
const lr = (r + r0) / 2;
|
|
3515
|
-
labels.push(
|
|
3652
|
+
labels.push(boundedLabel(px(cx + lr * Math.sin(mid)), px(cy - lr * Math.cos(mid)), text, width, {
|
|
3516
3653
|
part: 'slice-label',
|
|
3517
3654
|
anchor: 'middle',
|
|
3518
3655
|
baseline: 'middle',
|
|
@@ -3541,8 +3678,12 @@ function layoutPieChart(input) {
|
|
|
3541
3678
|
fill: 'var(--skdx-color-text-default)',
|
|
3542
3679
|
weight: 'bold',
|
|
3543
3680
|
}));
|
|
3544
|
-
const c = canvas(input, width, height,
|
|
3545
|
-
return {
|
|
3681
|
+
const c = canvas(input, width, height, legend);
|
|
3682
|
+
return {
|
|
3683
|
+
...c,
|
|
3684
|
+
shapes: withLabelSurfaces([...slices, ...connectors, ...c.shapes, ...labels]),
|
|
3685
|
+
issues,
|
|
3686
|
+
};
|
|
3546
3687
|
}
|
|
3547
3688
|
|
|
3548
3689
|
/*
|
|
@@ -3702,7 +3843,8 @@ function layoutRadarChart(input) {
|
|
|
3702
3843
|
const issues = [];
|
|
3703
3844
|
const format = makeFormatter(input.format);
|
|
3704
3845
|
const { width, height } = size(input, 300, 300);
|
|
3705
|
-
const
|
|
3846
|
+
const legend = input.series.map((s, i) => ({ name: s.name, color: colorOf(input, i, s.color) }));
|
|
3847
|
+
const top = legendTop(input, legend, width);
|
|
3706
3848
|
const cx = width / 2;
|
|
3707
3849
|
const cy = top + (height - top) / 2;
|
|
3708
3850
|
const radius = Math.max(0, Math.min(width, height - top) / 2 - 36);
|
|
@@ -3864,7 +4006,7 @@ function layoutRadarChart(input) {
|
|
|
3864
4006
|
item: { label: s.name, series: s.name, seriesId: s.id },
|
|
3865
4007
|
});
|
|
3866
4008
|
});
|
|
3867
|
-
const c = canvas(input, width, height,
|
|
4009
|
+
const c = canvas(input, width, height, legend);
|
|
3868
4010
|
return { ...c, shapes: [...grid, ...polygons, ...points, ...texts, ...c.shapes], issues };
|
|
3869
4011
|
}
|
|
3870
4012
|
|
|
@@ -4101,7 +4243,8 @@ function layoutFunnelChart(input) {
|
|
|
4101
4243
|
const max = Math.max(0, ...data.map((d) => d.value));
|
|
4102
4244
|
const total = data.reduce((s, d) => s + Math.max(0, d.value), 0);
|
|
4103
4245
|
const first = data[0]?.value ?? 0;
|
|
4104
|
-
const
|
|
4246
|
+
const legend = data.map((d, i) => ({ name: d.name, color: colorOf(input, i, d.color) }));
|
|
4247
|
+
const offset = legendTop(input, legend, width);
|
|
4105
4248
|
// Along: the axis stages are stacked on; across: the axis a stage's width is measured on.
|
|
4106
4249
|
const along = horizontal ? width : height - offset;
|
|
4107
4250
|
const across = horizontal ? height - offset : width;
|
|
@@ -4115,7 +4258,6 @@ function layoutFunnelChart(input) {
|
|
|
4115
4258
|
const percentFormat = input.percentFormat
|
|
4116
4259
|
? makeFormatter(input.percentFormat)
|
|
4117
4260
|
: (p) => `${Math.round(p * 100)}%`;
|
|
4118
|
-
const legend = data.map((d, i) => ({ name: d.name, color: colorOf(input, i, d.color) }));
|
|
4119
4261
|
const mid = (horizontal ? offset + (height - offset) / 2 : width / 2) - (outside ? across / 6 : 0);
|
|
4120
4262
|
const stages = data.flatMap((d, i) => {
|
|
4121
4263
|
const near = widthOf(d.value);
|
|
@@ -4124,8 +4266,9 @@ function layoutFunnelChart(input) {
|
|
|
4124
4266
|
const p1 = p0 + stageLen - gap;
|
|
4125
4267
|
const percent = pyramid ? (total > 0 ? d.value / total : 0) : first > 0 ? d.value / first : 0;
|
|
4126
4268
|
const previous = data[i - 1]?.value;
|
|
4269
|
+
const change = previous !== undefined && previous > 0 ? d.value / previous - 1 : 0;
|
|
4127
4270
|
const drop = !pyramid && previous !== undefined && previous > 0
|
|
4128
|
-
? ` ·
|
|
4271
|
+
? ` · ${change < 0 ? '−' : change > 0 ? '+' : ''}${percentFormat(Math.abs(change))} from ${data[i - 1]?.name}`
|
|
4129
4272
|
: '';
|
|
4130
4273
|
const title = `${d.name}: ${format(d.value)} (${percentFormat(percent)})${drop}`;
|
|
4131
4274
|
const d0 = horizontal
|
|
@@ -4148,7 +4291,7 @@ function layoutFunnelChart(input) {
|
|
|
4148
4291
|
const at = mid + full / 2 + PAD$2;
|
|
4149
4292
|
return [
|
|
4150
4293
|
stage,
|
|
4151
|
-
|
|
4294
|
+
boundedLabel(px(horizontal ? center : at), px(horizontal ? at : center), text, width, {
|
|
4152
4295
|
part: 'stage-label',
|
|
4153
4296
|
anchor: horizontal ? 'middle' : 'start',
|
|
4154
4297
|
baseline: horizontal ? 'hanging' : 'middle',
|
|
@@ -4156,14 +4299,27 @@ function layoutFunnelChart(input) {
|
|
|
4156
4299
|
}),
|
|
4157
4300
|
];
|
|
4158
4301
|
}
|
|
4302
|
+
const caption = boundedLabel(px(horizontal ? center : mid), px(horizontal ? mid : center), text, width, {
|
|
4303
|
+
part: 'stage-label',
|
|
4304
|
+
anchor: 'middle',
|
|
4305
|
+
baseline: 'middle',
|
|
4306
|
+
fill: 'var(--skdx-color-text-default)',
|
|
4307
|
+
});
|
|
4159
4308
|
return [
|
|
4160
4309
|
stage,
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4310
|
+
// A stage can be narrower than its label, and arbitrary series colors
|
|
4311
|
+
// cannot guarantee contrast. Keep the bounded label on a token surface.
|
|
4312
|
+
{
|
|
4313
|
+
kind: 'rect',
|
|
4314
|
+
part: 'stage-label-background',
|
|
4315
|
+
x: px(caption.x - (caption.text.length * CHAR + 8) / 2),
|
|
4316
|
+
y: px((horizontal ? mid : center) - 9),
|
|
4317
|
+
width: caption.text.length * CHAR + 8,
|
|
4318
|
+
height: 18,
|
|
4319
|
+
rx: 8,
|
|
4320
|
+
fill: 'var(--skdx-color-surface-default)',
|
|
4321
|
+
},
|
|
4322
|
+
caption,
|
|
4167
4323
|
];
|
|
4168
4324
|
});
|
|
4169
4325
|
const c = canvas(input, width, height, legend);
|
|
@@ -4187,7 +4343,8 @@ function layoutRadialBar(input) {
|
|
|
4187
4343
|
return state;
|
|
4188
4344
|
const format = makeFormatter(input.format);
|
|
4189
4345
|
const { width, height } = size(input, 300, 300);
|
|
4190
|
-
const
|
|
4346
|
+
const legend = data.map((d, i) => ({ name: d.name, color: colorOf(input, i, d.color) }));
|
|
4347
|
+
const top = legendTop(input, legend, width);
|
|
4191
4348
|
const cx = width / 2;
|
|
4192
4349
|
const cy = top + (height - top) / 2;
|
|
4193
4350
|
const outer = Math.max(0, Math.min(width, height - top) / 2 - (input.bands ? 20 : 8));
|
|
@@ -4202,7 +4359,6 @@ function layoutRadialBar(input) {
|
|
|
4202
4359
|
const rounded = input.rounded ?? true;
|
|
4203
4360
|
const ratio = (v) => (max > 0 ? Math.max(0, Math.min(1, v / max)) : 0);
|
|
4204
4361
|
const shapes = [];
|
|
4205
|
-
const legend = data.map((d, i) => ({ name: d.name, color: colorOf(input, i, d.color) }));
|
|
4206
4362
|
// Threshold sectors outside the arcs, e.g. poor / fair / good.
|
|
4207
4363
|
for (const b of input.bands ?? []) {
|
|
4208
4364
|
const a0 = start + ratio(b.from) * sweep;
|
|
@@ -4847,13 +5003,14 @@ function layoutNetworkChart(input) {
|
|
|
4847
5003
|
const { width, height } = size(input);
|
|
4848
5004
|
const [rMin, rMax] = input.nodeRange ?? [5, 16];
|
|
4849
5005
|
const labels = input.labels ?? nodes.length <= NETWORK_LABEL_LIMIT;
|
|
5006
|
+
const groups = [...new Set(input.nodes.map(groupOf).filter((g) => g !== undefined))];
|
|
5007
|
+
const legend = groups.map((g, i) => ({ name: g, color: colorOf(input, i) }));
|
|
4850
5008
|
const plot = plotBox(width, height, {
|
|
4851
|
-
top: legendTop(input) + rMax + 8,
|
|
5009
|
+
top: legendTop(input, legend, width) + rMax + 8,
|
|
4852
5010
|
right: rMax + (labels ? 48 : 8),
|
|
4853
5011
|
bottom: rMax + 8,
|
|
4854
5012
|
left: rMax + 8,
|
|
4855
5013
|
});
|
|
4856
|
-
const groups = [...new Set(input.nodes.map(groupOf).filter((g) => g !== undefined))];
|
|
4857
5014
|
const colorFor = (n, i) => n.color ?? colorOf(input, n.group !== undefined ? groups.indexOf(n.group) : i);
|
|
4858
5015
|
const [, vMax] = minMax(nodes.map((n) => n.value));
|
|
4859
5016
|
const radius = (v) => isFinite(v) && vMax > 0 ? rMin + Math.sqrt(Math.max(0, v) / vMax) * (rMax - rMin) : rMin;
|
|
@@ -5028,7 +5185,6 @@ function layoutNetworkChart(input) {
|
|
|
5028
5185
|
fill: dim(p.node.id) === undefined ? 'var(--skdx-color-text-default)' : CHART_COLORS.grid,
|
|
5029
5186
|
}));
|
|
5030
5187
|
}
|
|
5031
|
-
const legend = groups.map((g, i) => ({ name: g, color: colorOf(input, i) }));
|
|
5032
5188
|
const c = canvas(input, width, height, legend);
|
|
5033
5189
|
return {
|
|
5034
5190
|
...c,
|
|
@@ -5163,7 +5319,7 @@ function layoutTimelineChart(input) {
|
|
|
5163
5319
|
// A list: the date column, a spine, one marker and label per row.
|
|
5164
5320
|
const dateW = Math.max(...events.map((e) => dateOf(e.time).length)) * CHAR + 16;
|
|
5165
5321
|
const plot = plotBox(width, height, {
|
|
5166
|
-
top: 8 + legendTop(input),
|
|
5322
|
+
top: 8 + legendTop(input, legend, width),
|
|
5167
5323
|
right: 8,
|
|
5168
5324
|
bottom: 8,
|
|
5169
5325
|
left: dateW + 12,
|
|
@@ -5217,7 +5373,7 @@ function layoutTimelineChart(input) {
|
|
|
5217
5373
|
// Half a date label at each end, so the first and last ticks stay inside the canvas.
|
|
5218
5374
|
const dateW = (Math.max(dateOf(t0).length, dateOf(t1).length) * CHAR) / 2 + 4;
|
|
5219
5375
|
const plot = plotBox(width, height, {
|
|
5220
|
-
top: 8 + legendTop(input),
|
|
5376
|
+
top: 8 + legendTop(input, legend, width),
|
|
5221
5377
|
right: Math.max(16, dateW),
|
|
5222
5378
|
bottom: 32 + (input.xAxis?.label ? 14 : 0),
|
|
5223
5379
|
left: Math.max(16, laneW, dateW),
|
|
@@ -5311,6 +5467,26 @@ function layoutTimelineChart(input) {
|
|
|
5311
5467
|
return { ...c, shapes: [...shapes, ...texts, ...marks, ...c.shapes], issues };
|
|
5312
5468
|
}
|
|
5313
5469
|
|
|
5470
|
+
/*
|
|
5471
|
+
* Copyright (c) 2026 SkandaDX
|
|
5472
|
+
* This file is part of the SkandaDX organization.
|
|
5473
|
+
* Licensed under the MIT License. See LICENSE in the repository root.
|
|
5474
|
+
*/
|
|
5475
|
+
/** Shared input/surface rounding; consumer tokens can customize it without changing data geometry. */
|
|
5476
|
+
const CHART_SURFACE_RADIUS = 'var(--skdx-radius-default, var(--skdx-radius-md, 0.5rem))';
|
|
5477
|
+
/** Only rectangular UI surfaces follow control rounding. Data marks retain their geometry/options. */
|
|
5478
|
+
function chartSurfaceRadius(part) {
|
|
5479
|
+
return [
|
|
5480
|
+
'tooltip',
|
|
5481
|
+
'skeleton',
|
|
5482
|
+
'label-background',
|
|
5483
|
+
'stage-label-background',
|
|
5484
|
+
'brush-handle',
|
|
5485
|
+
].includes(part)
|
|
5486
|
+
? CHART_SURFACE_RADIUS
|
|
5487
|
+
: undefined;
|
|
5488
|
+
}
|
|
5489
|
+
|
|
5314
5490
|
/*
|
|
5315
5491
|
* Copyright (c) 2026 SkandaDX
|
|
5316
5492
|
* This file is part of the SkandaDX organization.
|
|
@@ -5873,7 +6049,7 @@ function shapeMarkup(s) {
|
|
|
5873
6049
|
case 'circle':
|
|
5874
6050
|
return `<circle${attrs([part, ['cx', s.cx], ['cy', s.cy], ['r', s.r], ['fill', s.fill], ['stroke', s.stroke]])}>${title}</circle>`;
|
|
5875
6051
|
case 'text':
|
|
5876
|
-
return `<text${attrs([part, ['x', s.x], ['y', s.y], ['text-anchor', s.anchor], ['dominant-baseline', s.baseline], ['fill', s.fill], ['font-weight', s.weight], ['transform', s.rotate ? `rotate(${s.rotate} ${s.x} ${s.y})` : undefined]])}>${esc(s.text)}</text>`;
|
|
6052
|
+
return `<text${attrs([part, ['aria-label', s.title], ['x', s.x], ['y', s.y], ['text-anchor', s.anchor], ['dominant-baseline', s.baseline], ['fill', s.fill], ['font-weight', s.weight], ['transform', s.rotate ? `rotate(${s.rotate} ${s.x} ${s.y})` : undefined]])}>${esc(s.text)}</text>`;
|
|
5877
6053
|
}
|
|
5878
6054
|
}
|
|
5879
6055
|
/** The `<defs>` block for a layout's gradients, or an empty string. */
|
|
@@ -6425,13 +6601,13 @@ function layoutTreemap(input) {
|
|
|
6425
6601
|
const formatValue = makeFormatter(input.format);
|
|
6426
6602
|
const { width, height } = size(input);
|
|
6427
6603
|
const crumbs = input.breadcrumbs && path.length > 0;
|
|
6428
|
-
const
|
|
6604
|
+
const legend = nodes.map((n, i) => ({ name: n.name, color: colorOf(input, i, n.color) }));
|
|
6605
|
+
const top = legendTop(input, legend, width) + (crumbs ? 20 : 0);
|
|
6429
6606
|
const pad = Math.max(0, input.padding ?? 2);
|
|
6430
6607
|
const sort = input.sort ?? 'desc';
|
|
6431
6608
|
const tiling = input.tiling ?? 'squarify';
|
|
6432
6609
|
const showLabels = input.labels ?? true;
|
|
6433
6610
|
const shapes = [];
|
|
6434
|
-
const legend = nodes.map((n, i) => ({ name: n.name, color: colorOf(input, i, n.color) }));
|
|
6435
6611
|
// Leaves are colored by value when a scale is given; branches keep the branch color.
|
|
6436
6612
|
const leaves = [];
|
|
6437
6613
|
const collect = (list) => {
|
|
@@ -6479,11 +6655,14 @@ function layoutTreemap(input) {
|
|
|
6479
6655
|
});
|
|
6480
6656
|
if (branch)
|
|
6481
6657
|
tile(t.node.children, tx + pad, ty + pad, Math.max(0, tw - 2 * pad), Math.max(0, th - 2 * pad), t.color, depth + 1);
|
|
6482
|
-
else if (showLabels && tw > 40 && th > 20)
|
|
6483
|
-
|
|
6658
|
+
else if (showLabels && tw > 40 && th > 20) {
|
|
6659
|
+
const capacity = Math.max(1, Math.floor((tw - 12) / CHAR));
|
|
6660
|
+
const text = t.node.name.length > capacity ? `${t.node.name.slice(0, capacity - 1)}…` : t.node.name;
|
|
6661
|
+
shapes.push(label(px(tx + 6), px(ty + 6), text, {
|
|
6484
6662
|
baseline: 'hanging',
|
|
6485
6663
|
fill: 'var(--skdx-color-text-on-accent)',
|
|
6486
6664
|
}));
|
|
6665
|
+
}
|
|
6487
6666
|
};
|
|
6488
6667
|
if (tiling === 'squarify')
|
|
6489
6668
|
squarify(tiles, x, y, w, h, place);
|
|
@@ -6492,9 +6671,9 @@ function layoutTreemap(input) {
|
|
|
6492
6671
|
};
|
|
6493
6672
|
tile(nodes, 0, top, width, height - top, undefined, 0);
|
|
6494
6673
|
if (crumbs)
|
|
6495
|
-
shapes.push(...breadcrumbShapes(path, 8, legendTop(input) + 10));
|
|
6674
|
+
shapes.push(...breadcrumbShapes(path, 8, legendTop(input, legend, width) + 10));
|
|
6496
6675
|
const c = canvas(input, width, height, legend);
|
|
6497
|
-
return { ...c, shapes: [...shapes, ...c.shapes] };
|
|
6676
|
+
return { ...c, shapes: withLabelSurfaces([...shapes, ...c.shapes]) };
|
|
6498
6677
|
}
|
|
6499
6678
|
/** The drill path as clickable crumbs (each carries the node's id) separated by `›`, from `x`. */
|
|
6500
6679
|
function breadcrumbShapes(path, x, y) {
|
|
@@ -6547,6 +6726,7 @@ function layoutCandlestick(input) {
|
|
|
6547
6726
|
const UP = input.upColor ?? CHART_COLORS.positive;
|
|
6548
6727
|
const DOWN = input.downColor ?? CHART_COLORS.negative;
|
|
6549
6728
|
const priceFormat = makeFormatter(input.format);
|
|
6729
|
+
const volumeFormat = makeFormatter(input.volumeFormat ?? { style: 'integer' });
|
|
6550
6730
|
const count = all.length;
|
|
6551
6731
|
const start = Math.max(0, Math.min(count - 2, Math.floor(input.zoom?.start ?? 0)));
|
|
6552
6732
|
const end = input.zoom ? Math.max(start + 2, Math.min(count, Math.ceil(input.zoom.end))) : count;
|
|
@@ -6585,17 +6765,22 @@ function layoutCandlestick(input) {
|
|
|
6585
6765
|
.filter((o) => !o.hidden)
|
|
6586
6766
|
.flatMap((o) => o.values.map((v) => (isFinite(v) ? cmp(v) : v))),
|
|
6587
6767
|
], false);
|
|
6768
|
+
const legend = [
|
|
6769
|
+
{ name: 'Up', color: UP },
|
|
6770
|
+
{ name: 'Down', color: DOWN },
|
|
6771
|
+
...overlays.map((o) => ({ name: o.name, color: o.color })),
|
|
6772
|
+
];
|
|
6588
6773
|
const outer = plotBox(width, height, {
|
|
6589
6774
|
...MARGIN$1,
|
|
6590
|
-
top: MARGIN$1.top + legendTop(input) + (selector.length ? SELECTOR_HEIGHT : 0),
|
|
6775
|
+
top: MARGIN$1.top + legendTop(input, legend, width) + (selector.length ? SELECTOR_HEIGHT : 0),
|
|
6591
6776
|
bottom: MARGIN$1.bottom + brushRoom,
|
|
6592
6777
|
left: input.scale === 'log'
|
|
6593
6778
|
? MARGIN$1.left
|
|
6594
|
-
: valueAxisRoom(prices, makeFormatter(pctFormat ?? input.format)),
|
|
6779
|
+
: valueAxisRoom(prices, makeFormatter(pctFormat ?? input.yAxis?.format ?? input.format)),
|
|
6595
6780
|
});
|
|
6596
6781
|
const volumeH = hasVolume ? outer.height * VOLUME_SHARE : 0;
|
|
6597
6782
|
const plot = { ...outer, height: Math.max(0, outer.height - volumeH - (hasVolume ? 8 : 0)) };
|
|
6598
|
-
const y = axis(prices, [plot.y + plot.height, plot.y], { scale: input.scale === 'log' ? 'log' : 'linear', format: pctFormat }, input.format);
|
|
6783
|
+
const y = axis(prices, [plot.y + plot.height, plot.y], { scale: input.scale === 'log' ? 'log' : 'linear', format: pctFormat ?? input.yAxis?.format }, input.format);
|
|
6599
6784
|
// A time axis places candles by their label's time, so missing sessions leave gaps; the bar
|
|
6600
6785
|
// width is 80% of the smallest gap. Otherwise every candle takes an equal slot.
|
|
6601
6786
|
const times = data.map((c) => categoryValue(c.label));
|
|
@@ -6623,11 +6808,6 @@ function layoutCandlestick(input) {
|
|
|
6623
6808
|
.map((t) => ({ pos: px(tx(t)), label: categoryLabel(t, tickFormat) }));
|
|
6624
6809
|
}
|
|
6625
6810
|
const labels = data.map((c) => categoryLabel(c.label, input.xAxis?.format));
|
|
6626
|
-
const legend = [
|
|
6627
|
-
{ name: 'Up', color: UP },
|
|
6628
|
-
{ name: 'Down', color: DOWN },
|
|
6629
|
-
...overlays.map((o) => ({ name: o.name, color: o.color })),
|
|
6630
|
-
];
|
|
6631
6811
|
const c0 = canvas(input, width, height, legend);
|
|
6632
6812
|
const frame = {
|
|
6633
6813
|
...c0,
|
|
@@ -6671,7 +6851,7 @@ function layoutCandlestick(input) {
|
|
|
6671
6851
|
const color = up ? UP : DOWN;
|
|
6672
6852
|
const cx = px(x.center(i));
|
|
6673
6853
|
const change = base !== undefined ? ` (${pct(cmp(c.close))})` : '';
|
|
6674
|
-
const title = `${labels[i]}: O ${priceFormat(c.open)} H ${priceFormat(c.high)} L ${priceFormat(c.low)} C ${priceFormat(c.close)}${change}${isFinite(c.volume) ? ` V ${
|
|
6854
|
+
const title = `${labels[i]}: O ${priceFormat(c.open)} H ${priceFormat(c.high)} L ${priceFormat(c.low)} C ${priceFormat(c.close)}${change}${isFinite(c.volume) ? ` V ${volumeFormat(c.volume)}` : ''}`;
|
|
6675
6855
|
const item = {
|
|
6676
6856
|
label: title,
|
|
6677
6857
|
id: c.id,
|
|
@@ -6685,7 +6865,7 @@ function layoutCandlestick(input) {
|
|
|
6685
6865
|
`High: ${priceFormat(c.high)}`,
|
|
6686
6866
|
`Low: ${priceFormat(c.low)}`,
|
|
6687
6867
|
`Close: ${priceFormat(c.close)}${change}`,
|
|
6688
|
-
...(isFinite(c.volume) ? [`Volume: ${
|
|
6868
|
+
...(isFinite(c.volume) ? [`Volume: ${volumeFormat(c.volume)}`] : []),
|
|
6689
6869
|
...overlays
|
|
6690
6870
|
.filter((o) => !o.hidden)
|
|
6691
6871
|
.map((o) => `${o.name}: ${isFinite(o.values[i]) ? priceFormat(o.values[i]) : '—'}`),
|
|
@@ -6764,7 +6944,7 @@ function layoutCandlestick(input) {
|
|
|
6764
6944
|
height: px(Math.max(h, 0)),
|
|
6765
6945
|
fill: c.close >= c.open ? UP : DOWN,
|
|
6766
6946
|
opacity: 0.4,
|
|
6767
|
-
title: `${labels[i]}: volume ${
|
|
6947
|
+
title: `${labels[i]}: volume ${volumeFormat(c.volume)}`,
|
|
6768
6948
|
});
|
|
6769
6949
|
});
|
|
6770
6950
|
}
|
|
@@ -6863,7 +7043,7 @@ function layoutCandlestick(input) {
|
|
|
6863
7043
|
width: 6,
|
|
6864
7044
|
height: box.height - 16,
|
|
6865
7045
|
fill: CHART_COLORS.axis,
|
|
6866
|
-
rx:
|
|
7046
|
+
rx: 8,
|
|
6867
7047
|
}, {
|
|
6868
7048
|
kind: 'rect',
|
|
6869
7049
|
part: 'brush-handle',
|
|
@@ -6872,7 +7052,7 @@ function layoutCandlestick(input) {
|
|
|
6872
7052
|
width: 6,
|
|
6873
7053
|
height: box.height - 16,
|
|
6874
7054
|
fill: CHART_COLORS.axis,
|
|
6875
|
-
rx:
|
|
7055
|
+
rx: 8,
|
|
6876
7056
|
});
|
|
6877
7057
|
hit.brush = { box, window };
|
|
6878
7058
|
}
|
|
@@ -6964,19 +7144,20 @@ function layoutWaterfall(input) {
|
|
|
6964
7144
|
flat: true,
|
|
6965
7145
|
});
|
|
6966
7146
|
const widest = horizontal ? Math.max(0, ...steps.map((s) => s.name.length)) * CHAR + 16 : 0;
|
|
7147
|
+
const legend = [
|
|
7148
|
+
{ name: 'Increase', color: up },
|
|
7149
|
+
{ name: 'Decrease', color: down },
|
|
7150
|
+
];
|
|
6967
7151
|
const plot = plotBox(width, height, {
|
|
6968
7152
|
...MARGIN$1,
|
|
6969
|
-
top: MARGIN$1.top + legendTop(input),
|
|
7153
|
+
top: MARGIN$1.top + legendTop(input, legend, width),
|
|
6970
7154
|
left: Math.max(MARGIN$1.left, widest),
|
|
6971
7155
|
right: input.labels && horizontal ? 56 : MARGIN$1.right,
|
|
6972
7156
|
});
|
|
6973
7157
|
const totals = steps.flatMap((s) => [s.from, s.to]);
|
|
6974
7158
|
const value = axis([Math.min(0, ...totals), Math.max(0, ...totals)], horizontal ? [plot.x, plot.x + plot.width] : [plot.y + plot.height, plot.y], {}, input.format);
|
|
6975
7159
|
const band = bandScale(steps.length, horizontal ? [plot.y, plot.y + plot.height] : [plot.x, plot.x + plot.width]);
|
|
6976
|
-
const c = canvas(input, width, height,
|
|
6977
|
-
{ name: 'Increase', color: up },
|
|
6978
|
-
{ name: 'Decrease', color: down },
|
|
6979
|
-
]);
|
|
7160
|
+
const c = canvas(input, width, height, legend);
|
|
6980
7161
|
const categoryTicks = steps.map((s, i) => ({ pos: px(band.center(i)), label: s.name }));
|
|
6981
7162
|
const shapes = frameShapes({
|
|
6982
7163
|
...c,
|
|
@@ -7188,8 +7369,9 @@ function layoutGantt(input) {
|
|
|
7188
7369
|
: '';
|
|
7189
7370
|
const widest = Math.max(0, ...rowNames.map((n) => n.length + rowSuffix(n).length)) * CHAR +
|
|
7190
7371
|
Math.max(0, ...rowNames.map((n) => (rowDepth.get(n) ?? 0) * 12));
|
|
7372
|
+
const legend = input.tasks.map((t, i) => ({ name: t.name, color: colorOf(input, i, t.color) }));
|
|
7191
7373
|
const plot = plotBox(width, height, {
|
|
7192
|
-
top: 8 + legendTop(input),
|
|
7374
|
+
top: 8 + legendTop(input, legend, width),
|
|
7193
7375
|
right: 16,
|
|
7194
7376
|
bottom: 32 + (input.xAxis?.label ? 14 : 0),
|
|
7195
7377
|
left: Math.min(width / 2, Math.max(64, widest + 16)),
|
|
@@ -7421,7 +7603,7 @@ function layoutGantt(input) {
|
|
|
7421
7603
|
});
|
|
7422
7604
|
}
|
|
7423
7605
|
shapes.push(...overlays, ...annotationShapes(input.annotations, scales));
|
|
7424
|
-
const c = canvas(input, width, height,
|
|
7606
|
+
const c = canvas(input, width, height, legend);
|
|
7425
7607
|
return {
|
|
7426
7608
|
...c,
|
|
7427
7609
|
shapes: [...shapes, ...c.shapes],
|
|
@@ -7586,9 +7768,10 @@ function layoutBoxplot(input) {
|
|
|
7586
7768
|
const horizontal = input.orientation === 'horizontal';
|
|
7587
7769
|
const groups = grouped ? categories : input.series.map((s) => s.name);
|
|
7588
7770
|
const widest = Math.max(0, ...groups.map((n) => n.length)) * CHAR;
|
|
7771
|
+
const legend = input.series.map((s, i) => ({ name: s.name, color: colorOf(input, i, s.color) }));
|
|
7589
7772
|
const plot = plotBox(width, height, {
|
|
7590
7773
|
...MARGIN$1,
|
|
7591
|
-
top: MARGIN$1.top + legendTop(input) + (input.yAxis?.label ? 12 : 0),
|
|
7774
|
+
top: MARGIN$1.top + legendTop(input, legend, width) + (input.yAxis?.label ? 12 : 0),
|
|
7592
7775
|
left: horizontal ? Math.max(MARGIN$1.left, widest + 16) : MARGIN$1.left,
|
|
7593
7776
|
bottom: MARGIN$1.bottom + (horizontal && input.yAxis?.label ? 14 : 0),
|
|
7594
7777
|
});
|
|
@@ -7606,7 +7789,7 @@ function layoutBoxplot(input) {
|
|
|
7606
7789
|
const slots = grouped ? [...new Set(shown.map((c) => c.si))] : [];
|
|
7607
7790
|
const slotW = grouped ? band.bandwidth / Math.max(1, slots.length) : band.bandwidth;
|
|
7608
7791
|
const center = (c) => grouped ? band.start(c.ci) + (slots.indexOf(c.si) + 0.5) * slotW : band.center(c.si);
|
|
7609
|
-
const c = canvas(input, width, height,
|
|
7792
|
+
const c = canvas(input, width, height, legend);
|
|
7610
7793
|
const categoryTicks = groups.map((g, i) => ({ pos: px(band.center(i)), label: g }));
|
|
7611
7794
|
const shapes = frameShapes({
|
|
7612
7795
|
...c,
|
|
@@ -7757,7 +7940,8 @@ function layoutSunburst(input) {
|
|
|
7757
7940
|
// Crumbs sit in the hole when there is one, else in a row above the rings.
|
|
7758
7941
|
const crumbs = input.breadcrumbs && path.length > 0;
|
|
7759
7942
|
const crumbsAbove = crumbs && inner === 0;
|
|
7760
|
-
const
|
|
7943
|
+
const legend = nodes.map((n, i) => ({ name: n.name, color: colorOf(input, i, n.color) }));
|
|
7944
|
+
const top = legendTop(input, legend, width) + (crumbsAbove ? 20 : 0);
|
|
7761
7945
|
const cx = width / 2;
|
|
7762
7946
|
const cy = top + (height - top) / 2;
|
|
7763
7947
|
const radius = Math.max(0, Math.min(width, height - top) / 2 - 8);
|
|
@@ -7837,11 +8021,11 @@ function layoutSunburst(input) {
|
|
|
7837
8021
|
if (crumbs) {
|
|
7838
8022
|
const w = path.reduce((s, n) => s + n.name.length * CHAR + 6, 0) + (path.length - 1) * (CHAR + 6);
|
|
7839
8023
|
texts.push(...(crumbsAbove
|
|
7840
|
-
? breadcrumbShapes(path, 8, legendTop(input) + 10)
|
|
8024
|
+
? breadcrumbShapes(path, 8, legendTop(input, legend, width) + 10)
|
|
7841
8025
|
: breadcrumbShapes(path, cx - w / 2, input.centerLabel ? cy + 8 : cy)));
|
|
7842
8026
|
}
|
|
7843
|
-
const c = canvas(input, width, height,
|
|
7844
|
-
return { ...c, shapes: [...shapes, ...texts, ...c.shapes] };
|
|
8027
|
+
const c = canvas(input, width, height, legend);
|
|
8028
|
+
return { ...c, shapes: withLabelSurfaces([...shapes, ...texts, ...c.shapes]) };
|
|
7845
8029
|
}
|
|
7846
8030
|
|
|
7847
8031
|
/*
|
|
@@ -7905,16 +8089,6 @@ function layoutChord(input) {
|
|
|
7905
8089
|
return { ...state, issues };
|
|
7906
8090
|
const formatValue = makeFormatter(input.format);
|
|
7907
8091
|
const { width, height } = size(input, 300, 300);
|
|
7908
|
-
const top = legendTop(input);
|
|
7909
|
-
const cx = width / 2;
|
|
7910
|
-
const cy = top + (height - top) / 2;
|
|
7911
|
-
// Group names sit outside the rim, so the circle keeps room for the widest one on either side;
|
|
7912
|
-
// without it the left-hand label runs off the svg.
|
|
7913
|
-
const nameGap = input.ticks ? 8 + TICK + 14 : 8;
|
|
7914
|
-
const nameRoom = nameGap + Math.max(0, ...given.map((s) => s.length)) * CHAR + 4;
|
|
7915
|
-
const r = Math.max(0, Math.min(width / 2 - nameRoom, (height - top) / 2 - 36));
|
|
7916
|
-
const r0 = Math.max(0, r - RING);
|
|
7917
|
-
const PAD = ((input.padding ?? 2.3) * Math.PI) / 180;
|
|
7918
8092
|
// Groups keep their input order (and color) but can be arranged by total flow.
|
|
7919
8093
|
const cellRaw = (i, j) => {
|
|
7920
8094
|
const v = given2[i]?.[j];
|
|
@@ -7926,6 +8100,17 @@ function layoutChord(input) {
|
|
|
7926
8100
|
order.sort((a, b) => input.sort === 'asc' ? totalOf(a) - totalOf(b) : totalOf(b) - totalOf(a));
|
|
7927
8101
|
const names = order.map((i) => given[i]);
|
|
7928
8102
|
const colorAt = (k) => colorOf(input, order[k]);
|
|
8103
|
+
const legend = names.map((name, i) => ({ name, color: colorAt(i) }));
|
|
8104
|
+
const top = legendTop(input, legend, width);
|
|
8105
|
+
const cx = width / 2;
|
|
8106
|
+
const cy = top + (height - top) / 2;
|
|
8107
|
+
// Group names sit outside the rim, so the circle keeps room for the widest one on either side;
|
|
8108
|
+
// without it the left-hand label runs off the svg.
|
|
8109
|
+
const nameGap = input.ticks ? 8 + TICK + 14 : 8;
|
|
8110
|
+
const nameRoom = nameGap + Math.max(0, ...given.map((s) => s.length)) * CHAR + 4;
|
|
8111
|
+
const r = Math.max(0, Math.min(width / 2 - nameRoom, (height - top) / 2 - 36));
|
|
8112
|
+
const r0 = Math.max(0, r - RING);
|
|
8113
|
+
const PAD = ((input.padding ?? 2.3) * Math.PI) / 180;
|
|
7929
8114
|
const n = names.length;
|
|
7930
8115
|
const selectedId = selectedIds(input.selected)[0];
|
|
7931
8116
|
const selected = selectedId === undefined ? -1 : names.indexOf(String(selectedId));
|
|
@@ -8043,7 +8228,7 @@ function layoutChord(input) {
|
|
|
8043
8228
|
}));
|
|
8044
8229
|
});
|
|
8045
8230
|
});
|
|
8046
|
-
const c = canvas(input, width, height,
|
|
8231
|
+
const c = canvas(input, width, height, legend);
|
|
8047
8232
|
return { ...c, shapes: [...shapes, ...c.shapes], issues };
|
|
8048
8233
|
}
|
|
8049
8234
|
|
|
@@ -8294,16 +8479,17 @@ function layoutMarimekkoChart(input) {
|
|
|
8294
8479
|
const format = makeFormatter(input.format);
|
|
8295
8480
|
const totalFormat = makeFormatter(input.xAxis?.format ?? input.format);
|
|
8296
8481
|
const { width, height } = size(input);
|
|
8482
|
+
const legend = segments.map((s) => ({ name: s.name, color: s.color }));
|
|
8297
8483
|
const plot = plotBox(width, height, {
|
|
8298
8484
|
...MARGIN$1,
|
|
8299
|
-
top: MARGIN$1.top + legendTop(input),
|
|
8485
|
+
top: MARGIN$1.top + legendTop(input, legend, width),
|
|
8300
8486
|
bottom: MARGIN$1.bottom + (input.xAxis?.label ? 14 : 0) + (input.xAxis?.format ? 14 : 0),
|
|
8301
8487
|
});
|
|
8302
8488
|
const gap = Math.max(0, Math.min(0.2, input.gap ?? 0.01)) * plot.width;
|
|
8303
8489
|
const gaps = Math.max(0, columns.length - 1);
|
|
8304
8490
|
const usable = Math.max(0, plot.width - gap * gaps);
|
|
8305
8491
|
const y = axis([0, 1], [plot.y + plot.height, plot.y], { format: { style: 'percent' } });
|
|
8306
|
-
const c = canvas(input, width, height,
|
|
8492
|
+
const c = canvas(input, width, height, legend);
|
|
8307
8493
|
// Column positions along x, each as wide as its share of the grand total.
|
|
8308
8494
|
let x = plot.x;
|
|
8309
8495
|
const placed = columns.map((col) => {
|
|
@@ -8365,7 +8551,7 @@ function layoutMarimekkoChart(input) {
|
|
|
8365
8551
|
}));
|
|
8366
8552
|
});
|
|
8367
8553
|
}
|
|
8368
|
-
return { ...c, shapes: [...shapes, ...cells, ...texts, ...c.shapes], issues };
|
|
8554
|
+
return { ...c, shapes: withLabelSurfaces([...shapes, ...cells, ...texts, ...c.shapes]), issues };
|
|
8369
8555
|
}
|
|
8370
8556
|
|
|
8371
8557
|
/*
|
|
@@ -8393,8 +8579,9 @@ function layoutParallelCoordinates(input) {
|
|
|
8393
8579
|
const first = dims[0];
|
|
8394
8580
|
const last = dims[dims.length - 1];
|
|
8395
8581
|
const pad = (d) => ((d.label ?? d.key).length * CHAR) / 2 + 8;
|
|
8582
|
+
const legend = groups.map((g, i) => ({ name: g, color: colorOf(input, i) }));
|
|
8396
8583
|
const plot = plotBox(width, height, {
|
|
8397
|
-
top: 28 + legendTop(input),
|
|
8584
|
+
top: 28 + legendTop(input, legend, width),
|
|
8398
8585
|
right: Math.max(16, pad(last)),
|
|
8399
8586
|
bottom: 16,
|
|
8400
8587
|
left: Math.max(48, pad(first)),
|
|
@@ -8497,7 +8684,7 @@ function layoutParallelCoordinates(input) {
|
|
|
8497
8684
|
: undefined,
|
|
8498
8685
|
};
|
|
8499
8686
|
});
|
|
8500
|
-
const c = canvas(input, width, height,
|
|
8687
|
+
const c = canvas(input, width, height, legend);
|
|
8501
8688
|
return { ...c, shapes: [...shapes, ...lines, ...c.shapes], issues };
|
|
8502
8689
|
}
|
|
8503
8690
|
|
|
@@ -8588,21 +8775,22 @@ function layoutDumbbellChart(input) {
|
|
|
8588
8775
|
sorted.sort((a, b) => (input.sort === 'asc' ? key(a) - key(b) : key(b) - key(a)));
|
|
8589
8776
|
}
|
|
8590
8777
|
const widest = Math.max(0, ...sorted.map((d) => d.name.length)) * CHAR;
|
|
8778
|
+
const startColor = colorOf(input, 0);
|
|
8779
|
+
const endColor = colorOf(input, 1);
|
|
8780
|
+
const legend = [
|
|
8781
|
+
{ name: startLabel, color: startColor },
|
|
8782
|
+
{ name: endLabel, color: endColor },
|
|
8783
|
+
];
|
|
8591
8784
|
const plot = plotBox(width, height, {
|
|
8592
8785
|
...MARGIN$1,
|
|
8593
|
-
top: MARGIN$1.top + legendTop(input) + (vertical && input.xAxis?.label ? 12 : 0),
|
|
8786
|
+
top: MARGIN$1.top + legendTop(input, legend, width) + (vertical && input.xAxis?.label ? 12 : 0),
|
|
8594
8787
|
right: input.labels && !vertical ? 56 : MARGIN$1.right,
|
|
8595
8788
|
bottom: MARGIN$1.bottom + (!vertical && input.xAxis?.label ? 14 : 0),
|
|
8596
8789
|
left: vertical ? MARGIN$1.left : Math.max(MARGIN$1.left, widest + 16),
|
|
8597
8790
|
});
|
|
8598
8791
|
const value = axis(extent(sorted.flatMap((d) => [hideStart ? undefined : d.start, hideEnd ? undefined : d.end]), false), vertical ? [plot.y + plot.height, plot.y] : [plot.x, plot.x + plot.width], input.xAxis ?? {}, input.format);
|
|
8599
8792
|
const band = bandScale(sorted.length, vertical ? [plot.x, plot.x + plot.width] : [plot.y, plot.y + plot.height]);
|
|
8600
|
-
const
|
|
8601
|
-
const endColor = colorOf(input, 1);
|
|
8602
|
-
const c = canvas(input, width, height, [
|
|
8603
|
-
{ name: startLabel, color: startColor },
|
|
8604
|
-
{ name: endLabel, color: endColor },
|
|
8605
|
-
]);
|
|
8793
|
+
const c = canvas(input, width, height, legend);
|
|
8606
8794
|
const categoryTicks = sorted.map((d, i) => ({ pos: px(band.center(i)), label: d.name }));
|
|
8607
8795
|
const shapes = frameShapes({
|
|
8608
8796
|
...c,
|
|
@@ -8943,7 +9131,10 @@ function layoutTreeChart(input) {
|
|
|
8943
9131
|
]
|
|
8944
9132
|
: [];
|
|
8945
9133
|
const c = canvas(input, width, height);
|
|
8946
|
-
return {
|
|
9134
|
+
return {
|
|
9135
|
+
...c,
|
|
9136
|
+
shapes: withLabelSurfaces([...links, ...marks, ...texts, ...crumbs, ...c.shapes]),
|
|
9137
|
+
};
|
|
8947
9138
|
}
|
|
8948
9139
|
/** An organization chart: the tree with boxes and elbow links. */
|
|
8949
9140
|
const layoutOrganizationChart = (input) => layoutTreeChart({ ...input, nodeShape: 'box', linkStyle: 'elbow' });
|
|
@@ -9018,7 +9209,11 @@ function layoutCirclePacking(input) {
|
|
|
9018
9209
|
return { ...state, issues };
|
|
9019
9210
|
const format = makeFormatter(input.format);
|
|
9020
9211
|
const { width, height } = size(input, 300, 300);
|
|
9021
|
-
const
|
|
9212
|
+
const legend = branches.map((n) => ({
|
|
9213
|
+
name: n.name,
|
|
9214
|
+
color: branchColor.get(nodeId(n)),
|
|
9215
|
+
}));
|
|
9216
|
+
const top = legendTop(input, legend, width);
|
|
9022
9217
|
const pad = input.padding ?? 2;
|
|
9023
9218
|
const labels = input.labels ?? true;
|
|
9024
9219
|
const leafValues = [];
|
|
@@ -9095,8 +9290,8 @@ function layoutCirclePacking(input) {
|
|
|
9095
9290
|
};
|
|
9096
9291
|
const radius = Math.max(0, Math.min(width, height - top) / 2 - 8);
|
|
9097
9292
|
pack(nodes, width / 2, top + (height - top) / 2, radius, undefined);
|
|
9098
|
-
const c = canvas(input, width, height,
|
|
9099
|
-
return { ...c, shapes: [...shapes, ...texts, ...c.shapes], issues };
|
|
9293
|
+
const c = canvas(input, width, height, legend);
|
|
9294
|
+
return { ...c, shapes: withLabelSurfaces([...shapes, ...texts, ...c.shapes]), issues };
|
|
9100
9295
|
}
|
|
9101
9296
|
|
|
9102
9297
|
/*
|
|
@@ -9119,7 +9314,8 @@ function layoutIcicle(input) {
|
|
|
9119
9314
|
const { width, height } = size(input);
|
|
9120
9315
|
const horizontal = input.orientation === 'horizontal';
|
|
9121
9316
|
const crumbs = input.breadcrumbs && path.length > 0;
|
|
9122
|
-
const
|
|
9317
|
+
const legend = nodes.map((n, i) => ({ name: n.name, color: colorOf(input, i, n.color) }));
|
|
9318
|
+
const top = legendTop(input, legend, width) + (crumbs ? 20 : 0);
|
|
9123
9319
|
const plot = plotBox(width, height, { top, right: 0, bottom: 0, left: 0 });
|
|
9124
9320
|
const gap = input.padding ?? 1;
|
|
9125
9321
|
const labels = input.labels ?? true;
|
|
@@ -9187,9 +9383,9 @@ function layoutIcicle(input) {
|
|
|
9187
9383
|
};
|
|
9188
9384
|
walk(nodes, 0, horizontal ? plot.y : plot.x, horizontal ? plot.height : plot.width, undefined);
|
|
9189
9385
|
if (crumbs)
|
|
9190
|
-
shapes.push(...breadcrumbShapes(path, 8, legendTop(input) + 10));
|
|
9191
|
-
const c = canvas(input, width, height,
|
|
9192
|
-
return { ...c, shapes: [...shapes, ...texts, ...c.shapes], issues };
|
|
9386
|
+
shapes.push(...breadcrumbShapes(path, 8, legendTop(input, legend, width) + 10));
|
|
9387
|
+
const c = canvas(input, width, height, legend);
|
|
9388
|
+
return { ...c, shapes: withLabelSurfaces([...shapes, ...texts, ...c.shapes]), issues };
|
|
9193
9389
|
}
|
|
9194
9390
|
|
|
9195
9391
|
/*
|
|
@@ -9247,16 +9443,17 @@ function layoutBumpChart(input) {
|
|
|
9247
9443
|
});
|
|
9248
9444
|
const showLabels = input.labels ?? true;
|
|
9249
9445
|
const widest = showLabels ? Math.max(0, ...drawn.map((s) => s.name.length)) * CHAR + 12 : 0;
|
|
9446
|
+
const legend = input.series.map((s, i) => ({ name: s.name, color: colorOf(input, i, s.color) }));
|
|
9250
9447
|
const plot = plotBox(width, height, {
|
|
9251
9448
|
...MARGIN$1,
|
|
9252
|
-
top: MARGIN$1.top + legendTop(input),
|
|
9449
|
+
top: MARGIN$1.top + legendTop(input, legend, width),
|
|
9253
9450
|
right: Math.max(MARGIN$1.right, widest),
|
|
9254
9451
|
bottom: MARGIN$1.bottom + (input.xAxis?.label ? 14 : 0),
|
|
9255
9452
|
});
|
|
9256
9453
|
// Rank 1 sits at the top: the axis runs down from half a rank above 1 to half a rank below `top`.
|
|
9257
9454
|
const y = linearScale([0.5, top + 0.5], [plot.y, plot.y + plot.height]);
|
|
9258
9455
|
const band = bandScale(count, [plot.x, plot.x + plot.width], 0);
|
|
9259
|
-
const c = canvas(input, width, height,
|
|
9456
|
+
const c = canvas(input, width, height, legend);
|
|
9260
9457
|
const rankTicks = Array.from({ length: top }, (_, k) => ({
|
|
9261
9458
|
pos: px(y(k + 1)),
|
|
9262
9459
|
label: `#${k + 1}`,
|
|
@@ -9364,7 +9561,8 @@ function layoutPolarAreaChart(input) {
|
|
|
9364
9561
|
return { ...state, issues };
|
|
9365
9562
|
const format = makeFormatter(input.format);
|
|
9366
9563
|
const { width, height } = size(input, 300, 300);
|
|
9367
|
-
const
|
|
9564
|
+
const legend = input.data.map((d, i) => ({ name: d.name, color: colorOf(input, i, d.color) }));
|
|
9565
|
+
const top = legendTop(input, legend, width);
|
|
9368
9566
|
const cx = width / 2;
|
|
9369
9567
|
const cy = top + (height - top) / 2;
|
|
9370
9568
|
const outer = Math.max(0, Math.min(width, height - top) / 2 - (input.labels ? 40 : 12));
|
|
@@ -9426,7 +9624,7 @@ function layoutPolarAreaChart(input) {
|
|
|
9426
9624
|
}));
|
|
9427
9625
|
}
|
|
9428
9626
|
});
|
|
9429
|
-
const c = canvas(input, width, height,
|
|
9627
|
+
const c = canvas(input, width, height, legend);
|
|
9430
9628
|
return { ...c, shapes: [...grid, ...sectors, ...texts, ...c.shapes], issues };
|
|
9431
9629
|
}
|
|
9432
9630
|
|
|
@@ -9489,15 +9687,16 @@ function layoutSwarmPlot(input) {
|
|
|
9489
9687
|
const { width, height } = size(input);
|
|
9490
9688
|
const horizontal = input.orientation === 'horizontal';
|
|
9491
9689
|
const widest = Math.max(0, ...input.series.map((s) => s.name.length)) * CHAR;
|
|
9690
|
+
const legend = input.series.map((s, i) => ({ name: s.name, color: colorOf(input, i, s.color) }));
|
|
9492
9691
|
const plot = plotBox(width, height, {
|
|
9493
9692
|
...MARGIN$1,
|
|
9494
|
-
top: MARGIN$1.top + legendTop(input) + (!horizontal && input.yAxis?.label ? 12 : 0),
|
|
9693
|
+
top: MARGIN$1.top + legendTop(input, legend, width) + (!horizontal && input.yAxis?.label ? 12 : 0),
|
|
9495
9694
|
left: horizontal ? Math.max(MARGIN$1.left, widest + 16) : MARGIN$1.left,
|
|
9496
9695
|
bottom: MARGIN$1.bottom + (horizontal && input.yAxis?.label ? 14 : 0),
|
|
9497
9696
|
});
|
|
9498
9697
|
const value = axis(extent(samples.flat(), false), horizontal ? [plot.x, plot.x + plot.width] : [plot.y + plot.height, plot.y], input.yAxis ?? {}, input.format);
|
|
9499
9698
|
const band = bandScale(input.series.length, horizontal ? [plot.y, plot.y + plot.height] : [plot.x, plot.x + plot.width]);
|
|
9500
|
-
const c = canvas(input, width, height,
|
|
9699
|
+
const c = canvas(input, width, height, legend);
|
|
9501
9700
|
const categoryTicks = input.series.map((s, i) => ({ pos: px(band.center(i)), label: s.name }));
|
|
9502
9701
|
const shapes = frameShapes({
|
|
9503
9702
|
...c,
|
|
@@ -9636,7 +9835,7 @@ function layoutWaffleChart(input) {
|
|
|
9636
9835
|
const corner = (k) => horizontal
|
|
9637
9836
|
? { x: x0 + (k % columns) * cell, y: y0 + Math.floor(k / columns) * cell }
|
|
9638
9837
|
: { x: x0 + Math.floor(k / rows) * cell, y: y0 + (rows - 1 - (k % rows)) * cell };
|
|
9639
|
-
const rect = (k, fill, title, item, opacity) => {
|
|
9838
|
+
const rect = (k, fill, title, item, opacity, stroke) => {
|
|
9640
9839
|
const { x, y } = corner(k);
|
|
9641
9840
|
return {
|
|
9642
9841
|
kind: 'rect',
|
|
@@ -9646,6 +9845,7 @@ function layoutWaffleChart(input) {
|
|
|
9646
9845
|
width: px(Math.max(0.5, cell - gap)),
|
|
9647
9846
|
height: px(Math.max(0.5, cell - gap)),
|
|
9648
9847
|
fill,
|
|
9848
|
+
stroke,
|
|
9649
9849
|
opacity,
|
|
9650
9850
|
rx: input.cellRadius ?? 2,
|
|
9651
9851
|
title,
|
|
@@ -9663,8 +9863,9 @@ function layoutWaffleChart(input) {
|
|
|
9663
9863
|
});
|
|
9664
9864
|
const rest = total - sum;
|
|
9665
9865
|
const restTitle = rest > 0 ? `Other: ${format(rest)} (${Math.round(share(rest) * 100)}%)` : 'Empty';
|
|
9866
|
+
// A subtle fill alone is the same luminance as a dark stage; the outline carries the contrast.
|
|
9666
9867
|
for (; k < cells; k++)
|
|
9667
|
-
shapes.push(rect(k, CHART_COLORS.grid, restTitle, undefined, 0.6));
|
|
9868
|
+
shapes.push(rect(k, CHART_COLORS.grid, restTitle, undefined, 0.6, CHART_COLORS.axis));
|
|
9668
9869
|
const c = canvas(legendInput, width, height, legendItems);
|
|
9669
9870
|
return { ...c, shapes: [...shapes, ...c.shapes], issues };
|
|
9670
9871
|
}
|
|
@@ -9683,6 +9884,7 @@ function layoutWaffleChart(input) {
|
|
|
9683
9884
|
/** Draws a core shape list back to front; marks with an `item` carry their index for hit-testing. */
|
|
9684
9885
|
class SkdxChartShapesComponent {
|
|
9685
9886
|
constructor() {
|
|
9887
|
+
this.surfaceRadius = chartSurfaceRadius;
|
|
9686
9888
|
this.shapes = input.required(/* @ts-ignore */
|
|
9687
9889
|
...(ngDevMode ? [{ debugName: "shapes" }] : /* istanbul ignore next */ []));
|
|
9688
9890
|
}
|
|
@@ -9718,9 +9920,13 @@ class SkdxChartShapesComponent {
|
|
|
9718
9920
|
[attr.width]="s.width"
|
|
9719
9921
|
[attr.height]="s.height"
|
|
9720
9922
|
[attr.rx]="s.rx"
|
|
9923
|
+
[style.rx]="surfaceRadius(s.part)"
|
|
9721
9924
|
[attr.fill]="s.fill"
|
|
9722
9925
|
[attr.stroke]="s.stroke"
|
|
9723
9926
|
[attr.fill-opacity]="s.opacity"
|
|
9927
|
+
[attr.pointer-events]="
|
|
9928
|
+
s.part === 'stage-label-background' || s.part === 'label-background' ? 'none' : null
|
|
9929
|
+
"
|
|
9724
9930
|
>
|
|
9725
9931
|
@if (s.title) {
|
|
9726
9932
|
<svg:title>{{ s.title }}</svg:title>
|
|
@@ -9763,6 +9969,7 @@ class SkdxChartShapesComponent {
|
|
|
9763
9969
|
}
|
|
9764
9970
|
@case ('text') {
|
|
9765
9971
|
<svg:text
|
|
9972
|
+
[attr.aria-label]="s.title"
|
|
9766
9973
|
[attr.data-skdx-part]="s.part"
|
|
9767
9974
|
[attr.data-skdx-i]="s.item ? $index : null"
|
|
9768
9975
|
[attr.x]="s.x"
|
|
@@ -9817,9 +10024,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
9817
10024
|
[attr.width]="s.width"
|
|
9818
10025
|
[attr.height]="s.height"
|
|
9819
10026
|
[attr.rx]="s.rx"
|
|
10027
|
+
[style.rx]="surfaceRadius(s.part)"
|
|
9820
10028
|
[attr.fill]="s.fill"
|
|
9821
10029
|
[attr.stroke]="s.stroke"
|
|
9822
10030
|
[attr.fill-opacity]="s.opacity"
|
|
10031
|
+
[attr.pointer-events]="
|
|
10032
|
+
s.part === 'stage-label-background' || s.part === 'label-background' ? 'none' : null
|
|
10033
|
+
"
|
|
9823
10034
|
>
|
|
9824
10035
|
@if (s.title) {
|
|
9825
10036
|
<svg:title>{{ s.title }}</svg:title>
|
|
@@ -9862,6 +10073,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
9862
10073
|
}
|
|
9863
10074
|
@case ('text') {
|
|
9864
10075
|
<svg:text
|
|
10076
|
+
[attr.aria-label]="s.title"
|
|
9865
10077
|
[attr.data-skdx-part]="s.part"
|
|
9866
10078
|
[attr.data-skdx-i]="s.item ? $index : null"
|
|
9867
10079
|
[attr.x]="s.x"
|
|
@@ -9957,12 +10169,16 @@ class SkdxChartRootComponent {
|
|
|
9957
10169
|
...(ngDevMode ? [{ debugName: "svg" }] : /* istanbul ignore next */ []));
|
|
9958
10170
|
this.hover = null;
|
|
9959
10171
|
this.token = {};
|
|
10172
|
+
this.dismissedCrosshair = signal(null, /* @ts-ignore */
|
|
10173
|
+
...(ngDevMode ? [{ debugName: "dismissedCrosshair" }] : /* istanbul ignore next */ []));
|
|
9960
10174
|
this.tip = signal([], /* @ts-ignore */
|
|
9961
10175
|
...(ngDevMode ? [{ debugName: "tip" }] : /* istanbul ignore next */ []));
|
|
9962
10176
|
this.tipShapes = computed(() => {
|
|
9963
10177
|
const own = this.tip();
|
|
9964
10178
|
const cross = this.crosshair();
|
|
9965
|
-
return own.length || !cross
|
|
10179
|
+
return own.length || !cross || cross === this.dismissedCrosshair()
|
|
10180
|
+
? own
|
|
10181
|
+
: crosshairAt(this.layout(), cross);
|
|
9966
10182
|
}, /* @ts-ignore */
|
|
9967
10183
|
...(ngDevMode ? [{ debugName: "tipShapes" }] : /* istanbul ignore next */ []));
|
|
9968
10184
|
this.lastCross = null;
|
|
@@ -9987,8 +10203,6 @@ class SkdxChartRootComponent {
|
|
|
9987
10203
|
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
9988
10204
|
this.focusable = computed(() => !this.layout().decorative && focusTargets(this.layout()).length > 0, /* @ts-ignore */
|
|
9989
10205
|
...(ngDevMode ? [{ debugName: "focusable" }] : /* istanbul ignore next */ []));
|
|
9990
|
-
this.descId = computed(() => this.layout().description ? `${this.kind()}-desc-${this.label().replace(/\W+/g, '-')}` : null, /* @ts-ignore */
|
|
9991
|
-
...(ngDevMode ? [{ debugName: "descId" }] : /* istanbul ignore next */ []));
|
|
9992
10206
|
this.focusShapes = computed(() => focusShapes(this.layout(), this.focused()), /* @ts-ignore */
|
|
9993
10207
|
...(ngDevMode ? [{ debugName: "focusShapes" }] : /* istanbul ignore next */ []));
|
|
9994
10208
|
this.drag = null;
|
|
@@ -10094,6 +10308,7 @@ class SkdxChartRootComponent {
|
|
|
10094
10308
|
this.shareCrosshair(null);
|
|
10095
10309
|
}
|
|
10096
10310
|
onPointerMove(e) {
|
|
10311
|
+
this.dismissedCrosshair.set(null);
|
|
10097
10312
|
const layout = this.layout();
|
|
10098
10313
|
if (this.pointers.has(e.pointerId))
|
|
10099
10314
|
this.pointers.set(e.pointerId, this.viewBox(e).x);
|
|
@@ -10308,6 +10523,14 @@ class SkdxChartRootComponent {
|
|
|
10308
10523
|
}
|
|
10309
10524
|
}
|
|
10310
10525
|
onKeyDown(e) {
|
|
10526
|
+
if (e.key === 'Escape') {
|
|
10527
|
+
e.preventDefault();
|
|
10528
|
+
this.focused.set(null);
|
|
10529
|
+
this.clearTip();
|
|
10530
|
+
this.dismissedCrosshair.set(this.crosshair());
|
|
10531
|
+
this.highlight(null);
|
|
10532
|
+
return;
|
|
10533
|
+
}
|
|
10311
10534
|
if (!this.focusable())
|
|
10312
10535
|
return;
|
|
10313
10536
|
const focused = this.focused();
|
|
@@ -10345,14 +10568,13 @@ class SkdxChartRootComponent {
|
|
|
10345
10568
|
[attr.role]="layout().decorative ? 'presentation' : 'img'"
|
|
10346
10569
|
[attr.aria-hidden]="layout().decorative ? 'true' : null"
|
|
10347
10570
|
[attr.aria-label]="layout().decorative ? null : label()"
|
|
10348
|
-
[attr.aria-
|
|
10571
|
+
[attr.aria-description]="layout().description"
|
|
10349
10572
|
[attr.tabindex]="focusable() ? 0 : null"
|
|
10350
10573
|
[attr.data-skdx-chart]="kind()"
|
|
10351
10574
|
[attr.font-family]="colors.fontFamily"
|
|
10352
10575
|
[attr.font-size]="colors.fontSize"
|
|
10353
10576
|
[style.max-width]="'100%'"
|
|
10354
10577
|
[style.height]="'auto'"
|
|
10355
|
-
[style.outline]="'none'"
|
|
10356
10578
|
[style.cursor]="canZoom() || canPan() ? 'grab' : brushing() ? 'crosshair' : null"
|
|
10357
10579
|
[style.touch-action]="active() ? 'none' : null"
|
|
10358
10580
|
[style.--skdx-chart-duration]="duration()"
|
|
@@ -10369,7 +10591,7 @@ class SkdxChartRootComponent {
|
|
|
10369
10591
|
>
|
|
10370
10592
|
<title>{{ label() }}</title>
|
|
10371
10593
|
@if (layout().description) {
|
|
10372
|
-
<svg:desc
|
|
10594
|
+
<svg:desc>{{ layout().description }}</svg:desc>
|
|
10373
10595
|
}
|
|
10374
10596
|
@if (layout().defs?.length) {
|
|
10375
10597
|
<svg:defs>
|
|
@@ -10415,7 +10637,7 @@ class SkdxChartRootComponent {
|
|
|
10415
10637
|
[attr.data-skdx-tooltip]="kind()"
|
|
10416
10638
|
[style.left.px]="p.x + 12"
|
|
10417
10639
|
[style.top.px]="p.y + 12"
|
|
10418
|
-
style="position:fixed;pointer-events:none;z-index:1000;background:var(--skdx-color-surface-raised);color:var(--skdx-color-text-default);border:1px solid var(--skdx-color-border-strong);border-radius:
|
|
10640
|
+
style="position:fixed;pointer-events:none;z-index:1000;background:var(--skdx-color-surface-raised);color:var(--skdx-color-text-default);border:1px solid var(--skdx-color-border-strong);border-radius:var(--skdx-radius-default, var(--skdx-radius-md, 0.5rem));padding:4px 8px;font-family:var(--skdx-font-family);font-size:var(--skdx-font-size-xs);white-space:nowrap"
|
|
10419
10641
|
>
|
|
10420
10642
|
@for (line of p.lines; track $index) {
|
|
10421
10643
|
<div [style.font-weight]="$index === 0 && p.lines.length > 1 ? 'bold' : null">
|
|
@@ -10476,14 +10698,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
10476
10698
|
[attr.role]="layout().decorative ? 'presentation' : 'img'"
|
|
10477
10699
|
[attr.aria-hidden]="layout().decorative ? 'true' : null"
|
|
10478
10700
|
[attr.aria-label]="layout().decorative ? null : label()"
|
|
10479
|
-
[attr.aria-
|
|
10701
|
+
[attr.aria-description]="layout().description"
|
|
10480
10702
|
[attr.tabindex]="focusable() ? 0 : null"
|
|
10481
10703
|
[attr.data-skdx-chart]="kind()"
|
|
10482
10704
|
[attr.font-family]="colors.fontFamily"
|
|
10483
10705
|
[attr.font-size]="colors.fontSize"
|
|
10484
10706
|
[style.max-width]="'100%'"
|
|
10485
10707
|
[style.height]="'auto'"
|
|
10486
|
-
[style.outline]="'none'"
|
|
10487
10708
|
[style.cursor]="canZoom() || canPan() ? 'grab' : brushing() ? 'crosshair' : null"
|
|
10488
10709
|
[style.touch-action]="active() ? 'none' : null"
|
|
10489
10710
|
[style.--skdx-chart-duration]="duration()"
|
|
@@ -10500,7 +10721,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
10500
10721
|
>
|
|
10501
10722
|
<title>{{ label() }}</title>
|
|
10502
10723
|
@if (layout().description) {
|
|
10503
|
-
<svg:desc
|
|
10724
|
+
<svg:desc>{{ layout().description }}</svg:desc>
|
|
10504
10725
|
}
|
|
10505
10726
|
@if (layout().defs?.length) {
|
|
10506
10727
|
<svg:defs>
|
|
@@ -10546,7 +10767,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
10546
10767
|
[attr.data-skdx-tooltip]="kind()"
|
|
10547
10768
|
[style.left.px]="p.x + 12"
|
|
10548
10769
|
[style.top.px]="p.y + 12"
|
|
10549
|
-
style="position:fixed;pointer-events:none;z-index:1000;background:var(--skdx-color-surface-raised);color:var(--skdx-color-text-default);border:1px solid var(--skdx-color-border-strong);border-radius:
|
|
10770
|
+
style="position:fixed;pointer-events:none;z-index:1000;background:var(--skdx-color-surface-raised);color:var(--skdx-color-text-default);border:1px solid var(--skdx-color-border-strong);border-radius:var(--skdx-radius-default, var(--skdx-radius-md, 0.5rem));padding:4px 8px;font-family:var(--skdx-font-family);font-size:var(--skdx-font-size-xs);white-space:nowrap"
|
|
10550
10771
|
>
|
|
10551
10772
|
@for (line of p.lines; track $index) {
|
|
10552
10773
|
<div [style.font-weight]="$index === 0 && p.lines.length > 1 ? 'bold' : null">
|
|
@@ -10771,10 +10992,19 @@ class SkdxSizedBase {
|
|
|
10771
10992
|
};
|
|
10772
10993
|
}
|
|
10773
10994
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: SkdxSizedBase, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
10774
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.1.4", type: SkdxSizedBase, isStandalone: true, inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, palette: { classPropertyName: "palette", publicName: "palette", isSignal: true, isRequired: false, transformFunction: null }, hiddenSeries: { classPropertyName: "hiddenSeries", publicName: "hiddenSeries", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, highlighted: { classPropertyName: "highlighted", publicName: "highlighted", isSignal: true, isRequired: false, transformFunction: null }, highlightScope: { classPropertyName: "highlightScope", publicName: "highlightScope", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, decorative: { classPropertyName: "decorative", publicName: "decorative", isSignal: true, isRequired: false, transformFunction: null }, accessibleTable: { classPropertyName: "accessibleTable", publicName: "accessibleTable", isSignal: true, isRequired: false, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, zoomable: { classPropertyName: "zoomable", publicName: "zoomable", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, syncId: { classPropertyName: "syncId", publicName: "syncId", isSignal: true, isRequired: false, transformFunction: null }, crossFilter: { classPropertyName: "crossFilter", publicName: "crossFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hiddenSeries: "hiddenSeriesChange", selected: "selectedChange", highlighted: "highlightedChange", zoom: "zoomChange", view: "viewChange", itemClick: "itemClick", dataIssue: "dataIssue", taskChange: "taskChange" }, viewQueries: [{ propertyName: "chartRoot", first: true, predicate: SkdxChartRootComponent, descendants: true, isSignal: true }], ngImport: i0 }); }
|
|
10995
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.1.4", type: SkdxSizedBase, isStandalone: true, inputs: { width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, legend: { classPropertyName: "legend", publicName: "legend", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, palette: { classPropertyName: "palette", publicName: "palette", isSignal: true, isRequired: false, transformFunction: null }, hiddenSeries: { classPropertyName: "hiddenSeries", publicName: "hiddenSeries", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, highlighted: { classPropertyName: "highlighted", publicName: "highlighted", isSignal: true, isRequired: false, transformFunction: null }, highlightScope: { classPropertyName: "highlightScope", publicName: "highlightScope", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, decorative: { classPropertyName: "decorative", publicName: "decorative", isSignal: true, isRequired: false, transformFunction: null }, accessibleTable: { classPropertyName: "accessibleTable", publicName: "accessibleTable", isSignal: true, isRequired: false, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, zoomable: { classPropertyName: "zoomable", publicName: "zoomable", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, syncId: { classPropertyName: "syncId", publicName: "syncId", isSignal: true, isRequired: false, transformFunction: null }, crossFilter: { classPropertyName: "crossFilter", publicName: "crossFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hiddenSeries: "hiddenSeriesChange", selected: "selectedChange", highlighted: "highlightedChange", zoom: "zoomChange", view: "viewChange", itemClick: "itemClick", dataIssue: "dataIssue", taskChange: "taskChange" }, host: { properties: { "style.display": "responsive() ? 'block' : null", "style.width": "responsive() ? '100%' : null", "style.min-width": "responsive() ? '0' : null" } }, viewQueries: [{ propertyName: "chartRoot", first: true, predicate: SkdxChartRootComponent, descendants: true, isSignal: true }], ngImport: i0 }); }
|
|
10775
10996
|
}
|
|
10776
10997
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: SkdxSizedBase, decorators: [{
|
|
10777
|
-
type: Directive
|
|
10998
|
+
type: Directive,
|
|
10999
|
+
args: [{
|
|
11000
|
+
// A responsive chart must fill its container even when that container centers flex items.
|
|
11001
|
+
// Otherwise its last SVG width becomes the host's intrinsic width and it cannot grow again.
|
|
11002
|
+
host: {
|
|
11003
|
+
'[style.display]': "responsive() ? 'block' : null",
|
|
11004
|
+
'[style.width]': "responsive() ? '100%' : null",
|
|
11005
|
+
'[style.min-width]': "responsive() ? '0' : null",
|
|
11006
|
+
},
|
|
11007
|
+
}]
|
|
10778
11008
|
}], propDecorators: { width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], legend: [{ type: i0.Input, args: [{ isSignal: true, alias: "legend", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], palette: [{ type: i0.Input, args: [{ isSignal: true, alias: "palette", required: false }] }], hiddenSeries: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenSeries", required: false }] }, { type: i0.Output, args: ["hiddenSeriesChange"] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], highlighted: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlighted", required: false }] }, { type: i0.Output, args: ["highlightedChange"] }], highlightScope: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightScope", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], decorative: [{ type: i0.Input, args: [{ isSignal: true, alias: "decorative", required: false }] }], accessibleTable: [{ type: i0.Input, args: [{ isSignal: true, alias: "accessibleTable", required: false }] }], animate: [{ type: i0.Input, args: [{ isSignal: true, alias: "animate", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }, { type: i0.Output, args: ["zoomChange"] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], zoomable: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoomable", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], syncId: [{ type: i0.Input, args: [{ isSignal: true, alias: "syncId", required: false }] }], crossFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "crossFilter", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], dataIssue: [{ type: i0.Output, args: ["dataIssue"] }], taskChange: [{ type: i0.Output, args: ["taskChange"] }], chartRoot: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SkdxChartRootComponent), { isSignal: true }] }] } });
|
|
10779
11009
|
/** Inputs the cartesian charts (bar, line, area) take. */
|
|
10780
11010
|
class SkdxChartBase extends SkdxSizedBase {
|
|
@@ -10899,5 +11129,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
10899
11129
|
* Generated bundle index. Do not edit.
|
|
10900
11130
|
*/
|
|
10901
11131
|
|
|
10902
|
-
export { ANIMATION_CSS, ANIMATION_LIMIT, CHART_COLORS, MARKER_LIMIT, NETWORK_LABEL_LIMIT, PARALLEL_TITLE_LIMIT, SAMPLING_THRESHOLD, SERIES_COLORS, SWARM_TITLE_LIMIT, SkdxChartBase, SkdxChartRootComponent, SkdxChartShapesComponent, SkdxSizedBase, TABLE_LIMIT, TITLE_LIMIT, aggregate, anchorOf, animationDuration, annotationShapes, applyTransforms, binCounts, binEdges, binSamples, boxFrom, brushBoxShape, brushDrag, brushGrab, categoryLabel, colorLegendShapes, crosshairAt, crosshairLine, crosshairRows, crosshairShapes, csv, cumulative, cutDepth, defsMarkup, depthOf, difference, drill, emphasize, exponentialMovingAverage, exportChart, filter, findPath, focusShapes, focusTargets, formatValue, ganttDrag, ganttGhost, ganttGrab, ganttKey, hoverTooltip, hoveredRef, insidePolygon, isSelected, isUnzoomed, itemAt, itemId, itemsInBox, itemsInPolygon, lassoShape, layoutAreaChart, layoutBarChart, layoutBoxplot, layoutBubbleChart, layoutBulletChart, layoutBumpChart, layoutCandlestick, layoutCartesian, layoutChord, layoutCirclePacking, layoutComboChart, layoutDumbbellChart, layoutFunnelChart, layoutGantt, layoutGaugeChart, layoutHeatmap, layoutHistogram, layoutIcicle, layoutLineChart, layoutLinearGauge, layoutMap, layoutMarimekkoChart, layoutNetworkChart, layoutOrganizationChart, layoutParallelCoordinates, layoutParetoChart, layoutPieChart, layoutPolarAreaChart, layoutRadarChart, layoutRadialBar, layoutRangeChart, layoutSankey, layoutScatterChart, layoutSparkline, layoutSunburst, layoutSwarmPlot, layoutTimelineChart, layoutTreeChart, layoutTreemap, layoutWaffleChart, layoutWaterfall, legendOptions, lttb, m4, makeColorScale, makeFormatter, mapPan, mapWheel, matchesItem, minMaxSample, mixStops, movingAverage, nextFocus, nodeId, nodeValue, normalize, packCircles, parseColor, percentageChange, placeLegend, pointerShapes, pointerTooltipText, rank, refOf, referenceShapes, sameRef, sampleIndexes, samplingOptions, selectedIds, seriesCsv, shapeMarkup, sortChildren, sortValues, stateCanvas, svgMarkup, svgToPng, swarmOffsets, syncGroup, tableRows, timeTicks, toRefs, toViewBox, toggleSelection, tooltipOptions, tooltipShapes, translatePath, translateShapes, variantColor, waffleCounts, zoomPan, zoomPinch, zoomWheel };
|
|
11132
|
+
export { ANIMATION_CSS, ANIMATION_LIMIT, CHART_COLORS, CHART_SURFACE_RADIUS, MARKER_LIMIT, NETWORK_LABEL_LIMIT, PARALLEL_TITLE_LIMIT, SAMPLING_THRESHOLD, SERIES_COLORS, SWARM_TITLE_LIMIT, SkdxChartBase, SkdxChartRootComponent, SkdxChartShapesComponent, SkdxSizedBase, TABLE_LIMIT, TITLE_LIMIT, aggregate, anchorOf, animationDuration, annotationShapes, applyTransforms, binCounts, binEdges, binSamples, boxFrom, brushBoxShape, brushDrag, brushGrab, categoryLabel, chartSurfaceRadius, colorLegendShapes, crosshairAt, crosshairLine, crosshairRows, crosshairShapes, csv, cumulative, cutDepth, defsMarkup, depthOf, difference, drill, emphasize, exponentialMovingAverage, exportChart, filter, findPath, focusShapes, focusTargets, formatValue, ganttDrag, ganttGhost, ganttGrab, ganttKey, hoverTooltip, hoveredRef, insidePolygon, isSelected, isUnzoomed, itemAt, itemId, itemsInBox, itemsInPolygon, lassoShape, layoutAreaChart, layoutBarChart, layoutBoxplot, layoutBubbleChart, layoutBulletChart, layoutBumpChart, layoutCandlestick, layoutCartesian, layoutChord, layoutCirclePacking, layoutComboChart, layoutDumbbellChart, layoutFunnelChart, layoutGantt, layoutGaugeChart, layoutHeatmap, layoutHistogram, layoutIcicle, layoutLineChart, layoutLinearGauge, layoutMap, layoutMarimekkoChart, layoutNetworkChart, layoutOrganizationChart, layoutParallelCoordinates, layoutParetoChart, layoutPieChart, layoutPolarAreaChart, layoutRadarChart, layoutRadialBar, layoutRangeChart, layoutSankey, layoutScatterChart, layoutSparkline, layoutSunburst, layoutSwarmPlot, layoutTimelineChart, layoutTreeChart, layoutTreemap, layoutWaffleChart, layoutWaterfall, legendOptions, lttb, m4, makeColorScale, makeFormatter, mapPan, mapWheel, matchesItem, minMaxSample, mixStops, movingAverage, nextFocus, nodeId, nodeValue, normalize, packCircles, parseColor, percentageChange, placeLegend, pointerShapes, pointerTooltipText, rank, refOf, referenceShapes, sameRef, sampleIndexes, samplingOptions, selectedIds, seriesCsv, shapeMarkup, sortChildren, sortValues, stateCanvas, svgMarkup, svgToPng, swarmOffsets, syncGroup, tableRows, timeTicks, toRefs, toViewBox, toggleSelection, tooltipOptions, tooltipShapes, translatePath, translateShapes, variantColor, waffleCounts, zoomPan, zoomPinch, zoomWheel };
|
|
10903
11133
|
//# sourceMappingURL=skdx-angular-charts-internal.mjs.map
|