@automattic/charts 4.11.0 → 4.12.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/CHANGELOG.md +18 -0
- package/dist/index.cjs +856 -236
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +19 -13
- package/dist/index.d.cts +43 -4
- package/dist/index.d.ts +43 -4
- package/dist/index.js +855 -237
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/charts/bar-chart/bar-chart.tsx +134 -138
- package/src/charts/bar-chart/index.ts +3 -0
- package/src/charts/bar-chart/private/band-tooltip.tsx +41 -15
- package/src/charts/bar-chart/private/bar-layer.tsx +132 -0
- package/src/charts/bar-chart/private/comparison-bars-geometry.ts +22 -34
- package/src/charts/bar-chart/private/comparison-bars.tsx +9 -18
- package/src/charts/bar-chart/private/comparison-constants.ts +4 -10
- package/src/charts/bar-chart/private/grouped-bars.ts +68 -0
- package/src/charts/bar-chart/private/index.ts +7 -1
- package/src/charts/bar-chart/private/overlap-bars.ts +183 -0
- package/src/charts/bar-chart/private/selected-bar-ring.tsx +84 -0
- package/src/charts/bar-chart/private/slot-tooltip-members.tsx +29 -0
- package/src/charts/bar-chart/private/slotted-bar-series.tsx +84 -0
- package/src/charts/bar-chart/private/test/comparison-bars-geometry.test.ts +4 -11
- package/src/charts/bar-chart/private/test/comparison-bars.test.tsx +2 -3
- package/src/charts/bar-chart/private/test/grouped-bars.test.ts +87 -0
- package/src/charts/bar-chart/private/test/overlap-bars.test.ts +159 -0
- package/src/charts/bar-chart/private/use-bar-stops.ts +89 -0
- package/src/charts/bar-chart/private/use-overlap-slots.ts +194 -0
- package/src/charts/bar-chart/private/value-domain.ts +0 -10
- package/src/charts/bar-chart/test/bar-chart-overlap.test.tsx +347 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +66 -19
- package/src/charts/bar-chart/test/use-bar-legend-items.test.tsx +81 -0
- package/src/charts/bar-chart/types.ts +3 -0
- package/src/charts/bar-chart/use-bar-colors.ts +46 -0
- package/src/charts/bar-chart/use-bar-legend-items.ts +87 -0
- package/src/charts/line-chart/line-chart.tsx +22 -17
- package/src/charts/line-chart/test/line-chart.test.tsx +165 -1
- package/src/charts/pie-chart/pie-chart.tsx +7 -2
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +7 -2
- package/src/charts/private/pie-keyboard-navigation/index.ts +0 -1
- package/src/charts/private/{pie-keyboard-navigation/pie-keyboard-navigation.module.scss → selected-ring/selected-ring.module.scss} +11 -6
- package/src/charts/private/selected-ring/selected-ring.tsx +73 -0
- package/src/charts/private/{pie-keyboard-navigation/test/selected-segment-ring.test.ts → selected-ring/test/selected-ring.test.ts} +1 -1
- package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +20 -0
- package/src/components/legend/hooks/use-chart-legend-items.ts +27 -3
- package/src/components/tooltip/xy-chart-tooltip.tsx +3 -2
- package/src/index.ts +8 -2
- package/src/providers/chart-context/global-charts-provider.tsx +2 -0
- package/src/providers/chart-context/test/chart-context.test.tsx +0 -13
- package/src/providers/chart-context/themes.ts +0 -1
- package/src/providers/chart-context/types.ts +2 -0
- package/src/test-utils/selected-bar-ring.ts +14 -0
- package/src/types.ts +10 -2
- package/src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx +0 -47
package/dist/index.js
CHANGED
|
@@ -1296,10 +1296,7 @@ const defaultTheme = {
|
|
|
1296
1296
|
strokeDasharray: "4 4",
|
|
1297
1297
|
strokeLinecap: "square"
|
|
1298
1298
|
} } },
|
|
1299
|
-
barChart: { barStyles: { comparison: {
|
|
1300
|
-
widthFactor: 1.5,
|
|
1301
|
-
opacity: .5
|
|
1302
|
-
} } },
|
|
1299
|
+
barChart: { barStyles: { comparison: { widthFactor: 1.5 } } },
|
|
1303
1300
|
sparkline: {
|
|
1304
1301
|
margin: {
|
|
1305
1302
|
top: 2,
|
|
@@ -1457,6 +1454,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
|
1457
1454
|
theme: providerTheme,
|
|
1458
1455
|
formatting,
|
|
1459
1456
|
getElementStyles,
|
|
1457
|
+
backgroundColor: colorCache.background,
|
|
1460
1458
|
toggleSeriesVisibility,
|
|
1461
1459
|
setSeriesVisibility,
|
|
1462
1460
|
setChartHiddenSeries,
|
|
@@ -1473,6 +1471,7 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
|
1473
1471
|
providerTheme,
|
|
1474
1472
|
formatting,
|
|
1475
1473
|
getElementStyles,
|
|
1474
|
+
colorCache.background,
|
|
1476
1475
|
toggleSeriesVisibility,
|
|
1477
1476
|
setSeriesVisibility,
|
|
1478
1477
|
setChartHiddenSeries,
|
|
@@ -2297,6 +2296,21 @@ const Legend = forwardRef(({ chartId, items, shape, ...props }, ref) => {
|
|
|
2297
2296
|
//#endregion
|
|
2298
2297
|
//#region src/components/legend/hooks/use-chart-legend-items.ts
|
|
2299
2298
|
/**
|
|
2299
|
+
* Wraps `getElementStyles` so a swatch takes the color given for its series.
|
|
2300
|
+
* @param getElementStyles - Function to get element styles
|
|
2301
|
+
* @param seriesColors - Each series' swatch color, by index
|
|
2302
|
+
* @return Element styles with the given color
|
|
2303
|
+
*/
|
|
2304
|
+
function withSeriesColors(getElementStyles, seriesColors) {
|
|
2305
|
+
return (params) => {
|
|
2306
|
+
const styles = getElementStyles(params);
|
|
2307
|
+
return {
|
|
2308
|
+
...styles,
|
|
2309
|
+
color: seriesColors[params.index] ?? styles.color
|
|
2310
|
+
};
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
/**
|
|
2300
2314
|
* Formats the value for a data point based on its type and display preference
|
|
2301
2315
|
* @param point - The data point to format
|
|
2302
2316
|
* @param showValues - Whether to show values or return empty string
|
|
@@ -2508,21 +2522,22 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
|
|
|
2508
2522
|
* @return Array of legend items ready for display
|
|
2509
2523
|
*/
|
|
2510
2524
|
function useChartLegendItems(data, options = {}, legendShape) {
|
|
2511
|
-
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, renderGlyph } = options;
|
|
2512
|
-
const { getElementStyles } = useGlobalChartsContext();
|
|
2525
|
+
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, seriesColors, renderGlyph } = options;
|
|
2526
|
+
const { getElementStyles: getSeriesStyles } = useGlobalChartsContext();
|
|
2513
2527
|
return useMemo(() => {
|
|
2514
2528
|
if (!data || !Array.isArray(data) || data.length === 0) return [];
|
|
2515
2529
|
if ("data" in data[0]) {
|
|
2516
2530
|
const seriesData = data;
|
|
2531
|
+
const getElementStyles = seriesColors ? withSeriesColors(getSeriesStyles, seriesColors) : getSeriesStyles;
|
|
2517
2532
|
const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
|
|
2518
2533
|
if (comparisonSeriesItems) return [...items, ...buildPerSeriesComparisonItems(seriesData, items, comparisonSeriesItems, getElementStyles, legendShape)];
|
|
2519
2534
|
const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : __("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
|
|
2520
2535
|
return comparison ? [...items, comparison] : items;
|
|
2521
2536
|
}
|
|
2522
|
-
return processPointData(data,
|
|
2537
|
+
return processPointData(data, getSeriesStyles, showValues, legendValueDisplay, withGlyph, glyphSize, renderGlyph, legendShape);
|
|
2523
2538
|
}, [
|
|
2524
2539
|
data,
|
|
2525
|
-
|
|
2540
|
+
getSeriesStyles,
|
|
2526
2541
|
showValues,
|
|
2527
2542
|
legendValueDisplay,
|
|
2528
2543
|
withGlyph,
|
|
@@ -2530,6 +2545,7 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2530
2545
|
collapseGroups,
|
|
2531
2546
|
comparisonItem,
|
|
2532
2547
|
comparisonSeriesItems,
|
|
2548
|
+
seriesColors,
|
|
2533
2549
|
renderGlyph,
|
|
2534
2550
|
legendShape
|
|
2535
2551
|
]);
|
|
@@ -3055,17 +3071,19 @@ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocu
|
|
|
3055
3071
|
return;
|
|
3056
3072
|
}
|
|
3057
3073
|
hasKeyboardSelection.current = true;
|
|
3058
|
-
if (mode === "group")
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
datum
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3074
|
+
if (mode === "group") {
|
|
3075
|
+
closeTooltipNow();
|
|
3076
|
+
series.forEach((s, index) => {
|
|
3077
|
+
if (selectedIndex < s.data.length) {
|
|
3078
|
+
const datum = s.data[selectedIndex];
|
|
3079
|
+
tooltipContext?.showTooltip({
|
|
3080
|
+
datum,
|
|
3081
|
+
key: s.label,
|
|
3082
|
+
index
|
|
3083
|
+
});
|
|
3084
|
+
}
|
|
3085
|
+
});
|
|
3086
|
+
} else if (mode === "individual") {
|
|
3069
3087
|
if (selectedIndex < tooltipData.length) {
|
|
3070
3088
|
const tooltipItem = tooltipData[selectedIndex];
|
|
3071
3089
|
tooltipContext?.showTooltip({
|
|
@@ -4812,6 +4830,8 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
|
|
|
4812
4830
|
isVisible: !hiddenSeries.has(series.label)
|
|
4813
4831
|
}));
|
|
4814
4832
|
}, [dataSorted, hiddenSeries]);
|
|
4833
|
+
const visibleSeries = useMemo(() => dataSorted.filter((series) => isSeriesVisible(series.label)), [dataSorted, isSeriesVisible]);
|
|
4834
|
+
const visibleSeriesKey = useMemo(() => JSON.stringify(visibleSeries.map((series) => series.label)), [visibleSeries]);
|
|
4815
4835
|
const allSeriesHidden = useMemo(() => {
|
|
4816
4836
|
return seriesWithVisibility.every(({ isVisible }) => !isVisible);
|
|
4817
4837
|
}, [seriesWithVisibility]);
|
|
@@ -4842,21 +4862,21 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
|
|
|
4842
4862
|
options?.yScale
|
|
4843
4863
|
]);
|
|
4844
4864
|
const activateSelectedPoint = useCallback((index) => {
|
|
4845
|
-
const series =
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
datum,
|
|
4865
|
+
const series = visibleSeries.find((candidate) => candidate.data[index]);
|
|
4866
|
+
if (series) onDatumActivate?.({
|
|
4867
|
+
datum: series.data[index],
|
|
4849
4868
|
index,
|
|
4850
4869
|
key: series.label
|
|
4851
4870
|
});
|
|
4852
|
-
}, [
|
|
4871
|
+
}, [visibleSeries, onDatumActivate]);
|
|
4853
4872
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
4854
4873
|
selectedIndex,
|
|
4855
4874
|
setSelectedIndex,
|
|
4856
4875
|
isNavigating,
|
|
4857
4876
|
setIsNavigating,
|
|
4858
4877
|
chartRef,
|
|
4859
|
-
totalPoints:
|
|
4878
|
+
totalPoints: Math.max(0, ...visibleSeries.map((series) => series.data.length)),
|
|
4879
|
+
visibleSeriesKey,
|
|
4860
4880
|
onActivate: activateSelectedPoint,
|
|
4861
4881
|
preventTooltipScroll: tooltipPlacement === "below-axis"
|
|
4862
4882
|
});
|
|
@@ -4875,7 +4895,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
|
|
|
4875
4895
|
}
|
|
4876
4896
|
return min <= max ? [min, max] : void 0;
|
|
4877
4897
|
}, [dataSorted, isSeriesVisible]);
|
|
4878
|
-
const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(
|
|
4898
|
+
const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(visibleSeries), [visibleSeries]);
|
|
4879
4899
|
const chartOptions = useMemo(() => {
|
|
4880
4900
|
const fallbackYDomain = getFallbackYDomain(visibleReadingExtent, options?.yScale?.type === "log");
|
|
4881
4901
|
return {
|
|
@@ -4921,11 +4941,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
|
|
|
4921
4941
|
formatting,
|
|
4922
4942
|
isSeriesVisible
|
|
4923
4943
|
]);
|
|
4924
|
-
const bucketInfo = useMemo(() => getBucketInfo(
|
|
4925
|
-
dataSorted,
|
|
4926
|
-
isSeriesVisible,
|
|
4927
|
-
options?.axis?.x?.tickResolution
|
|
4928
|
-
]);
|
|
4944
|
+
const bucketInfo = useMemo(() => getBucketInfo(visibleSeries, options?.axis?.x?.tickResolution), [visibleSeries, options?.axis?.x?.tickResolution]);
|
|
4929
4945
|
const tooltipRenderGlyph = useMemo(() => {
|
|
4930
4946
|
return (props) => {
|
|
4931
4947
|
const seriesIndex = dataSorted.findIndex((series) => series.label === props.key || series.data.includes(props.datum));
|
|
@@ -5155,7 +5171,7 @@ const LineChartInternal = forwardRef(({ data, ariaLabel, chartId: providedChartI
|
|
|
5155
5171
|
selectedIndex,
|
|
5156
5172
|
tooltipRef,
|
|
5157
5173
|
keyboardFocusedClassName: line_chart_module_default["line-chart__tooltip--keyboard-focused"],
|
|
5158
|
-
series:
|
|
5174
|
+
series: visibleSeries
|
|
5159
5175
|
}),
|
|
5160
5176
|
/* @__PURE__ */ jsx(LineChartScalesRef, {
|
|
5161
5177
|
chartRef: internalChartRef,
|
|
@@ -5815,13 +5831,6 @@ const getBarValue = (point) => {
|
|
|
5815
5831
|
*/
|
|
5816
5832
|
const isBarRendered = (point) => Number.isFinite(getBarValue(point));
|
|
5817
5833
|
/**
|
|
5818
|
-
* How many bars visx renders for a list of points.
|
|
5819
|
-
*
|
|
5820
|
-
* @param points - Data points handed to visx.
|
|
5821
|
-
* @return The number of points that get a bar.
|
|
5822
|
-
*/
|
|
5823
|
-
const countRenderedBars = (points) => points.filter(isBarRendered).length;
|
|
5824
|
-
/**
|
|
5825
5834
|
* An explicit domain for the value scale, or null to let visx fit one to the data.
|
|
5826
5835
|
*
|
|
5827
5836
|
* Zero goes into the domain here rather than through the scale's `zero` flag: visx applies
|
|
@@ -6083,8 +6092,7 @@ const createGroupScale = (keys, bandwidth, padding) => scaleBand({
|
|
|
6083
6092
|
//#endregion
|
|
6084
6093
|
//#region src/charts/bar-chart/private/comparison-bars-geometry.ts
|
|
6085
6094
|
/**
|
|
6086
|
-
* Mirrors visx's getScaleBaseline so
|
|
6087
|
-
* share the same baseline, including out-of-domain zero values.
|
|
6095
|
+
* Mirrors visx's getScaleBaseline so bars drawn outside visx share the baseline of its bars, including out-of-domain zero values.
|
|
6088
6096
|
*
|
|
6089
6097
|
* @param {ValueScale} scale - The continuous value scale.
|
|
6090
6098
|
* @return {number} The baseline output position in pixels.
|
|
@@ -6098,36 +6106,33 @@ function getValueScaleBaseline(scale) {
|
|
|
6098
6106
|
return Number.isFinite(maybeZero) ? Math.max(maybeZero, minOutput) : minOutput;
|
|
6099
6107
|
}
|
|
6100
6108
|
/**
|
|
6101
|
-
* Compute the rect
|
|
6102
|
-
*
|
|
6103
|
-
*
|
|
6104
|
-
* @param {
|
|
6105
|
-
* @param {
|
|
6106
|
-
* @param {number}
|
|
6107
|
-
* @param {number}
|
|
6108
|
-
* @param {number}
|
|
6109
|
-
* @param {number}
|
|
6110
|
-
* @
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
const
|
|
6116
|
-
const
|
|
6117
|
-
const
|
|
6118
|
-
const shadowStart = slotStart + slotThickness / 2 - shadowThickness / 2;
|
|
6119
|
-
const valueStart = Math.min(valuePosition, baseline);
|
|
6120
|
-
const valueLength = Math.abs(baseline - valuePosition);
|
|
6109
|
+
* Compute the rect that spans `valuePositions` along the value axis, centered on a slot and scaled by `widthFactor` across it.
|
|
6110
|
+
*
|
|
6111
|
+
* @param {object} params - Geometry inputs.
|
|
6112
|
+
* @param {boolean} params.horizontal - True for a horizontal bar chart, false for vertical.
|
|
6113
|
+
* @param {number} params.bandPosition - bandScale(category): start px of the category band.
|
|
6114
|
+
* @param {number} params.slotOffset - groupScale(slotKey): offset of the slot within the band.
|
|
6115
|
+
* @param {number} params.slotThickness - groupScale.bandwidth(): slot thickness in px.
|
|
6116
|
+
* @param {number[]} params.valuePositions - Output px the rect must reach, such as the baseline and each bar's value.
|
|
6117
|
+
* @param {number} params.widthFactor - Thickness multiplier, e.g. 0.5 for half the slot.
|
|
6118
|
+
* @return {SlotRect} The {x, y, width, height} of the rect.
|
|
6119
|
+
*/
|
|
6120
|
+
function computeSlotRect(params) {
|
|
6121
|
+
const { horizontal, bandPosition, slotOffset, slotThickness, valuePositions, widthFactor } = params;
|
|
6122
|
+
const thickness = slotThickness * widthFactor;
|
|
6123
|
+
const start = bandPosition + slotOffset + slotThickness / 2 - thickness / 2;
|
|
6124
|
+
const valueStart = Math.min(...valuePositions);
|
|
6125
|
+
const valueLength = Math.max(...valuePositions) - valueStart;
|
|
6121
6126
|
if (horizontal) return {
|
|
6122
6127
|
x: valueStart,
|
|
6123
|
-
y:
|
|
6128
|
+
y: start,
|
|
6124
6129
|
width: valueLength,
|
|
6125
|
-
height:
|
|
6130
|
+
height: thickness
|
|
6126
6131
|
};
|
|
6127
6132
|
return {
|
|
6128
|
-
x:
|
|
6133
|
+
x: start,
|
|
6129
6134
|
y: valueStart,
|
|
6130
|
-
width:
|
|
6135
|
+
width: thickness,
|
|
6131
6136
|
height: valueLength
|
|
6132
6137
|
};
|
|
6133
6138
|
}
|
|
@@ -6176,6 +6181,518 @@ const ClassifiedBarSeries = ({ barClassName, primaryKeys, groupPadding, ...props
|
|
|
6176
6181
|
renderGlyph
|
|
6177
6182
|
});
|
|
6178
6183
|
};
|
|
6184
|
+
//#endregion
|
|
6185
|
+
//#region src/charts/bar-chart/private/slotted-bar-series.tsx
|
|
6186
|
+
const SlottedBarSeries = ({ barClassName, slotKeys, slotKey, thickness, groupPadding, ...props }) => {
|
|
6187
|
+
const { xScale, yScale, horizontal } = useContext(DataContext);
|
|
6188
|
+
const bandScale = horizontal ? yScale : xScale;
|
|
6189
|
+
const valueScale = horizontal ? xScale : yScale;
|
|
6190
|
+
const groupScale = useMemo(() => createGroupScale(slotKeys, bandScale?.bandwidth?.() ?? 0, groupPadding), [
|
|
6191
|
+
slotKeys,
|
|
6192
|
+
bandScale,
|
|
6193
|
+
groupPadding
|
|
6194
|
+
]);
|
|
6195
|
+
const renderGlyph = useCallback(({ datum, x, y, color }) => {
|
|
6196
|
+
if (!bandScale?.bandwidth || !valueScale) return null;
|
|
6197
|
+
const baseline = getValueScaleBaseline(valueScale);
|
|
6198
|
+
const rect = computeSlotRect({
|
|
6199
|
+
horizontal: !!horizontal,
|
|
6200
|
+
bandPosition: Number(bandScale((horizontal ? props.yAccessor : props.xAccessor)(datum))),
|
|
6201
|
+
slotOffset: groupScale(slotKey) ?? 0,
|
|
6202
|
+
slotThickness: groupScale.bandwidth(),
|
|
6203
|
+
valuePositions: [baseline, horizontal ? x : y],
|
|
6204
|
+
widthFactor: thickness
|
|
6205
|
+
});
|
|
6206
|
+
return /* @__PURE__ */ jsx("rect", {
|
|
6207
|
+
...rect,
|
|
6208
|
+
className: clsx("visx-bar", barClassName?.(datum)),
|
|
6209
|
+
fill: color
|
|
6210
|
+
});
|
|
6211
|
+
}, [
|
|
6212
|
+
bandScale,
|
|
6213
|
+
valueScale,
|
|
6214
|
+
horizontal,
|
|
6215
|
+
groupScale,
|
|
6216
|
+
slotKey,
|
|
6217
|
+
thickness,
|
|
6218
|
+
props.xAccessor,
|
|
6219
|
+
props.yAccessor,
|
|
6220
|
+
barClassName
|
|
6221
|
+
]);
|
|
6222
|
+
return /* @__PURE__ */ jsx(GlyphSeries, {
|
|
6223
|
+
...props,
|
|
6224
|
+
enableEvents: false,
|
|
6225
|
+
renderGlyph
|
|
6226
|
+
});
|
|
6227
|
+
};
|
|
6228
|
+
//#endregion
|
|
6229
|
+
//#region src/charts/private/selected-ring/selected-ring.module.scss
|
|
6230
|
+
var selected_ring_module_default = {
|
|
6231
|
+
"selected-ring__contrast": "a8ccharts-gx1_AW-selected-ring__contrast",
|
|
6232
|
+
"selected-ring__edge": "a8ccharts-gx1_AW-selected-ring__edge",
|
|
6233
|
+
"selected-ring__far": "a8ccharts-gx1_AW-selected-ring__far",
|
|
6234
|
+
"selected-ring__focus": "a8ccharts-gx1_AW-selected-ring__focus"
|
|
6235
|
+
};
|
|
6236
|
+
//#endregion
|
|
6237
|
+
//#region src/charts/private/selected-ring/selected-ring.tsx
|
|
6238
|
+
const TONES = {
|
|
6239
|
+
inside: ["contrast", "focus"],
|
|
6240
|
+
outside: ["focus", "contrast"]
|
|
6241
|
+
};
|
|
6242
|
+
const EVERYWHERE = "M-1e6 -1e6H1e6V1e6H-1e6Z";
|
|
6243
|
+
/**
|
|
6244
|
+
* Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
|
|
6245
|
+
*
|
|
6246
|
+
* @param value - Any string.
|
|
6247
|
+
* @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
|
|
6248
|
+
*/
|
|
6249
|
+
const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
|
|
6250
|
+
/**
|
|
6251
|
+
* Marks a selected shape with a focus-colored ring and a contrast ring, so it reads against any fill.
|
|
6252
|
+
*
|
|
6253
|
+
* @param {SelectedRingProps} props - Component props
|
|
6254
|
+
* @return {JSX.Element} The ring
|
|
6255
|
+
*/
|
|
6256
|
+
const SelectedRing = ({ chartId, d, side, testId }) => {
|
|
6257
|
+
const clipId = `selected-ring-clip-${toSvgId(chartId)}`;
|
|
6258
|
+
const clipPath = `url(#${clipId})`;
|
|
6259
|
+
const [far, edge] = TONES[side];
|
|
6260
|
+
return /* @__PURE__ */ jsxs("g", {
|
|
6261
|
+
pointerEvents: "none",
|
|
6262
|
+
"aria-hidden": "true",
|
|
6263
|
+
children: [
|
|
6264
|
+
/* @__PURE__ */ jsx("clipPath", {
|
|
6265
|
+
id: clipId,
|
|
6266
|
+
children: side === "inside" ? /* @__PURE__ */ jsx("path", { d }) : /* @__PURE__ */ jsx("path", {
|
|
6267
|
+
d: `${EVERYWHERE} ${d}`,
|
|
6268
|
+
clipRule: "evenodd"
|
|
6269
|
+
})
|
|
6270
|
+
}),
|
|
6271
|
+
/* @__PURE__ */ jsx("path", {
|
|
6272
|
+
d,
|
|
6273
|
+
clipPath,
|
|
6274
|
+
className: clsx(selected_ring_module_default["selected-ring__far"], selected_ring_module_default[`selected-ring__${far}`])
|
|
6275
|
+
}),
|
|
6276
|
+
/* @__PURE__ */ jsx("path", {
|
|
6277
|
+
d,
|
|
6278
|
+
clipPath,
|
|
6279
|
+
className: clsx(selected_ring_module_default["selected-ring__edge"], selected_ring_module_default[`selected-ring__${edge}`])
|
|
6280
|
+
})
|
|
6281
|
+
]
|
|
6282
|
+
});
|
|
6283
|
+
};
|
|
6284
|
+
//#endregion
|
|
6285
|
+
//#region src/charts/bar-chart/private/selected-bar-ring.tsx
|
|
6286
|
+
/**
|
|
6287
|
+
* Marks the keyboard-selected slot with a two-tone ring outside its edge, so the ring reads against any bar color.
|
|
6288
|
+
*
|
|
6289
|
+
* @param props - Component props.
|
|
6290
|
+
* @param props.chartId - The chart's id, which keeps the clip path unique on a page with several charts.
|
|
6291
|
+
* @param props.selected - The selected slot.
|
|
6292
|
+
* @param props.slotKeys - The slots, in the order the band lays them out.
|
|
6293
|
+
* @param props.groupPadding - The padding between slots.
|
|
6294
|
+
* @param props.horizontal - Whether the bars run horizontally.
|
|
6295
|
+
* @param props.xAccessor - Reads a datum's x value.
|
|
6296
|
+
* @param props.yAccessor - Reads a datum's y value.
|
|
6297
|
+
* @return The ring, or nothing when the slot has no position.
|
|
6298
|
+
*/
|
|
6299
|
+
const SelectedBarRing = ({ chartId, selected, slotKeys, groupPadding, horizontal, xAccessor, yAccessor }) => {
|
|
6300
|
+
const context = useContext(DataContext);
|
|
6301
|
+
const bandScale = horizontal ? context?.yScale : context?.xScale;
|
|
6302
|
+
const valueScale = horizontal ? context?.xScale : context?.yScale;
|
|
6303
|
+
const bandwidth = bandScale?.bandwidth?.() ?? 0;
|
|
6304
|
+
const [category] = selected.data;
|
|
6305
|
+
if (!bandScale || !valueScale || !bandwidth || !category) return null;
|
|
6306
|
+
const groupScale = createGroupScale(slotKeys, bandwidth, groupPadding);
|
|
6307
|
+
const slotOffset = groupScale(selected.slotKey);
|
|
6308
|
+
const bandPosition = Number(bandScale((horizontal ? yAccessor : xAccessor)(category)));
|
|
6309
|
+
if (slotOffset == null || !Number.isFinite(bandPosition)) return null;
|
|
6310
|
+
const valuePositions = selected.data.map((datum) => Number(valueScale(Number((horizontal ? xAccessor : yAccessor)(datum)))));
|
|
6311
|
+
const rect = computeSlotRect({
|
|
6312
|
+
horizontal,
|
|
6313
|
+
bandPosition,
|
|
6314
|
+
slotOffset,
|
|
6315
|
+
slotThickness: groupScale.bandwidth(),
|
|
6316
|
+
valuePositions: [getValueScaleBaseline(valueScale), ...valuePositions],
|
|
6317
|
+
widthFactor: selected.thickness
|
|
6318
|
+
});
|
|
6319
|
+
return /* @__PURE__ */ jsx(SelectedRing, {
|
|
6320
|
+
chartId,
|
|
6321
|
+
d: `M${rect.x} ${rect.y}h${rect.width}v${rect.height}h${-rect.width}Z`,
|
|
6322
|
+
side: "outside",
|
|
6323
|
+
testId: "bar-chart-selected-ring"
|
|
6324
|
+
});
|
|
6325
|
+
};
|
|
6326
|
+
//#endregion
|
|
6327
|
+
//#region src/charts/bar-chart/private/bar-layer.tsx
|
|
6328
|
+
/**
|
|
6329
|
+
* Draws the bars in front of any comparison shadows, slotted for an overlap layout and grouped by visx otherwise, then the selected bar's ring.
|
|
6330
|
+
*
|
|
6331
|
+
* @param props - Component props.
|
|
6332
|
+
* @param props.chartId - The chart's id, which keeps the ring's clip path unique on a page with several charts.
|
|
6333
|
+
* @param props.overlapSlots - The overlap layout, or undefined for a grouped one.
|
|
6334
|
+
* @param props.selectedBar - The bar or slot the keyboard has selected.
|
|
6335
|
+
* @param props.primaryEntries - The visible primary series, for a grouped layout.
|
|
6336
|
+
* @param props.primaryKeys - Their labels, in group order.
|
|
6337
|
+
* @param props.getBarBackground - Reads a series' bar fill.
|
|
6338
|
+
* @param props.barClassName - Adds classes to a bar.
|
|
6339
|
+
* @param props.groupPadding - The padding between the bars of a category.
|
|
6340
|
+
* @param props.horizontal - Whether the bars run horizontally.
|
|
6341
|
+
* @param props.xAccessor - Reads a datum's x value.
|
|
6342
|
+
* @param props.yAccessor - Reads a datum's y value.
|
|
6343
|
+
* @return The bars.
|
|
6344
|
+
*/
|
|
6345
|
+
const BarLayer = ({ chartId, overlapSlots, selectedBar, primaryEntries, primaryKeys, getBarBackground, barClassName, groupPadding, horizontal, xAccessor, yAccessor }) => {
|
|
6346
|
+
let bars;
|
|
6347
|
+
if (overlapSlots) bars = /* @__PURE__ */ jsx("g", {
|
|
6348
|
+
className: "visx-bar-group",
|
|
6349
|
+
children: overlapSlots.entries.map(({ series, index }) => /* @__PURE__ */ jsx(SlottedBarSeries, {
|
|
6350
|
+
dataKey: series.label,
|
|
6351
|
+
data: series.data,
|
|
6352
|
+
xAccessor,
|
|
6353
|
+
yAccessor,
|
|
6354
|
+
colorAccessor: getBarBackground(index),
|
|
6355
|
+
barClassName,
|
|
6356
|
+
slotKeys: overlapSlots.slotKeys,
|
|
6357
|
+
slotKey: overlapSlots.slotOf(series.label),
|
|
6358
|
+
thickness: overlapSlots.thicknessOf(series.label),
|
|
6359
|
+
groupPadding
|
|
6360
|
+
}, series.label))
|
|
6361
|
+
});
|
|
6362
|
+
else if (barClassName) bars = /* @__PURE__ */ jsx("g", {
|
|
6363
|
+
className: "visx-bar-group",
|
|
6364
|
+
children: primaryEntries.map(({ series, index }) => /* @__PURE__ */ jsx(ClassifiedBarSeries, {
|
|
6365
|
+
dataKey: series.label,
|
|
6366
|
+
data: series.data,
|
|
6367
|
+
xAccessor,
|
|
6368
|
+
yAccessor,
|
|
6369
|
+
colorAccessor: getBarBackground(index),
|
|
6370
|
+
barClassName,
|
|
6371
|
+
primaryKeys,
|
|
6372
|
+
groupPadding
|
|
6373
|
+
}, series.label))
|
|
6374
|
+
});
|
|
6375
|
+
else bars = /* @__PURE__ */ jsx(BarGroup, {
|
|
6376
|
+
padding: groupPadding,
|
|
6377
|
+
children: primaryEntries.map(({ series, index }) => /* @__PURE__ */ jsx(BarSeries, {
|
|
6378
|
+
dataKey: series.label,
|
|
6379
|
+
data: series.data,
|
|
6380
|
+
xAccessor,
|
|
6381
|
+
yAccessor,
|
|
6382
|
+
colorAccessor: getBarBackground(index)
|
|
6383
|
+
}, series.label))
|
|
6384
|
+
});
|
|
6385
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [bars, selectedBar && /* @__PURE__ */ jsx(SelectedBarRing, {
|
|
6386
|
+
chartId,
|
|
6387
|
+
selected: selectedBar,
|
|
6388
|
+
slotKeys: overlapSlots?.slotKeys ?? primaryKeys,
|
|
6389
|
+
groupPadding,
|
|
6390
|
+
horizontal,
|
|
6391
|
+
xAccessor,
|
|
6392
|
+
yAccessor
|
|
6393
|
+
})] });
|
|
6394
|
+
};
|
|
6395
|
+
//#endregion
|
|
6396
|
+
//#region src/charts/bar-chart/private/slot-tooltip-members.tsx
|
|
6397
|
+
/**
|
|
6398
|
+
* Fills the tooltip with every bar of the keyboard-selected category, and only those.
|
|
6399
|
+
*
|
|
6400
|
+
* The last member shown becomes the tooltip's nearest datum, so the caller lists the keyboard stop last.
|
|
6401
|
+
*
|
|
6402
|
+
* @param props - Component props.
|
|
6403
|
+
* @param props.members - The category's bars, the keyboard stop last.
|
|
6404
|
+
* @param props.index - The selected data point.
|
|
6405
|
+
* @return No visual content.
|
|
6406
|
+
*/
|
|
6407
|
+
function SlotTooltipMembers({ members, index }) {
|
|
6408
|
+
const { showTooltip, updateTooltip } = useContext(TooltipContext) ?? {};
|
|
6409
|
+
useEffect(() => {
|
|
6410
|
+
updateTooltip?.((state) => ({
|
|
6411
|
+
...state,
|
|
6412
|
+
tooltipData: void 0
|
|
6413
|
+
}));
|
|
6414
|
+
members.forEach(({ key, datum }) => showTooltip?.({
|
|
6415
|
+
key,
|
|
6416
|
+
datum,
|
|
6417
|
+
index
|
|
6418
|
+
}));
|
|
6419
|
+
}, [members, index]);
|
|
6420
|
+
return null;
|
|
6421
|
+
}
|
|
6422
|
+
//#endregion
|
|
6423
|
+
//#region src/charts/bar-chart/private/overlap-bars.ts
|
|
6424
|
+
const PRIMARY_SLOT = "primary";
|
|
6425
|
+
const COMPARISON_SLOT = "comparison";
|
|
6426
|
+
const OVERLAP_SLOTS = [PRIMARY_SLOT, COMPARISON_SLOT];
|
|
6427
|
+
const SEARCH_STEPS = 16;
|
|
6428
|
+
/**
|
|
6429
|
+
* Places each series of an overlap layout: primaries in one slot and comparisons in the other, with each `group` a layer, back to front in order of first appearance.
|
|
6430
|
+
*
|
|
6431
|
+
* @param series - The series to place.
|
|
6432
|
+
* @return Each series' placement, by index.
|
|
6433
|
+
*/
|
|
6434
|
+
function getOverlapPlacements(series) {
|
|
6435
|
+
const layerByGroup = /* @__PURE__ */ new Map();
|
|
6436
|
+
series.forEach(({ group }) => {
|
|
6437
|
+
if (!layerByGroup.has(group)) layerByGroup.set(group, layerByGroup.size);
|
|
6438
|
+
});
|
|
6439
|
+
const layerCount = layerByGroup.size;
|
|
6440
|
+
return series.map((item) => {
|
|
6441
|
+
const layer = layerByGroup.get(item.group) ?? 0;
|
|
6442
|
+
return {
|
|
6443
|
+
slot: item.options?.type === "comparison" ? COMPARISON_SLOT : PRIMARY_SLOT,
|
|
6444
|
+
layer,
|
|
6445
|
+
thickness: layerCount > 1 ? 1 - layer * .5 / (layerCount - 1) : 1
|
|
6446
|
+
};
|
|
6447
|
+
});
|
|
6448
|
+
}
|
|
6449
|
+
/**
|
|
6450
|
+
* Blends `from` toward `to` and returns the blend nearest the point where `passes` changes, on its passing side.
|
|
6451
|
+
*
|
|
6452
|
+
* @param from - Where the blend starts.
|
|
6453
|
+
* @param to - Where the blend ends.
|
|
6454
|
+
* @param passes - A test that changes at most once along the blend.
|
|
6455
|
+
* @return A hex color.
|
|
6456
|
+
*/
|
|
6457
|
+
function blendToEdge(from, to, passes) {
|
|
6458
|
+
const passesAtStart = passes(from);
|
|
6459
|
+
let low = 0;
|
|
6460
|
+
let high = 1;
|
|
6461
|
+
for (let step = 0; step < SEARCH_STEPS; step++) {
|
|
6462
|
+
const middle = (low + high) / 2;
|
|
6463
|
+
if (passes(mixHexColors(from, to, middle)) === passesAtStart) low = middle;
|
|
6464
|
+
else high = middle;
|
|
6465
|
+
}
|
|
6466
|
+
return mixHexColors(from, to, passesAtStart ? low : high);
|
|
6467
|
+
}
|
|
6468
|
+
const awayFrom = (background) => contrastRatio(background, "#000000") >= contrastRatio(background, "#ffffff") ? "#000000" : "#ffffff";
|
|
6469
|
+
const opposite = (end) => end === "#000000" ? "#ffffff" : "#000000";
|
|
6470
|
+
/**
|
|
6471
|
+
* The tone of a color nearest the background that keeps 3:1 against it.
|
|
6472
|
+
*
|
|
6473
|
+
* @param color - A hex color.
|
|
6474
|
+
* @param background - The hex chart background.
|
|
6475
|
+
* @return A hex color.
|
|
6476
|
+
*/
|
|
6477
|
+
function tintWithContrast(color, background) {
|
|
6478
|
+
const passes = (tone) => contrastRatio(tone, background) >= 3;
|
|
6479
|
+
return blendToEdge(color, passes(color) ? background : awayFrom(background), passes);
|
|
6480
|
+
}
|
|
6481
|
+
/**
|
|
6482
|
+
* The tone of a color nearest the original that keeps 3:1 against the bar it is drawn over, on the far side of that bar from the background when that side can reach 3:1.
|
|
6483
|
+
*
|
|
6484
|
+
* @param color - A hex color.
|
|
6485
|
+
* @param under - The hex color of the bar behind it.
|
|
6486
|
+
* @param background - The hex chart background.
|
|
6487
|
+
* @return A hex color.
|
|
6488
|
+
*/
|
|
6489
|
+
function shadeWithContrast(color, under, background) {
|
|
6490
|
+
const passes = (tone) => contrastRatio(tone, under) >= 3;
|
|
6491
|
+
const start = contrastRatio(color, background) > contrastRatio(under, background) ? color : under;
|
|
6492
|
+
if (passes(start)) return start;
|
|
6493
|
+
const away = awayFrom(background);
|
|
6494
|
+
return blendToEdge(start, passes(away) ? away : opposite(away), passes);
|
|
6495
|
+
}
|
|
6496
|
+
/**
|
|
6497
|
+
* The colors an overlap layout fills its series with: per slot, the back layer tinted to 3:1 against the background and each layer in front shaded to 3:1 against the one behind. A slot whose front-most series has its own `stroke` keeps its colors as given.
|
|
6498
|
+
*
|
|
6499
|
+
* @param series - Every series of the chart.
|
|
6500
|
+
* @param colors - Each series' resolved color.
|
|
6501
|
+
* @param slotColors - The palette color of each slot, primaries first.
|
|
6502
|
+
* @param background - The hex chart background.
|
|
6503
|
+
* @return Each series' fill, by index.
|
|
6504
|
+
*/
|
|
6505
|
+
function getOverlapBarColors(series, colors, slotColors, background) {
|
|
6506
|
+
const placements = getOverlapPlacements(series);
|
|
6507
|
+
const barColors = [...colors];
|
|
6508
|
+
OVERLAP_SLOTS.forEach((slot, slotIndex) => {
|
|
6509
|
+
const members = placements.flatMap((placement, index) => placement.slot === slot ? [{
|
|
6510
|
+
index,
|
|
6511
|
+
layer: placement.layer
|
|
6512
|
+
}] : []);
|
|
6513
|
+
if (!members.length) return;
|
|
6514
|
+
const layers = [...new Set(members.map(({ layer }) => layer))].sort((a, b) => a - b);
|
|
6515
|
+
const back = members.find(({ layer }) => layer === layers[0]);
|
|
6516
|
+
const base = back && series[back.index].options?.stroke ? colors[back.index] : slotColors[slotIndex];
|
|
6517
|
+
if (members.some(({ index, layer }) => layer === layers[layers.length - 1] && !!series[index].options?.stroke) || !isValidHexColor(base) || !isValidHexColor(background)) return;
|
|
6518
|
+
const toneByLayer = /* @__PURE__ */ new Map();
|
|
6519
|
+
let under;
|
|
6520
|
+
layers.forEach((layer) => {
|
|
6521
|
+
const tone = under === void 0 ? tintWithContrast(base, background) : shadeWithContrast(base, under, background);
|
|
6522
|
+
toneByLayer.set(layer, tone);
|
|
6523
|
+
under = tone;
|
|
6524
|
+
});
|
|
6525
|
+
members.forEach(({ index, layer }) => {
|
|
6526
|
+
barColors[index] = toneByLayer.get(layer) ?? colors[index];
|
|
6527
|
+
});
|
|
6528
|
+
});
|
|
6529
|
+
return barColors;
|
|
6530
|
+
}
|
|
6531
|
+
//#endregion
|
|
6532
|
+
//#region src/charts/bar-chart/private/use-overlap-slots.ts
|
|
6533
|
+
/**
|
|
6534
|
+
* Whether two data points sit at the same category: the same label, or the same date.
|
|
6535
|
+
*
|
|
6536
|
+
* @param point - A data point.
|
|
6537
|
+
* @param category - The data point naming the category.
|
|
6538
|
+
* @return Whether `point` is at `category`.
|
|
6539
|
+
*/
|
|
6540
|
+
function isSameCategory(point, category) {
|
|
6541
|
+
return category.label != null ? point.label === category.label : !!category.date && !!point.date && point.date.getTime() === category.date.getTime();
|
|
6542
|
+
}
|
|
6543
|
+
/**
|
|
6544
|
+
* Lays out the visible series of an overlap layout in slots and layers.
|
|
6545
|
+
*
|
|
6546
|
+
* @param enabled - Whether the chart draws an overlap layout.
|
|
6547
|
+
* @param seriesWithVisibility - Every series, with its index and whether it is visible.
|
|
6548
|
+
* @return The layout, or undefined when the chart is not an overlap layout.
|
|
6549
|
+
*/
|
|
6550
|
+
function useOverlapSlots(enabled, seriesWithVisibility) {
|
|
6551
|
+
return useMemo(() => {
|
|
6552
|
+
if (!enabled) return;
|
|
6553
|
+
const visible = seriesWithVisibility.filter(({ isVisible }) => isVisible);
|
|
6554
|
+
const placements = getOverlapPlacements(visible.map(({ series }) => series));
|
|
6555
|
+
const placed = visible.map(({ series, index }, position) => ({
|
|
6556
|
+
entry: {
|
|
6557
|
+
series,
|
|
6558
|
+
index
|
|
6559
|
+
},
|
|
6560
|
+
placement: placements[position]
|
|
6561
|
+
})).sort((a, b) => a.placement.layer - b.placement.layer);
|
|
6562
|
+
const entries = placed.map(({ entry }) => entry);
|
|
6563
|
+
const placementByKey = new Map(placed.map(({ entry, placement }) => [entry.series.label, placement]));
|
|
6564
|
+
const slotOf = (key) => placementByKey.get(key)?.slot ?? "primary";
|
|
6565
|
+
const thicknessOf = (key) => placementByKey.get(key)?.thickness ?? 1;
|
|
6566
|
+
const hasPrimaries = seriesWithVisibility.some(({ series }) => series.options?.type !== "comparison");
|
|
6567
|
+
const showsComparisons = entries.some(({ series }) => slotOf(series.label) === COMPARISON_SLOT);
|
|
6568
|
+
const slotKeys = [...hasPrimaries ? [PRIMARY_SLOT] : [], ...showsComparisons ? [COMPARISON_SLOT] : []];
|
|
6569
|
+
return {
|
|
6570
|
+
entries,
|
|
6571
|
+
keys: entries.map(({ series }) => series.label),
|
|
6572
|
+
slotKeys,
|
|
6573
|
+
slotOf,
|
|
6574
|
+
thicknessOf,
|
|
6575
|
+
positions: getStopPositions(entries, slotKeys, slotOf)
|
|
6576
|
+
};
|
|
6577
|
+
}, [enabled, seriesWithVisibility]);
|
|
6578
|
+
}
|
|
6579
|
+
/**
|
|
6580
|
+
* The category a data point sits at, as a key two points share when `isSameCategory` holds.
|
|
6581
|
+
*
|
|
6582
|
+
* @param point - A data point.
|
|
6583
|
+
* @return The category key.
|
|
6584
|
+
*/
|
|
6585
|
+
function categoryKey(point) {
|
|
6586
|
+
return point.label != null ? `label:${point.label}` : `date:${point.date?.getTime()}`;
|
|
6587
|
+
}
|
|
6588
|
+
/**
|
|
6589
|
+
* Lists a stop for every slot at every category that slot draws a bar at, category by category.
|
|
6590
|
+
*
|
|
6591
|
+
* @param entries - The visible series, back to front.
|
|
6592
|
+
* @param slotKeys - The slots, in band order.
|
|
6593
|
+
* @param slotOf - The slot a series sits in.
|
|
6594
|
+
* @return The positions, in keyboard order.
|
|
6595
|
+
*/
|
|
6596
|
+
function getStopPositions(entries, slotKeys, slotOf) {
|
|
6597
|
+
const categories = /* @__PURE__ */ new Map();
|
|
6598
|
+
entries.forEach(({ series }) => {
|
|
6599
|
+
series.data.forEach((datum, dataPointIndex) => {
|
|
6600
|
+
const key = categoryKey(datum);
|
|
6601
|
+
const slots = categories.get(key) ?? /* @__PURE__ */ new Map();
|
|
6602
|
+
categories.set(key, slots);
|
|
6603
|
+
if (!isBarRendered(datum)) return;
|
|
6604
|
+
const slotKey = slotOf(series.label);
|
|
6605
|
+
slots.set(slotKey, {
|
|
6606
|
+
slotKey,
|
|
6607
|
+
key: series.label,
|
|
6608
|
+
datum,
|
|
6609
|
+
dataPointIndex
|
|
6610
|
+
});
|
|
6611
|
+
});
|
|
6612
|
+
});
|
|
6613
|
+
const ordered = [...categories.values()].filter((slots) => slots.size > 0);
|
|
6614
|
+
if (ordered.every((slots) => [...slots.values()].every(({ datum }) => datum.label == null && datum.date))) {
|
|
6615
|
+
const time = (slots) => [...slots.values()][0].datum.date?.getTime() ?? 0;
|
|
6616
|
+
ordered.sort((a, b) => time(a) - time(b));
|
|
6617
|
+
}
|
|
6618
|
+
return ordered.flatMap((slots) => slotKeys.flatMap((slotKey) => {
|
|
6619
|
+
const position = slots.get(slotKey);
|
|
6620
|
+
return position ? [position] : [];
|
|
6621
|
+
}));
|
|
6622
|
+
}
|
|
6623
|
+
/**
|
|
6624
|
+
* The slot a keyboard index selects, and every bar at its category.
|
|
6625
|
+
*
|
|
6626
|
+
* @param slots - The overlap layout.
|
|
6627
|
+
* @param selectedIndex - The keyboard index into `slots.positions`.
|
|
6628
|
+
* @return The selected slot, or undefined when nothing is selected or drawn there.
|
|
6629
|
+
*/
|
|
6630
|
+
function getSelectedSlot(slots, selectedIndex) {
|
|
6631
|
+
const position = selectedIndex === void 0 ? void 0 : slots?.positions[selectedIndex];
|
|
6632
|
+
if (!slots || !position) return;
|
|
6633
|
+
const { slotKey, key: stopKey, datum: category, dataPointIndex } = position;
|
|
6634
|
+
const members = slots.entries.flatMap(({ series }) => {
|
|
6635
|
+
const datum = series.data.find((point) => isSameCategory(point, category));
|
|
6636
|
+
return datum ? [{
|
|
6637
|
+
key: series.label,
|
|
6638
|
+
datum
|
|
6639
|
+
}] : [];
|
|
6640
|
+
});
|
|
6641
|
+
const slotBars = members.filter(({ key, datum }) => isBarRendered(datum) && slots.slotOf(key) === slotKey);
|
|
6642
|
+
return {
|
|
6643
|
+
data: slotBars.map(({ datum }) => datum),
|
|
6644
|
+
slotKey,
|
|
6645
|
+
thickness: Math.max(...slotBars.map(({ key }) => slots.thicknessOf(key))),
|
|
6646
|
+
index: dataPointIndex,
|
|
6647
|
+
members: [...members.filter(({ key }) => key !== stopKey), ...members.filter(({ key }) => key === stopKey)]
|
|
6648
|
+
};
|
|
6649
|
+
}
|
|
6650
|
+
//#endregion
|
|
6651
|
+
//#region src/charts/bar-chart/private/use-bar-stops.ts
|
|
6652
|
+
/**
|
|
6653
|
+
* Lays out the keyboard stops: one per slot and category in an overlap layout, else one per primary bar, series-major within each category.
|
|
6654
|
+
*
|
|
6655
|
+
* @param overlapSlots - The overlap layout, or undefined for a grouped one.
|
|
6656
|
+
* @param primaryEntries - The visible primary series.
|
|
6657
|
+
* @return The stops.
|
|
6658
|
+
*/
|
|
6659
|
+
function useBarStops(overlapSlots, primaryEntries) {
|
|
6660
|
+
const series = useMemo(() => overlapSlots ? [] : primaryEntries.map((entry) => entry.series), [overlapSlots, primaryEntries]);
|
|
6661
|
+
return {
|
|
6662
|
+
count: overlapSlots?.positions.length ?? Math.max(0, ...series.map((item) => item.data.length)) * series.length,
|
|
6663
|
+
series,
|
|
6664
|
+
key: useMemo(() => JSON.stringify(overlapSlots?.keys ?? series.map((item) => item.label)), [overlapSlots, series]),
|
|
6665
|
+
barAt: useCallback((stop) => {
|
|
6666
|
+
if (overlapSlots) {
|
|
6667
|
+
const position = overlapSlots.positions[stop];
|
|
6668
|
+
return position && {
|
|
6669
|
+
datum: position.datum,
|
|
6670
|
+
index: position.dataPointIndex,
|
|
6671
|
+
key: position.key
|
|
6672
|
+
};
|
|
6673
|
+
}
|
|
6674
|
+
if (!series.length) return;
|
|
6675
|
+
const index = Math.floor(stop / series.length);
|
|
6676
|
+
const item = series[stop % series.length];
|
|
6677
|
+
const datum = item?.data[index];
|
|
6678
|
+
return item && datum ? {
|
|
6679
|
+
datum,
|
|
6680
|
+
index,
|
|
6681
|
+
key: item.label
|
|
6682
|
+
} : void 0;
|
|
6683
|
+
}, [overlapSlots, series]),
|
|
6684
|
+
stopOf: useCallback((seriesKey, dataPointIndex) => {
|
|
6685
|
+
if (overlapSlots) {
|
|
6686
|
+
const hovered = overlapSlots.entries.find((entry) => entry.series.label === seriesKey)?.series.data[dataPointIndex];
|
|
6687
|
+
const slotKey = overlapSlots.slotOf(seriesKey);
|
|
6688
|
+
const stop = hovered ? overlapSlots.positions.findIndex((position) => position.slotKey === slotKey && isSameCategory(position.datum, hovered)) : -1;
|
|
6689
|
+
return stop >= 0 ? stop : void 0;
|
|
6690
|
+
}
|
|
6691
|
+
const seriesIndex = series.findIndex((item) => item.label === seriesKey);
|
|
6692
|
+
return seriesIndex >= 0 ? dataPointIndex * series.length + seriesIndex : void 0;
|
|
6693
|
+
}, [overlapSlots, series])
|
|
6694
|
+
};
|
|
6695
|
+
}
|
|
6179
6696
|
/**
|
|
6180
6697
|
* Upper clamp on the computed group padding, so bars can never collapse to zero width
|
|
6181
6698
|
* even at very large `widthFactor` values.
|
|
@@ -6211,9 +6728,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
6211
6728
|
data: series,
|
|
6212
6729
|
index
|
|
6213
6730
|
});
|
|
6214
|
-
const opacity = barStyles?.opacity ?? .5;
|
|
6215
6731
|
const widthFactor = barStyles?.widthFactor ?? 1.5;
|
|
6216
|
-
const fill = resolveFill(entry);
|
|
6217
6732
|
series.data.forEach((datum, i) => {
|
|
6218
6733
|
const bandPosition = Number(bandScale(bandAccessor(datum)));
|
|
6219
6734
|
const valuePosition = Number(valueScale(Number(valueAccessor(datum))));
|
|
@@ -6221,13 +6736,12 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
6221
6736
|
if (process.env.NODE_ENV !== "production" && !Number.isFinite(bandPosition)) console.warn(`[Charts] ComparisonBars: datum key "${String(bandAccessor(datum))}" did not match any primary category. Shadow will not be rendered. Ensure comparison series data uses the same label/date keys as the primary series.`);
|
|
6222
6737
|
return;
|
|
6223
6738
|
}
|
|
6224
|
-
const rect =
|
|
6739
|
+
const rect = computeSlotRect({
|
|
6225
6740
|
horizontal,
|
|
6226
6741
|
bandPosition,
|
|
6227
6742
|
slotOffset,
|
|
6228
6743
|
slotThickness,
|
|
6229
|
-
valuePosition,
|
|
6230
|
-
baseline,
|
|
6744
|
+
valuePositions: [baseline, valuePosition],
|
|
6231
6745
|
widthFactor
|
|
6232
6746
|
});
|
|
6233
6747
|
rects.push(/* @__PURE__ */ jsx("rect", {
|
|
@@ -6236,8 +6750,8 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
6236
6750
|
y: rect.y,
|
|
6237
6751
|
width: rect.width,
|
|
6238
6752
|
height: rect.height,
|
|
6239
|
-
fill,
|
|
6240
|
-
opacity
|
|
6753
|
+
fill: resolveFill(entry, datum),
|
|
6754
|
+
opacity: barStyles?.opacity
|
|
6241
6755
|
}, `${index}-${i}`));
|
|
6242
6756
|
});
|
|
6243
6757
|
});
|
|
@@ -6336,7 +6850,8 @@ function nearestBandIndex(data, accessor, scale, position) {
|
|
|
6336
6850
|
/**
|
|
6337
6851
|
* Correct visx's range-based band inversion, which omits outer padding.
|
|
6338
6852
|
* @param root0 - Registered series selection.
|
|
6339
|
-
* @param root0.keys - Visible series keys.
|
|
6853
|
+
* @param root0.keys - Visible series keys, back to front where bars overlap.
|
|
6854
|
+
* @param root0.slots - Where series share slots: the slots of a category, in the order the band lays them out, and the slot each series sits in.
|
|
6340
6855
|
* @param root0.groupPadding - Padding between grouped bars.
|
|
6341
6856
|
* @param root0.withTooltips - Whether pointer events update the tooltip.
|
|
6342
6857
|
* @param root0.onPointerDown - Receives the corrected pointer-down datum.
|
|
@@ -6344,12 +6859,13 @@ function nearestBandIndex(data, accessor, scale, position) {
|
|
|
6344
6859
|
* @param root0.onPointerMove - Receives the corrected datum under a moving pointer.
|
|
6345
6860
|
* @return No visual content.
|
|
6346
6861
|
*/
|
|
6347
|
-
function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointerUp, onPointerMove }) {
|
|
6862
|
+
function BandTooltip({ keys, slots, groupPadding, withTooltips, onPointerDown, onPointerUp, onPointerMove }) {
|
|
6348
6863
|
const { xScale, yScale, dataRegistry, horizontal } = useContext(DataContext);
|
|
6349
|
-
const { showTooltip } = useContext(TooltipContext);
|
|
6864
|
+
const { showTooltip, hideTooltip, updateTooltip } = useContext(TooltipContext);
|
|
6350
6865
|
const scale = horizontal ? yScale : xScale;
|
|
6351
6866
|
const bandwidth = scale?.bandwidth?.() ?? 0;
|
|
6352
|
-
const groupScale = useMemo(() => createGroupScale(keys, bandwidth, groupPadding), [
|
|
6867
|
+
const groupScale = useMemo(() => createGroupScale(slots?.keys ?? keys, bandwidth, groupPadding), [
|
|
6868
|
+
slots,
|
|
6353
6869
|
keys,
|
|
6354
6870
|
bandwidth,
|
|
6355
6871
|
groupPadding
|
|
@@ -6357,18 +6873,21 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
|
|
|
6357
6873
|
const getSelections = useCallback((params) => {
|
|
6358
6874
|
const point = params?.svgPoint;
|
|
6359
6875
|
if (!point || !scale?.bandwidth) return [];
|
|
6876
|
+
const position = horizontal ? point.y : point.x;
|
|
6360
6877
|
const selections = [];
|
|
6878
|
+
const bands = [];
|
|
6361
6879
|
for (const key of keys) {
|
|
6362
6880
|
const entry = dataRegistry?.get(key);
|
|
6363
6881
|
if (!entry) continue;
|
|
6364
6882
|
const accessor = horizontal ? entry.yAccessor : entry.xAccessor;
|
|
6365
|
-
const index = nearestBandIndex(entry.data, accessor, scale,
|
|
6883
|
+
const index = nearestBandIndex(entry.data, accessor, scale, position);
|
|
6366
6884
|
if (index < 0) continue;
|
|
6367
6885
|
const datum = entry.data[index];
|
|
6368
|
-
const
|
|
6886
|
+
const band = Number(scale(accessor(datum)));
|
|
6887
|
+
const start = band + Number(groupScale(slots ? slots.slotOf(key) : key));
|
|
6369
6888
|
const end = start + groupScale.step();
|
|
6370
|
-
const position = horizontal ? point.y : point.x;
|
|
6371
6889
|
const distance = position >= start && position <= end ? 0 : Math.abs(position - (start + end) / 2);
|
|
6890
|
+
bands.push(band);
|
|
6372
6891
|
selections.push({
|
|
6373
6892
|
event: params.event,
|
|
6374
6893
|
key,
|
|
@@ -6379,12 +6898,16 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
|
|
|
6379
6898
|
distanceY: horizontal ? distance : 0
|
|
6380
6899
|
});
|
|
6381
6900
|
}
|
|
6382
|
-
return selections;
|
|
6901
|
+
if (!slots) return selections;
|
|
6902
|
+
const bandDistance = (band) => Math.abs(band + scale.bandwidth() / 2 - position);
|
|
6903
|
+
const hoveredBand = bands.reduce((best, band) => best === void 0 || bandDistance(band) < bandDistance(best) ? band : best, void 0);
|
|
6904
|
+
return selections.filter((_, index) => bands[index] === hoveredBand);
|
|
6383
6905
|
}, [
|
|
6384
6906
|
scale,
|
|
6385
6907
|
dataRegistry,
|
|
6386
6908
|
horizontal,
|
|
6387
6909
|
keys,
|
|
6910
|
+
slots,
|
|
6388
6911
|
groupScale
|
|
6389
6912
|
]);
|
|
6390
6913
|
const handlePointer = useCallback((params) => {
|
|
@@ -6394,24 +6917,162 @@ function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointe
|
|
|
6394
6917
|
return !best || distance(selection) <= distance(best) ? selection : best;
|
|
6395
6918
|
}, void 0);
|
|
6396
6919
|
if (params?.event.type === "pointermove" && nearest) onPointerMove?.(nearest);
|
|
6397
|
-
if (withTooltips && params?.event.type !== "pointerup")
|
|
6920
|
+
if (withTooltips && params?.event.type !== "pointerup") {
|
|
6921
|
+
if (slots) updateTooltip((state) => ({
|
|
6922
|
+
...state,
|
|
6923
|
+
tooltipData: void 0
|
|
6924
|
+
}));
|
|
6925
|
+
selections.forEach(showTooltip);
|
|
6926
|
+
}
|
|
6398
6927
|
const callback = params?.event.type === "pointerdown" ? onPointerDown : onPointerUp;
|
|
6399
6928
|
if (params?.event.type === "pointermove" || !callback) return;
|
|
6400
6929
|
if (nearest) callback(nearest);
|
|
6401
6930
|
}, [
|
|
6402
6931
|
getSelections,
|
|
6403
6932
|
withTooltips,
|
|
6933
|
+
slots,
|
|
6404
6934
|
showTooltip,
|
|
6935
|
+
updateTooltip,
|
|
6405
6936
|
onPointerDown,
|
|
6406
6937
|
onPointerUp,
|
|
6407
6938
|
onPointerMove
|
|
6408
6939
|
]);
|
|
6409
6940
|
useEventEmitter("pointermove", withTooltips ? handlePointer : void 0);
|
|
6941
|
+
useEventEmitter("pointerout", withTooltips && slots ? hideTooltip : void 0);
|
|
6410
6942
|
useEventEmitter("pointerdown", handlePointer);
|
|
6411
6943
|
useEventEmitter("pointerup", onPointerUp ? handlePointer : void 0);
|
|
6412
6944
|
return null;
|
|
6413
6945
|
}
|
|
6414
6946
|
//#endregion
|
|
6947
|
+
//#region src/charts/bar-chart/private/grouped-bars.ts
|
|
6948
|
+
/**
|
|
6949
|
+
* Pairs each comparison series with the primary of its `group`, or with the only primary.
|
|
6950
|
+
*
|
|
6951
|
+
* @param series - The chart's series.
|
|
6952
|
+
* @return The index of each paired comparison's primary, keyed by the comparison's index.
|
|
6953
|
+
*/
|
|
6954
|
+
function getComparisonPrimaries(series) {
|
|
6955
|
+
const primaries = series.flatMap((item, index) => item.options?.type === "comparison" ? [] : [{
|
|
6956
|
+
group: item.group,
|
|
6957
|
+
index
|
|
6958
|
+
}]);
|
|
6959
|
+
const primaryByGroup = new Map(primaries.map(({ group, index }) => [group, index]));
|
|
6960
|
+
const onlyPrimary = primaries.length === 1 ? primaries[0].index : void 0;
|
|
6961
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
6962
|
+
series.forEach((item, index) => {
|
|
6963
|
+
const primary = item.options?.type === "comparison" ? primaryByGroup.get(item.group) ?? onlyPrimary : void 0;
|
|
6964
|
+
if (primary !== void 0) pairs.set(index, primary);
|
|
6965
|
+
});
|
|
6966
|
+
return pairs;
|
|
6967
|
+
}
|
|
6968
|
+
/**
|
|
6969
|
+
* The colors a grouped bar chart fills its series with. A comparison takes the lightest tint of its primary's color that keeps 3:1 against the background, and the primary in front of it the shade that keeps 3:1 against that tint. A primary with its own `stroke` keeps it, and a comparison with its own, different `stroke` keeps the pair's colors as given.
|
|
6970
|
+
*
|
|
6971
|
+
* @param series - The chart's series.
|
|
6972
|
+
* @param colors - Each series' resolved color.
|
|
6973
|
+
* @param background - The hex chart background.
|
|
6974
|
+
* @return Each series' fill, by index.
|
|
6975
|
+
*/
|
|
6976
|
+
function getGroupedBarColors(series, colors, background) {
|
|
6977
|
+
const barColors = [...colors];
|
|
6978
|
+
getComparisonPrimaries(series).forEach((primary, comparison) => {
|
|
6979
|
+
const base = colors[primary];
|
|
6980
|
+
if (!!series[comparison].options?.stroke && colors[comparison].toLowerCase() !== base.toLowerCase() || !isValidHexColor(base) || !isValidHexColor(background)) return;
|
|
6981
|
+
const tint = tintWithContrast(base, background);
|
|
6982
|
+
barColors[comparison] = tint;
|
|
6983
|
+
if (!series[primary].options?.stroke) barColors[primary] = shadeWithContrast(base, tint, background);
|
|
6984
|
+
});
|
|
6985
|
+
return barColors;
|
|
6986
|
+
}
|
|
6987
|
+
//#endregion
|
|
6988
|
+
//#region src/charts/bar-chart/use-bar-colors.ts
|
|
6989
|
+
/**
|
|
6990
|
+
* Reads the colors `BarChart` fills series with, so a custom tooltip or legend can match the bars.
|
|
6991
|
+
*
|
|
6992
|
+
* @return A function from series and a layout to each series' bar color, by index.
|
|
6993
|
+
*/
|
|
6994
|
+
function useBarColors() {
|
|
6995
|
+
const { getElementStyles, backgroundColor = BACKGROUND_FALLBACK, theme } = useGlobalChartsContext();
|
|
6996
|
+
const comparisonOpacity = theme.barChart?.barStyles?.comparison?.opacity;
|
|
6997
|
+
return useCallback((series, { layout = "grouped" } = {}) => {
|
|
6998
|
+
const colors = series.map((data, index) => getElementStyles({
|
|
6999
|
+
data,
|
|
7000
|
+
index
|
|
7001
|
+
}).color);
|
|
7002
|
+
if (layout !== "overlap") return comparisonOpacity === void 0 ? getGroupedBarColors(series, colors, backgroundColor) : colors;
|
|
7003
|
+
return getOverlapBarColors(series, colors, [getElementStyles({ index: 0 }).color, getElementStyles({ index: 1 }).color], backgroundColor);
|
|
7004
|
+
}, [
|
|
7005
|
+
getElementStyles,
|
|
7006
|
+
backgroundColor,
|
|
7007
|
+
comparisonOpacity
|
|
7008
|
+
]);
|
|
7009
|
+
}
|
|
7010
|
+
//#endregion
|
|
7011
|
+
//#region src/charts/bar-chart/use-bar-legend-items.ts
|
|
7012
|
+
const isComparison = (data, label) => data.some((series) => series.label === label && series.options?.type === "comparison");
|
|
7013
|
+
/**
|
|
7014
|
+
* Applies what a bar layout changes about a legend: overlap lists every primary before every comparison, as it draws their slots, with every swatch opaque like its bar; a collapsed grouped item takes its comparison's tint, the wider bar that frames the group.
|
|
7015
|
+
*
|
|
7016
|
+
* @param data - The series the items were built from.
|
|
7017
|
+
* @param items - The legend items.
|
|
7018
|
+
* @param layout - The layout the bars are drawn in.
|
|
7019
|
+
* @param seriesColors - Each series' bar color, by index.
|
|
7020
|
+
* @return The legend items.
|
|
7021
|
+
*/
|
|
7022
|
+
function forBarLayout(data, items, layout, seriesColors) {
|
|
7023
|
+
if (layout === "overlap") {
|
|
7024
|
+
const opaque = items.map((item) => item.shapeStyle ? {
|
|
7025
|
+
...item,
|
|
7026
|
+
shapeStyle: {
|
|
7027
|
+
...item.shapeStyle,
|
|
7028
|
+
opacity: void 0
|
|
7029
|
+
}
|
|
7030
|
+
} : item);
|
|
7031
|
+
const seriesItems = opaque.filter((item) => item.seriesLabels);
|
|
7032
|
+
const firstLabel = (item) => item.seriesLabels?.[0];
|
|
7033
|
+
return [
|
|
7034
|
+
...seriesItems.filter((item) => !isComparison(data, firstLabel(item))),
|
|
7035
|
+
...seriesItems.filter((item) => isComparison(data, firstLabel(item))),
|
|
7036
|
+
...opaque.filter((item) => !item.seriesLabels)
|
|
7037
|
+
];
|
|
7038
|
+
}
|
|
7039
|
+
return items.map((item) => {
|
|
7040
|
+
if ((item.seriesLabels?.length ?? 0) < 2) return item;
|
|
7041
|
+
const comparisonIndex = data.findIndex((series) => series.options?.type === "comparison" && item.seriesLabels?.includes(series.label));
|
|
7042
|
+
return comparisonIndex === -1 ? item : {
|
|
7043
|
+
...item,
|
|
7044
|
+
color: seriesColors[comparisonIndex]
|
|
7045
|
+
};
|
|
7046
|
+
});
|
|
7047
|
+
}
|
|
7048
|
+
/**
|
|
7049
|
+
* Builds legend items that match `BarChart`'s bars in a layout, for a custom legend or a chart's own.
|
|
7050
|
+
*
|
|
7051
|
+
* @param data - The series the chart draws.
|
|
7052
|
+
* @param options - The legend options, and the layout the bars are drawn in.
|
|
7053
|
+
* @param legendShape - The shape of the legend swatches.
|
|
7054
|
+
* @return The legend items.
|
|
7055
|
+
*/
|
|
7056
|
+
function useBarLegendItems(data, options = {}, legendShape) {
|
|
7057
|
+
const { layout } = options;
|
|
7058
|
+
const getBarColors = useBarColors();
|
|
7059
|
+
const seriesColors = useMemo(() => layout ? getBarColors(data, { layout }) : void 0, [
|
|
7060
|
+
data,
|
|
7061
|
+
layout,
|
|
7062
|
+
getBarColors
|
|
7063
|
+
]);
|
|
7064
|
+
const items = useChartLegendItems(data, useMemo(() => ({
|
|
7065
|
+
...options,
|
|
7066
|
+
seriesColors
|
|
7067
|
+
}), [options, seriesColors]), legendShape);
|
|
7068
|
+
return useMemo(() => layout && seriesColors ? forBarLayout(data, items, layout, seriesColors) : items, [
|
|
7069
|
+
data,
|
|
7070
|
+
items,
|
|
7071
|
+
layout,
|
|
7072
|
+
seriesColors
|
|
7073
|
+
]);
|
|
7074
|
+
}
|
|
7075
|
+
//#endregion
|
|
6415
7076
|
//#region src/charts/bar-chart/bar-chart.tsx
|
|
6416
7077
|
const validateData$2 = (data) => {
|
|
6417
7078
|
if (!data?.length) return __("No data available", "jetpack-charts");
|
|
@@ -6423,13 +7084,14 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
|
|
|
6423
7084
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
6424
7085
|
children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
6425
7086
|
});
|
|
6426
|
-
const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
7087
|
+
const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", layout = "grouped", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
6427
7088
|
if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
|
|
6428
7089
|
const legendInteractive = legend.interactive ?? false;
|
|
6429
7090
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
6430
7091
|
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
6431
7092
|
const legendComparisonSeriesItems = legend.comparisonSeriesItems;
|
|
6432
7093
|
const horizontal = orientation === "horizontal";
|
|
7094
|
+
const isOverlap = layout === "overlap";
|
|
6433
7095
|
const chartId = useChartId(providedChartId);
|
|
6434
7096
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
6435
7097
|
const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
|
|
@@ -6439,16 +7101,25 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6439
7101
|
enabled: showZeroValues,
|
|
6440
7102
|
valueAxisLength: horizontal ? width : height
|
|
6441
7103
|
});
|
|
6442
|
-
const legendItems =
|
|
7104
|
+
const legendItems = useBarLegendItems(dataSorted, useMemo(() => ({
|
|
6443
7105
|
collapseGroups: legendCollapseGroups,
|
|
6444
7106
|
comparisonItem: legendComparisonItem,
|
|
6445
|
-
comparisonSeriesItems: legendComparisonSeriesItems
|
|
7107
|
+
comparisonSeriesItems: legendComparisonSeriesItems,
|
|
7108
|
+
layout
|
|
6446
7109
|
}), [
|
|
6447
7110
|
legendCollapseGroups,
|
|
6448
7111
|
legendComparisonItem,
|
|
6449
|
-
legendComparisonSeriesItems
|
|
7112
|
+
legendComparisonSeriesItems,
|
|
7113
|
+
layout
|
|
6450
7114
|
]));
|
|
6451
|
-
const { getElementStyles } = useGlobalChartsContext();
|
|
7115
|
+
const { getElementStyles, theme: providerTheme } = useGlobalChartsContext();
|
|
7116
|
+
const getBarColors = useBarColors();
|
|
7117
|
+
const barColors = useMemo(() => getBarColors(dataSorted, { layout }), [
|
|
7118
|
+
layout,
|
|
7119
|
+
getBarColors,
|
|
7120
|
+
dataSorted
|
|
7121
|
+
]);
|
|
7122
|
+
if (providerTheme.barChart?.barStyles?.comparison?.opacity !== void 0) warnOnce("bar-chart-comparison-opacity", "BarChart: theme.barChart.barStyles.comparison.opacity is deprecated. Comparison bars are opaque; leave it unset.");
|
|
6452
7123
|
const isSeriesRendered = useCallback((series) => isSeriesVisible(series.label), [isSeriesVisible]);
|
|
6453
7124
|
const hasWholeNumberValues = useMemo(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
|
|
6454
7125
|
const chartOptions = useBarChartOptions(dataWithVisibleZeros, horizontal, options, isSeriesRendered);
|
|
@@ -6477,37 +7148,30 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6477
7148
|
return seriesWithVisibility.every(({ isVisible }) => !isVisible);
|
|
6478
7149
|
}, [seriesWithVisibility]);
|
|
6479
7150
|
const primaryEntries = useMemo(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
|
|
6480
|
-
const
|
|
7151
|
+
const overlapSlots = useOverlapSlots(isOverlap, seriesWithVisibility);
|
|
6481
7152
|
const primaryKeys = useMemo(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
|
|
6482
|
-
const
|
|
6483
|
-
const
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
const datum = series?.data[dataPointIndex];
|
|
6489
|
-
if (series && datum) onDatumActivate?.({
|
|
6490
|
-
datum,
|
|
6491
|
-
index: dataPointIndex,
|
|
6492
|
-
key: series.label
|
|
6493
|
-
});
|
|
6494
|
-
}, [primaryEntries, onDatumActivate]);
|
|
6495
|
-
const visibleSeriesKey = useMemo(() => JSON.stringify(primaryKeys), [primaryKeys]);
|
|
7153
|
+
const stops = useBarStops(overlapSlots, primaryEntries);
|
|
7154
|
+
const { barAt, stopOf } = stops;
|
|
7155
|
+
const activateSelectedBar = useCallback((stop) => {
|
|
7156
|
+
const bar = barAt(stop);
|
|
7157
|
+
if (bar) onDatumActivate?.(bar);
|
|
7158
|
+
}, [barAt, onDatumActivate]);
|
|
6496
7159
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown, onChartPointerMove } = useKeyboardNavigation({
|
|
6497
7160
|
selectedIndex,
|
|
6498
7161
|
setSelectedIndex,
|
|
6499
7162
|
isNavigating,
|
|
6500
7163
|
setIsNavigating,
|
|
6501
7164
|
chartRef,
|
|
6502
|
-
totalPoints,
|
|
7165
|
+
totalPoints: stops.count,
|
|
6503
7166
|
onActivate: activateSelectedBar,
|
|
6504
|
-
visibleSeriesKey
|
|
7167
|
+
visibleSeriesKey: stops.key
|
|
6505
7168
|
});
|
|
6506
7169
|
const handlePointerMove = useCallback(({ key, index }) => {
|
|
6507
|
-
const
|
|
6508
|
-
if (
|
|
6509
|
-
}, [
|
|
7170
|
+
const stop = stopOf(key, index);
|
|
7171
|
+
if (stop !== void 0) onChartPointerMove(stop);
|
|
7172
|
+
}, [stopOf, onChartPointerMove]);
|
|
6510
7173
|
const comparisonEntries = useMemo(() => {
|
|
7174
|
+
if (isOverlap) return [];
|
|
6511
7175
|
const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
|
|
6512
7176
|
label: series.label,
|
|
6513
7177
|
index
|
|
@@ -6523,12 +7187,12 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6523
7187
|
entries.push({
|
|
6524
7188
|
series,
|
|
6525
7189
|
index,
|
|
6526
|
-
primaryKey: primary.label
|
|
6527
|
-
primaryIndex: primary.index
|
|
7190
|
+
primaryKey: primary.label
|
|
6528
7191
|
});
|
|
6529
7192
|
});
|
|
6530
7193
|
return entries;
|
|
6531
7194
|
}, [
|
|
7195
|
+
isOverlap,
|
|
6532
7196
|
seriesWithVisibility,
|
|
6533
7197
|
primaryEntries,
|
|
6534
7198
|
primaryKeys
|
|
@@ -6568,23 +7232,32 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6568
7232
|
chartOptions.yScale,
|
|
6569
7233
|
horizontal
|
|
6570
7234
|
]);
|
|
6571
|
-
const getBarBackground = useCallback((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ??
|
|
6572
|
-
data: dataSorted[index],
|
|
6573
|
-
index
|
|
6574
|
-
}).color, [
|
|
7235
|
+
const getBarBackground = useCallback((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? barColors[index] ?? "", [
|
|
6575
7236
|
withPatterns,
|
|
6576
|
-
|
|
6577
|
-
dataSorted,
|
|
7237
|
+
barColors,
|
|
6578
7238
|
chartId
|
|
6579
7239
|
]);
|
|
6580
|
-
const resolveComparisonFill = useCallback((entry) => withPatterns ? `url(#${getPatternId(chartId, entry.
|
|
6581
|
-
data: entry.series,
|
|
6582
|
-
index: entry.index
|
|
6583
|
-
}).color, [
|
|
7240
|
+
const resolveComparisonFill = useCallback((entry, datum) => withPatterns ? `url(#${getPatternId(chartId, entry.index)})` : datum.color ?? barColors[entry.index] ?? "", [
|
|
6584
7241
|
withPatterns,
|
|
6585
7242
|
chartId,
|
|
6586
|
-
|
|
7243
|
+
barColors
|
|
6587
7244
|
]);
|
|
7245
|
+
const renderOverlapTooltip = useCallback(({ tooltipData }) => {
|
|
7246
|
+
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
7247
|
+
if (!nearestDatum) return null;
|
|
7248
|
+
const datumByKey = tooltipData?.datumByKey ?? {};
|
|
7249
|
+
const categoryLabel = chartOptions.tooltip.labelFormatter(nearestDatum.label || (nearestDatum.date ? nearestDatum.date.getTime() : 0), 0, []);
|
|
7250
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
7251
|
+
className: bar_chart_module_default["bar-chart__tooltip"],
|
|
7252
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
7253
|
+
className: bar_chart_module_default["bar-chart__tooltip-header"],
|
|
7254
|
+
children: categoryLabel
|
|
7255
|
+
}), dataSorted.flatMap(({ label }) => {
|
|
7256
|
+
const datum = datumByKey[label]?.datum;
|
|
7257
|
+
return datum ? [/* @__PURE__ */ jsx(Fragment, { children: renderTooltipRow(label, formatReading(datum.value)) }, label)] : [];
|
|
7258
|
+
})]
|
|
7259
|
+
});
|
|
7260
|
+
}, [chartOptions.tooltip, dataSorted]);
|
|
6588
7261
|
const renderDefaultTooltip = useCallback(({ tooltipData }) => {
|
|
6589
7262
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
6590
7263
|
if (!nearestDatum) return null;
|
|
@@ -6659,26 +7332,24 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6659
7332
|
}
|
|
6660
7333
|
`;
|
|
6661
7334
|
}, [chartId]);
|
|
6662
|
-
const
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
const
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
stroke-width: 2px;
|
|
6676
|
-
}
|
|
6677
|
-
`;
|
|
7335
|
+
const overlapBandSlots = useMemo(() => overlapSlots && {
|
|
7336
|
+
keys: overlapSlots.slotKeys,
|
|
7337
|
+
slotOf: overlapSlots.slotOf
|
|
7338
|
+
}, [overlapSlots]);
|
|
7339
|
+
const selectedSlot = useMemo(() => getSelectedSlot(overlapSlots, selectedIndex), [overlapSlots, selectedIndex]);
|
|
7340
|
+
const selectedBar = useMemo(() => {
|
|
7341
|
+
if (overlapSlots) return selectedSlot;
|
|
7342
|
+
const bar = selectedIndex === void 0 ? void 0 : barAt(selectedIndex);
|
|
7343
|
+
return bar && isBarRendered(bar.datum) ? {
|
|
7344
|
+
data: [bar.datum],
|
|
7345
|
+
slotKey: bar.key,
|
|
7346
|
+
thickness: 1
|
|
7347
|
+
} : void 0;
|
|
6678
7348
|
}, [
|
|
7349
|
+
overlapSlots,
|
|
7350
|
+
selectedSlot,
|
|
6679
7351
|
selectedIndex,
|
|
6680
|
-
|
|
6681
|
-
chartId
|
|
7352
|
+
barAt
|
|
6682
7353
|
]);
|
|
6683
7354
|
const error = validateData$2(dataSorted);
|
|
6684
7355
|
const isDataValid = !error;
|
|
@@ -6699,7 +7370,6 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6699
7370
|
children: error
|
|
6700
7371
|
});
|
|
6701
7372
|
const gridVisibility = gridVisibilityProp ?? chartOptions.gridVisibility;
|
|
6702
|
-
const highlightedBarStyle = createKeyboardHighlightStyle();
|
|
6703
7373
|
const legendPosition = legend.position ?? "bottom";
|
|
6704
7374
|
const legendElement = showLegend && /* @__PURE__ */ jsx(Legend, {
|
|
6705
7375
|
orientation: legend.orientation ?? "horizontal",
|
|
@@ -6779,14 +7449,7 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6779
7449
|
tickValues: (horizontal ? void 0 : valueTicks) ?? chartOptions.axis.y.tickValues
|
|
6780
7450
|
})] })
|
|
6781
7451
|
}),
|
|
6782
|
-
withPatterns && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("defs", { children:
|
|
6783
|
-
data: seriesData,
|
|
6784
|
-
index
|
|
6785
|
-
}).color)) }), /* @__PURE__ */ jsx("style", { children: dataSorted.map((seriesData, index) => createPatternBorderStyle(index, getElementStyles({
|
|
6786
|
-
data: seriesData,
|
|
6787
|
-
index
|
|
6788
|
-
}).color)) })] }),
|
|
6789
|
-
highlightedBarStyle && /* @__PURE__ */ jsx("style", { children: highlightedBarStyle }),
|
|
7452
|
+
withPatterns && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("defs", { children: barColors.map((color, index) => renderPattern(index, color)) }), /* @__PURE__ */ jsx("style", { children: barColors.map((color, index) => createPatternBorderStyle(index, color)) })] }),
|
|
6790
7453
|
allSeriesHidden ? /* @__PURE__ */ jsx(SvgEmptyState, {
|
|
6791
7454
|
x: width / 2,
|
|
6792
7455
|
y: chartHeight / 2,
|
|
@@ -6804,30 +7467,22 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6804
7467
|
getElementStyles,
|
|
6805
7468
|
resolveFill: resolveComparisonFill
|
|
6806
7469
|
}),
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
}) : /* @__PURE__ */ jsx(BarGroup, {
|
|
6820
|
-
padding: groupPadding,
|
|
6821
|
-
children: primaryEntries.map(({ series: seriesData, index }) => /* @__PURE__ */ jsx(BarSeries, {
|
|
6822
|
-
dataKey: seriesData?.label,
|
|
6823
|
-
data: seriesData.data,
|
|
6824
|
-
yAccessor: chartOptions.accessors.yAccessor,
|
|
6825
|
-
xAccessor: chartOptions.accessors.xAccessor,
|
|
6826
|
-
colorAccessor: getBarBackground(index)
|
|
6827
|
-
}, seriesData?.label))
|
|
7470
|
+
/* @__PURE__ */ jsx(BarLayer, {
|
|
7471
|
+
chartId,
|
|
7472
|
+
overlapSlots,
|
|
7473
|
+
selectedBar,
|
|
7474
|
+
primaryEntries,
|
|
7475
|
+
primaryKeys,
|
|
7476
|
+
getBarBackground,
|
|
7477
|
+
barClassName,
|
|
7478
|
+
groupPadding,
|
|
7479
|
+
horizontal,
|
|
7480
|
+
xAccessor: chartOptions.accessors.xAccessor,
|
|
7481
|
+
yAccessor: chartOptions.accessors.yAccessor
|
|
6828
7482
|
}),
|
|
6829
7483
|
(withTooltips || onPointerDown || onPointerUp) && /* @__PURE__ */ jsx(BandTooltip, {
|
|
6830
|
-
keys: primaryKeys,
|
|
7484
|
+
keys: overlapSlots?.keys ?? primaryKeys,
|
|
7485
|
+
slots: overlapBandSlots,
|
|
6831
7486
|
groupPadding,
|
|
6832
7487
|
withTooltips,
|
|
6833
7488
|
onPointerDown,
|
|
@@ -6844,6 +7499,10 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6844
7499
|
...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6845
7500
|
})] })
|
|
6846
7501
|
}),
|
|
7502
|
+
withTooltips && selectedSlot && /* @__PURE__ */ jsx(SlotTooltipMembers, {
|
|
7503
|
+
members: selectedSlot.members,
|
|
7504
|
+
index: selectedSlot.index
|
|
7505
|
+
}),
|
|
6847
7506
|
withTooltips && /* @__PURE__ */ jsx(XYChartTooltip, {
|
|
6848
7507
|
tooltipPlacement,
|
|
6849
7508
|
tooltipAnchorTop,
|
|
@@ -6851,11 +7510,11 @@ const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, he
|
|
|
6851
7510
|
detectBounds: true,
|
|
6852
7511
|
snapTooltipToDatumX: true,
|
|
6853
7512
|
snapTooltipToDatumY: true,
|
|
6854
|
-
renderTooltip: renderTooltip || renderDefaultTooltip,
|
|
7513
|
+
renderTooltip: renderTooltip || (isOverlap ? renderOverlapTooltip : renderDefaultTooltip),
|
|
6855
7514
|
selectedIndex,
|
|
6856
7515
|
tooltipRef,
|
|
6857
7516
|
keyboardFocusedClassName: bar_chart_module_default["bar-chart__tooltip--keyboard-focused"],
|
|
6858
|
-
series:
|
|
7517
|
+
series: stops.series,
|
|
6859
7518
|
mode: "individual"
|
|
6860
7519
|
})
|
|
6861
7520
|
]
|
|
@@ -9219,7 +9878,7 @@ function warning(message) {
|
|
|
9219
9878
|
logged.add(message);
|
|
9220
9879
|
}
|
|
9221
9880
|
//#endregion
|
|
9222
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
9881
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
|
|
9223
9882
|
function useUpdateEffect(effect, deps) {
|
|
9224
9883
|
const mountedRef = useRef$1(false);
|
|
9225
9884
|
useEffect$1(() => {
|
|
@@ -10267,7 +10926,7 @@ function serializeStyles(args, registered, mergedProps) {
|
|
|
10267
10926
|
}
|
|
10268
10927
|
React["useInsertionEffect"] && React["useInsertionEffect"] || React.useLayoutEffect;
|
|
10269
10928
|
//#endregion
|
|
10270
|
-
//#region ../../../node_modules/.pnpm/@emotion+react@11.14.0_@types+react@
|
|
10929
|
+
//#region ../../../node_modules/.pnpm/@emotion+react@11.14.0_@types+react@19.3.0_react@19.3.0/node_modules/@emotion/react/dist/emotion-element-f0de968e.browser.esm.js
|
|
10271
10930
|
var EmotionCacheContext = /* #__PURE__ */ React.createContext(typeof HTMLElement !== "undefined" ? /* #__PURE__ */ createCache({ key: "css" }) : null);
|
|
10272
10931
|
EmotionCacheContext.Provider;
|
|
10273
10932
|
var __unsafe_useEmotionCache = function useEmotionCache() {
|
|
@@ -10374,7 +11033,7 @@ _createEmotion.css;
|
|
|
10374
11033
|
_createEmotion.sheet;
|
|
10375
11034
|
_createEmotion.cache;
|
|
10376
11035
|
//#endregion
|
|
10377
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11036
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
|
|
10378
11037
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
10379
11038
|
var useCx = () => {
|
|
10380
11039
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -10481,7 +11140,7 @@ function memize(fn, options) {
|
|
|
10481
11140
|
return memoized;
|
|
10482
11141
|
}
|
|
10483
11142
|
//#endregion
|
|
10484
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11143
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
10485
11144
|
var import_es6 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
10486
11145
|
module.exports = function equal(a, b) {
|
|
10487
11146
|
if (a === b) return true;
|
|
@@ -10549,18 +11208,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
10549
11208
|
};
|
|
10550
11209
|
memo(BaseContextSystemProvider);
|
|
10551
11210
|
//#endregion
|
|
10552
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11211
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/constants.mjs
|
|
10553
11212
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
10554
11213
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
10555
11214
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
10556
11215
|
//#endregion
|
|
10557
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11216
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
|
|
10558
11217
|
function getStyledClassName(namespace) {
|
|
10559
11218
|
return `components-${paramCase(namespace)}`;
|
|
10560
11219
|
}
|
|
10561
11220
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
10562
11221
|
//#endregion
|
|
10563
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11222
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/context-connect.mjs
|
|
10564
11223
|
function contextConnect(Component, namespace) {
|
|
10565
11224
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
10566
11225
|
}
|
|
@@ -10577,7 +11236,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
10577
11236
|
});
|
|
10578
11237
|
}
|
|
10579
11238
|
//#endregion
|
|
10580
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11239
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/utils.mjs
|
|
10581
11240
|
function getNamespace(componentName) {
|
|
10582
11241
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
10583
11242
|
}
|
|
@@ -10585,7 +11244,7 @@ function getConnectedNamespace() {
|
|
|
10585
11244
|
return { [CONNECTED_NAMESPACE]: true };
|
|
10586
11245
|
}
|
|
10587
11246
|
//#endregion
|
|
10588
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11247
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
|
|
10589
11248
|
function useContextSystem(props, namespace) {
|
|
10590
11249
|
const contextSystemProps = useComponentsContext();
|
|
10591
11250
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -10607,7 +11266,7 @@ function useContextSystem(props, namespace) {
|
|
|
10607
11266
|
return finalComponentProps;
|
|
10608
11267
|
}
|
|
10609
11268
|
//#endregion
|
|
10610
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11269
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
|
|
10611
11270
|
var visuallyHidden = {
|
|
10612
11271
|
border: 0,
|
|
10613
11272
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -10623,7 +11282,7 @@ var visuallyHidden = {
|
|
|
10623
11282
|
wordBreak: "normal"
|
|
10624
11283
|
};
|
|
10625
11284
|
//#endregion
|
|
10626
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11285
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
|
|
10627
11286
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
10628
11287
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
10629
11288
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -10713,7 +11372,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
10713
11372
|
}
|
|
10714
11373
|
var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
|
|
10715
11374
|
//#endregion
|
|
10716
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11375
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/view/component.mjs
|
|
10717
11376
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
10718
11377
|
return /* @__PURE__ */ jsx(PolymorphicElement, {
|
|
10719
11378
|
ref,
|
|
@@ -10722,7 +11381,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
10722
11381
|
}
|
|
10723
11382
|
var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
|
|
10724
11383
|
//#endregion
|
|
10725
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11384
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
|
|
10726
11385
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
10727
11386
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
10728
11387
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -10737,7 +11396,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
10737
11396
|
}
|
|
10738
11397
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
10739
11398
|
//#endregion
|
|
10740
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11399
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
|
|
10741
11400
|
var breakpoints = [
|
|
10742
11401
|
"40em",
|
|
10743
11402
|
"52em",
|
|
@@ -10776,7 +11435,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
10776
11435
|
return array[index >= array.length ? array.length - 1 : index];
|
|
10777
11436
|
}
|
|
10778
11437
|
//#endregion
|
|
10779
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11438
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/grid/utils.mjs
|
|
10780
11439
|
var ALIGNMENTS = {
|
|
10781
11440
|
bottom: {
|
|
10782
11441
|
alignItems: "flex-end",
|
|
@@ -10824,7 +11483,7 @@ function getAlignmentProps(alignment) {
|
|
|
10824
11483
|
return alignment ? ALIGNMENTS[alignment] ?? {} : {};
|
|
10825
11484
|
}
|
|
10826
11485
|
//#endregion
|
|
10827
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11486
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/grid/hook.mjs
|
|
10828
11487
|
var STYLE_HASH_ATTRIBUTE = "data-wp-hash";
|
|
10829
11488
|
function getRuntime() {
|
|
10830
11489
|
const globalScope = globalThis;
|
|
@@ -10969,7 +11628,7 @@ function useGrid(props) {
|
|
|
10969
11628
|
};
|
|
10970
11629
|
}
|
|
10971
11630
|
//#endregion
|
|
10972
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@
|
|
11631
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@42.0.0_@date-fns+tz@1.5.0_@types+react-dom@19.3.0_@types+react@19_6d0393a58a031b78f608040e2ecbe6e0/node_modules/@wordpress/components/build-module/grid/component.mjs
|
|
10973
11632
|
function UnconnectedGrid(props, forwardedRef) {
|
|
10974
11633
|
const gridProps = useGrid(props);
|
|
10975
11634
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -11576,51 +12235,6 @@ const PieSelectionOutput = ({ withTooltips, selectedIndex, selectedData, keyboar
|
|
|
11576
12235
|
] });
|
|
11577
12236
|
};
|
|
11578
12237
|
//#endregion
|
|
11579
|
-
//#region src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss
|
|
11580
|
-
var pie_keyboard_navigation_module_default = {
|
|
11581
|
-
"selected-ring__contrast": "a8ccharts-V2HDKq-selected-ring__contrast",
|
|
11582
|
-
"selected-ring__focus": "a8ccharts-V2HDKq-selected-ring__focus"
|
|
11583
|
-
};
|
|
11584
|
-
//#endregion
|
|
11585
|
-
//#region src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx
|
|
11586
|
-
/**
|
|
11587
|
-
* Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
|
|
11588
|
-
*
|
|
11589
|
-
* @param value - Any string.
|
|
11590
|
-
* @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
|
|
11591
|
-
*/
|
|
11592
|
-
const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
|
|
11593
|
-
/**
|
|
11594
|
-
* Marks the selected segment with a two-tone ring drawn inside its edge, so the SVG edge cannot cut it off.
|
|
11595
|
-
*
|
|
11596
|
-
* @param {SelectedSegmentRingProps} props - Component props
|
|
11597
|
-
* @return {JSX.Element} The ring
|
|
11598
|
-
*/
|
|
11599
|
-
const SelectedSegmentRing = ({ chartId, d }) => {
|
|
11600
|
-
const clipId = `pie-selected-ring-clip-${toSvgId(chartId)}`;
|
|
11601
|
-
const clipPath = `url(#${clipId})`;
|
|
11602
|
-
return /* @__PURE__ */ jsxs("g", {
|
|
11603
|
-
pointerEvents: "none",
|
|
11604
|
-
"aria-hidden": "true",
|
|
11605
|
-
children: [
|
|
11606
|
-
/* @__PURE__ */ jsx("clipPath", {
|
|
11607
|
-
id: clipId,
|
|
11608
|
-
children: /* @__PURE__ */ jsx("path", { d })
|
|
11609
|
-
}),
|
|
11610
|
-
/* @__PURE__ */ jsx("path", {
|
|
11611
|
-
d,
|
|
11612
|
-
clipPath,
|
|
11613
|
-
className: pie_keyboard_navigation_module_default["selected-ring__contrast"]
|
|
11614
|
-
}),
|
|
11615
|
-
/* @__PURE__ */ jsx("path", {
|
|
11616
|
-
d,
|
|
11617
|
-
clipPath,
|
|
11618
|
-
className: pie_keyboard_navigation_module_default["selected-ring__focus"]
|
|
11619
|
-
})
|
|
11620
|
-
]
|
|
11621
|
-
});
|
|
11622
|
-
};
|
|
11623
|
-
//#endregion
|
|
11624
12238
|
//#region src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
|
|
11625
12239
|
const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX, tooltipOffsetY }) => {
|
|
11626
12240
|
const chartRef = useRef(null);
|
|
@@ -11996,9 +12610,11 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
11996
12610
|
selectedArc && /* @__PURE__ */ jsx(Group, {
|
|
11997
12611
|
top: centerY,
|
|
11998
12612
|
left: centerX,
|
|
11999
|
-
children: /* @__PURE__ */ jsx(
|
|
12613
|
+
children: /* @__PURE__ */ jsx(SelectedRing, {
|
|
12000
12614
|
chartId,
|
|
12001
|
-
d: path(selectedArc) || ""
|
|
12615
|
+
d: path(selectedArc) || "",
|
|
12616
|
+
side: "inside",
|
|
12617
|
+
testId: "pie-selected-ring"
|
|
12002
12618
|
})
|
|
12003
12619
|
}),
|
|
12004
12620
|
!allSegmentsHidden && /* @__PURE__ */ jsxs(Group, {
|
|
@@ -12235,9 +12851,11 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12235
12851
|
selectedArc && /* @__PURE__ */ jsx(Group, {
|
|
12236
12852
|
top: height,
|
|
12237
12853
|
left: width / 2,
|
|
12238
|
-
children: /* @__PURE__ */ jsx(
|
|
12854
|
+
children: /* @__PURE__ */ jsx(SelectedRing, {
|
|
12239
12855
|
chartId,
|
|
12240
|
-
d: path(selectedArc) || ""
|
|
12856
|
+
d: path(selectedArc) || "",
|
|
12857
|
+
side: "inside",
|
|
12858
|
+
testId: "pie-selected-ring"
|
|
12241
12859
|
})
|
|
12242
12860
|
}),
|
|
12243
12861
|
!allSegmentsHidden && /* @__PURE__ */ jsxs(Group, {
|
|
@@ -12488,6 +13106,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
|
|
|
12488
13106
|
});
|
|
12489
13107
|
}
|
|
12490
13108
|
//#endregion
|
|
12491
|
-
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TooltipBox, TrendIndicator, XYChartTooltip, buildCalendarHeatmapData, buildMonthCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, useMonthCalendarHeatmapData, validateHexColor };
|
|
13109
|
+
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TooltipBox, TrendIndicator, XYChartTooltip, buildCalendarHeatmapData, buildMonthCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useBarColors, useBarLegendItems, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, useMonthCalendarHeatmapData, validateHexColor };
|
|
12492
13110
|
|
|
12493
13111
|
//# sourceMappingURL=index.js.map
|