@automattic/charts 3.2.0 → 4.0.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 +29 -0
- package/TOKENS.md +53 -58
- package/dist/index.cjs +1012 -542
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +72 -29
- package/dist/index.d.cts +151 -179
- package/dist/index.d.ts +151 -179
- package/dist/index.js +1013 -544
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/charts/area-chart/area-chart.tsx +39 -25
- package/src/charts/area-chart/test/area-chart.test.tsx +4 -33
- package/src/charts/area-chart/test/tick-placement.test.tsx +55 -0
- package/src/charts/area-chart/test/tooltip-resolution-branches.test.tsx +86 -0
- package/src/charts/area-chart/test/tooltip-resolution.test.tsx +69 -0
- package/src/charts/area-chart/types.ts +4 -7
- package/src/charts/bar-chart/bar-chart.tsx +2 -1
- package/src/charts/bar-chart/private/test/use-bar-chart-options-formatting.test.tsx +69 -0
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +27 -15
- package/src/charts/bar-list-chart/bar-list-chart.tsx +5 -0
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +33 -23
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +138 -182
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +46 -0
- package/src/charts/geo-chart/geo-chart.module.scss +1 -0
- package/src/charts/geo-chart/geo-chart.tsx +5 -10
- package/src/charts/geo-chart/test/geo-chart.test.tsx +2 -2
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +21 -16
- package/src/charts/heatmap-chart/heatmap-chart.tsx +45 -28
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +3 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +11 -4
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +51 -12
- package/src/charts/heatmap-chart/types.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts +3 -5
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +31 -19
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +27 -17
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +14 -0
- package/src/charts/leaderboard-chart/test/use-leaderboard-legend-items.test.tsx +2 -9
- package/src/charts/line-chart/line-chart.module.scss +10 -18
- package/src/charts/line-chart/line-chart.tsx +93 -24
- package/src/charts/line-chart/private/line-chart-annotation.tsx +18 -19
- package/src/charts/line-chart/test/default-tooltip-formatting.test.tsx +74 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +27 -3
- package/src/charts/line-chart/test/tick-placement.test.tsx +84 -0
- package/src/charts/line-chart/test/tooltip-resolution.test.tsx +140 -0
- package/src/charts/line-chart/types.ts +4 -1
- package/src/charts/pie-chart/pie-chart.module.scss +13 -1
- package/src/charts/pie-chart/pie-chart.tsx +30 -40
- package/src/charts/pie-chart/test/pie-chart.test.tsx +56 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +8 -3
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +23 -37
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +50 -0
- package/src/charts/private/chart-layout/chart-layout.module.scss +3 -2
- package/src/charts/private/svg-empty-state/svg-empty-state.module.scss +1 -1
- package/src/charts/private/test/axis-formatting.test.tsx +85 -0
- package/src/charts/private/test/time-axis-formatting.test.ts +109 -0
- package/src/charts/private/test/time-axis-options.test.ts +267 -0
- package/src/charts/private/test/time-axis-tick-invariants.test.ts +153 -0
- package/src/charts/private/test/time-axis-tick-values.test.ts +280 -0
- package/src/charts/private/test/time-axis.test.ts +9 -69
- package/src/charts/private/time-axis-options.ts +106 -0
- package/src/charts/private/time-axis.ts +318 -136
- package/src/charts/private/x-zoom/x-zoom.module.scss +3 -3
- package/src/charts/private/xy-plot/xy-plot.module.scss +8 -0
- package/src/charts/sparkline/test/sparkline.test.tsx +29 -56
- package/src/charts/sparkline/types.ts +1 -1
- package/src/components/legend/private/base-legend.module.scss +9 -5
- package/src/components/tooltip/accessible-tooltip.tsx +13 -15
- package/src/components/tooltip/base-tooltip.module.scss +3 -3
- package/src/components/tooltip/private/bounded-tooltip.tsx +172 -0
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +2 -3
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +129 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +279 -0
- package/src/components/tooltip/xy-chart-tooltip.tsx +288 -0
- package/src/components/trend-indicator/trend-indicator.module.scss +2 -2
- package/src/hooks/test/use-xychart-theme.test.tsx +16 -3
- package/src/hooks/use-xychart-theme.ts +25 -9
- package/src/index.ts +4 -0
- package/src/providers/chart-context/global-charts-provider.tsx +37 -38
- package/src/providers/chart-context/hooks/use-chart-formatting.ts +22 -0
- package/src/providers/chart-context/index.ts +1 -0
- package/src/providers/chart-context/private/catalog-pointers.ts +42 -0
- package/src/providers/chart-context/private/series-palette.ts +3 -13
- package/src/providers/chart-context/test/{sparse-theme.test.ts → catalog-pointers.test.ts} +22 -10
- package/src/providers/chart-context/test/chart-context.test.tsx +177 -792
- package/src/providers/chart-context/test/use-global-charts-theme.test.tsx +7 -25
- package/src/providers/chart-context/themes.ts +7 -52
- package/src/providers/chart-context/types.ts +3 -0
- package/src/styles/chart-scope.scss +39 -62
- package/src/styles/test/chart-scope.test.ts +19 -47
- package/src/test-utils/series-fixtures.ts +31 -0
- package/src/types.ts +79 -166
- package/src/utils/bucket-info.ts +87 -0
- package/src/utils/color-utils.ts +0 -27
- package/src/utils/date-formatting.ts +174 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/test/bucket-info.test.ts +185 -0
- package/src/utils/test/color-utils.test.ts +1 -48
- package/src/utils/test/date-formatting.test.ts +89 -0
- package/src/utils/test/get-styles.test.ts +10 -7
- package/src/utils/test/merge-themes.test.ts +18 -46
- package/src/visx/types.ts +29 -2
- package/src/hooks/test/use-xychart-theme-provider-override.test.tsx +0 -28
- package/src/providers/chart-context/private/theme-override-vars.ts +0 -131
- package/src/providers/chart-context/private/with-catalog-pointers.ts +0 -93
- package/src/providers/chart-context/test/theme-override-vars-guard.test.tsx +0 -29
- package/src/providers/chart-context/test/theme-override-vars.test.ts +0 -183
- package/src/providers/chart-context/test/with-catalog-pointers.test.ts +0 -104
- package/src/styles/test/wpds-fallbacks.test.ts +0 -131
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getStringWidth as getStringWidth$1 } from "./visx/text/index.js";
|
|
2
2
|
import { formatNumber, formatNumberCompact } from "@automattic/number-formatters";
|
|
3
|
-
import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid,
|
|
3
|
+
import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, TooltipContext, XYChart, buildChartTheme } from "@visx/xychart";
|
|
4
4
|
import { __, _x, sprintf } from "@wordpress/i18n";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import * as React from "react";
|
|
@@ -10,11 +10,12 @@ import { addDays, differenceInCalendarWeeks, differenceInHours, differenceInYear
|
|
|
10
10
|
import { Text, getStringWidth } from "@visx/text";
|
|
11
11
|
import deepmerge from "deepmerge";
|
|
12
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
13
|
+
import { Tooltip, defaultStyles, useTooltip } from "@visx/tooltip";
|
|
14
14
|
import { createScale, getTicks, scaleBand, scaleOrdinal, scaleTime } from "@visx/scale";
|
|
15
15
|
import { Group } from "@visx/group";
|
|
16
16
|
import { LegendItem, LegendLabel, LegendOrdinal, LegendShape } from "@visx/legend";
|
|
17
17
|
import { IconButton, Stack, Text as Text$1 } from "@wordpress/ui";
|
|
18
|
+
import { createPortal } from "react-dom";
|
|
18
19
|
import { LinearGradient } from "@visx/gradient";
|
|
19
20
|
import { curveCatmullRom, curveLinear, curveMonotoneX } from "@visx/curve";
|
|
20
21
|
import { useParentSize } from "@visx/responsive";
|
|
@@ -172,6 +173,39 @@ const parseAsLocalDate = (dateString) => {
|
|
|
172
173
|
return /* @__PURE__ */ new Date(NaN);
|
|
173
174
|
};
|
|
174
175
|
//#endregion
|
|
176
|
+
//#region src/utils/bucket-info.ts
|
|
177
|
+
const getInstant = (point) => {
|
|
178
|
+
if (!point) return;
|
|
179
|
+
if ("date" in point && point.date) return point.date.getTime();
|
|
180
|
+
if ("dateString" in point && point.dateString) return parseAsLocalDate(point.dateString).getTime();
|
|
181
|
+
};
|
|
182
|
+
const getPointSpacingInHours = (data) => {
|
|
183
|
+
return data.reduce((spacing, datom) => {
|
|
184
|
+
const instants = [...new Set(datom.data.map((point) => getInstant(point)))].filter((time) => time !== void 0 && Number.isFinite(time)).sort((a, b) => a - b);
|
|
185
|
+
return instants.reduce((seriesSpacing, time, index) => index === 0 ? seriesSpacing : Math.min(seriesSpacing, Math.abs(differenceInHours(time, instants[index - 1]))), spacing);
|
|
186
|
+
}, Number.POSITIVE_INFINITY);
|
|
187
|
+
};
|
|
188
|
+
const SUB_DAILY_SPACING_HOURS = 23;
|
|
189
|
+
const MONTHLY_SPACING_HOURS = 672;
|
|
190
|
+
const getBucketResolution = (data, tickResolution) => {
|
|
191
|
+
if (tickResolution) return tickResolution === "week" ? "day" : tickResolution;
|
|
192
|
+
const spacingInHours = getPointSpacingInHours(data);
|
|
193
|
+
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
194
|
+
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
195
|
+
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* How this data was classified, for consumers that render their own labels.
|
|
199
|
+
*
|
|
200
|
+
* @param data - The series the chart draws, in any order, dated by `date` or `dateString`.
|
|
201
|
+
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
202
|
+
* @return The declared or inferred bucket, and the resolution formats key on.
|
|
203
|
+
*/
|
|
204
|
+
const getBucketInfo = (data, tickResolution) => ({
|
|
205
|
+
bucket: tickResolution ?? getBucketResolution(data),
|
|
206
|
+
displayResolution: getBucketResolution(data, tickResolution)
|
|
207
|
+
});
|
|
208
|
+
//#endregion
|
|
175
209
|
//#region src/utils/format-metric-value.ts
|
|
176
210
|
/**
|
|
177
211
|
* Format a numeric metric value based on type, precision and scale.
|
|
@@ -384,20 +418,6 @@ const parseHslString = (hslString) => {
|
|
|
384
418
|
];
|
|
385
419
|
};
|
|
386
420
|
/**
|
|
387
|
-
* Parse an RGB string like 'rgb(255, 0, 0)' into a hex color.
|
|
388
|
-
*
|
|
389
|
-
* @deprecated Use normalizeColorToHex() instead, which handles all color formats including rgb() and rgba().
|
|
390
|
-
* @param rgbString - RGB color string (not RGBA)
|
|
391
|
-
* @return hex color string or null if invalid
|
|
392
|
-
*/
|
|
393
|
-
const parseRgbString = (rgbString) => {
|
|
394
|
-
const lower = rgbString.toLowerCase().trim();
|
|
395
|
-
if (!lower.startsWith("rgb(") || lower.startsWith("rgba(")) return null;
|
|
396
|
-
const parsed = color(lower);
|
|
397
|
-
if (!parsed) return null;
|
|
398
|
-
return parsed.formatHex();
|
|
399
|
-
};
|
|
400
|
-
/**
|
|
401
421
|
* Normalize any CSS color value to a hex color string.
|
|
402
422
|
* Handles hex, HSL, HSLA, RGB, RGBA, named CSS colors, and CSS variables.
|
|
403
423
|
*
|
|
@@ -625,6 +645,112 @@ const resolveFontSize = (val) => {
|
|
|
625
645
|
}
|
|
626
646
|
};
|
|
627
647
|
//#endregion
|
|
648
|
+
//#region src/utils/date-formatting.ts
|
|
649
|
+
const formatters = /* @__PURE__ */ new Map();
|
|
650
|
+
const getFormatter$1 = (options, { locale, timeZone }) => {
|
|
651
|
+
const key = `${locale ?? ""}|${timeZone ?? ""}|${JSON.stringify(options)}`;
|
|
652
|
+
let formatter = formatters.get(key);
|
|
653
|
+
if (!formatter) {
|
|
654
|
+
formatter = new Intl.DateTimeFormat(locale, {
|
|
655
|
+
...options,
|
|
656
|
+
timeZone
|
|
657
|
+
});
|
|
658
|
+
formatters.set(key, formatter);
|
|
659
|
+
}
|
|
660
|
+
return formatter;
|
|
661
|
+
};
|
|
662
|
+
const warned = /* @__PURE__ */ new Set();
|
|
663
|
+
const warnOnce = (key, message) => {
|
|
664
|
+
if (warned.has(key) || process.env.NODE_ENV === "production") return;
|
|
665
|
+
warned.add(key);
|
|
666
|
+
console.warn(`[Charts] ${message}`);
|
|
667
|
+
};
|
|
668
|
+
const isUsable = (formatting) => {
|
|
669
|
+
try {
|
|
670
|
+
Intl.DateTimeFormat(formatting.locale, { timeZone: formatting.timeZone });
|
|
671
|
+
return true;
|
|
672
|
+
} catch {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
const toBcp47 = (locale) => locale?.replace(/_/g, "-");
|
|
677
|
+
/**
|
|
678
|
+
* Repairs a host locale for `Intl`, dropping either half it still cannot use.
|
|
679
|
+
*
|
|
680
|
+
* Every formatter below is built during render, so an unusable string would throw
|
|
681
|
+
* where React unmounts the whole host tree rather than one chart. WordPress hands
|
|
682
|
+
* out the likeliest one either way: `timezone_string` is `''` on a site set to a
|
|
683
|
+
* raw UTC offset, and has no repair.
|
|
684
|
+
*
|
|
685
|
+
* @param formatting - Locale and time zone as the host supplied them.
|
|
686
|
+
* @return The usable halves, each `undefined` where the host's value was not.
|
|
687
|
+
*/
|
|
688
|
+
const sanitizeFormatting = (formatting) => {
|
|
689
|
+
const repaired = {
|
|
690
|
+
...formatting,
|
|
691
|
+
locale: toBcp47(formatting.locale)
|
|
692
|
+
};
|
|
693
|
+
if (isUsable(repaired)) return repaired;
|
|
694
|
+
const locale = isUsable({ locale: repaired.locale }) ? repaired.locale : void 0;
|
|
695
|
+
const timeZone = isUsable({ timeZone: repaired.timeZone }) ? repaired.timeZone : void 0;
|
|
696
|
+
if (locale === void 0 && formatting.locale !== void 0) warnOnce(`locale:${formatting.locale}`, `locale ${JSON.stringify(formatting.locale)} is not a BCP-47 tag Intl accepts, so dates render in the browser's locale.`);
|
|
697
|
+
if (timeZone === void 0 && formatting.timeZone !== void 0) warnOnce(`timeZone:${formatting.timeZone}`, `timeZone ${JSON.stringify(formatting.timeZone)} is not a zone Intl accepts, so dates render in the browser's zone. Pass an IANA name or a UTC offset such as "+05:30".`);
|
|
698
|
+
return {
|
|
699
|
+
locale,
|
|
700
|
+
timeZone
|
|
701
|
+
};
|
|
702
|
+
};
|
|
703
|
+
/**
|
|
704
|
+
* A date formatter bound to the host's locale and time zone.
|
|
705
|
+
*
|
|
706
|
+
* @param options - Date-part options, as for `Intl.DateTimeFormat`.
|
|
707
|
+
* @param formatting - Host locale and time zone; either half absent leaves the runtime's own.
|
|
708
|
+
* @return Formatter taking a timestamp or a `Date`.
|
|
709
|
+
*/
|
|
710
|
+
const createDateFormatter = (options, formatting) => {
|
|
711
|
+
return (value) => {
|
|
712
|
+
if (!Number.isFinite(Number(value))) return new Date(Number(value)).toLocaleDateString();
|
|
713
|
+
return getFormatter$1(options, formatting).format(value);
|
|
714
|
+
};
|
|
715
|
+
};
|
|
716
|
+
const CLOCK_OPTIONS = {
|
|
717
|
+
month: "numeric",
|
|
718
|
+
hour: "numeric",
|
|
719
|
+
hourCycle: "h23"
|
|
720
|
+
};
|
|
721
|
+
const NO_FIELDS = {
|
|
722
|
+
month: NaN,
|
|
723
|
+
hour: NaN
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* A clock reading calendar fields in the host's time zone.
|
|
727
|
+
*
|
|
728
|
+
* `Date`'s own getters read the browser's zone, so a chart viewed from another
|
|
729
|
+
* country anchors its ticks to the wrong midnights and the wrong January
|
|
730
|
+
* without this.
|
|
731
|
+
*
|
|
732
|
+
* @param timeZone - IANA zone name; absent leaves the runtime's own.
|
|
733
|
+
* @return Reader taking a `Date`.
|
|
734
|
+
*/
|
|
735
|
+
const createZonedClock = (timeZone) => {
|
|
736
|
+
if (!timeZone) return (date) => ({
|
|
737
|
+
month: date.getMonth() + 1,
|
|
738
|
+
hour: date.getHours()
|
|
739
|
+
});
|
|
740
|
+
return (date) => {
|
|
741
|
+
if (!Number.isFinite(Number(date))) return NO_FIELDS;
|
|
742
|
+
const parts = getFormatter$1(CLOCK_OPTIONS, {
|
|
743
|
+
locale: "en-US",
|
|
744
|
+
timeZone
|
|
745
|
+
}).formatToParts(date);
|
|
746
|
+
const read = (type) => Number(parts.find((part) => part.type === type)?.value);
|
|
747
|
+
return {
|
|
748
|
+
month: read("month"),
|
|
749
|
+
hour: read("hour")
|
|
750
|
+
};
|
|
751
|
+
};
|
|
752
|
+
};
|
|
753
|
+
//#endregion
|
|
628
754
|
//#region src/providers/chart-scope/chart-scope-context.ts
|
|
629
755
|
/**
|
|
630
756
|
* The nearest chart element, published so JS token resolution reads the same CSS cascade that paints the chart's own colours.
|
|
@@ -772,150 +898,29 @@ const SERIES_SLOT_1_FALLBACK = "#3858e9";
|
|
|
772
898
|
/** The catalog pointer for every slot, in slot order. */
|
|
773
899
|
const SERIES_PALETTE_POINTERS = Array.from({ length: 5 }, (_, index) => index === 0 ? `var(${seriesRole(1)}, ${SERIES_SLOT_1_FALLBACK})` : `var(${seriesRole(index + 1)})`);
|
|
774
900
|
//#endregion
|
|
775
|
-
//#region src/providers/chart-context/private/theme-override-vars.ts
|
|
776
|
-
const ROLE_FOR_FIELD = [
|
|
777
|
-
["--a8c-charts-color-background", (theme) => theme.backgroundColor],
|
|
778
|
-
["--a8c-charts-color-grid", (theme) => theme.gridStyles?.stroke],
|
|
779
|
-
["--a8c-charts-color-axis", (theme) => theme.xAxisLineStyles?.stroke],
|
|
780
|
-
["--a8c-charts-color-tick", (theme) => theme.xTickLineStyles?.stroke],
|
|
781
|
-
["--a8c-charts-color-label-axis", (theme) => theme.svgLabelSmall?.fill],
|
|
782
|
-
["--a8c-charts-color-label-background", (theme) => theme.labelBackgroundColor],
|
|
783
|
-
["--a8c-charts-color-label-on-fill", (theme) => theme.labelTextColor],
|
|
784
|
-
...Array.from({ length: 5 }, (_, index) => [seriesRole(index + 1), (theme) => theme.colors?.[index]])
|
|
785
|
-
];
|
|
786
|
-
let warnedAboutExtraColors = false;
|
|
787
|
-
/**
|
|
788
|
-
* Warns once when a consumer passes more colors than there are slots to publish them into.
|
|
789
|
-
*
|
|
790
|
-
* @param count - How many entries `theme.colors` holds.
|
|
791
|
-
*/
|
|
792
|
-
function warnOnceAboutExtraColors(count) {
|
|
793
|
-
if (warnedAboutExtraColors || process.env.NODE_ENV === "production") return;
|
|
794
|
-
warnedAboutExtraColors = true;
|
|
795
|
-
console.warn(`[Charts] theme.colors holds ${count} colors and the palette has 5 slots, so entries past the 5th are ignored. Set a per-series color with \`options.stroke\` instead.`);
|
|
796
|
-
}
|
|
797
|
-
/**
|
|
798
|
-
* The variable a `theme` prop override is published as, one layer outside the role itself.
|
|
799
|
-
*
|
|
800
|
-
* `chart-scope.scss` declares each of these roles as `var(<role>-theme, <catalog default>)`, so an override that is invalid at computed-value time — a fallback-less `var()` naming a token the host never set — only invalidates this variable, and the role still resolves its mapped `--wpds-*` token. Published as the role directly, such a value took the role and every bare `var(<role>)` read site down with it.
|
|
801
|
-
*
|
|
802
|
-
* @param role - The catalog role being overridden.
|
|
803
|
-
* @return The custom property carrying the consumer's value.
|
|
804
|
-
*/
|
|
805
|
-
const themeLayerVar = (role) => `${role}-theme`;
|
|
806
|
-
ROLE_FOR_FIELD.map(([role]) => role);
|
|
807
|
-
/**
|
|
808
|
-
* Whether a value reads the role it is being published for, which would make the catalog entry depend on itself.
|
|
809
|
-
*
|
|
810
|
-
* The dependency runs `<role>: var(<role>-theme, …)`, so a value naming `<role>` closes a cycle through the catalog entry. CSS marks every custom property in a cycle invalid at computed-value time — the role's own fallback is *not* used, so the token resolves to nothing and every chart loses that color. Verified in Chrome: `--role-theme: var(--role, blue); --role: var(--role-theme, green)` leaves `--role` empty, not `green`.
|
|
811
|
-
*
|
|
812
|
-
* Three things this has to get right, none of which a plain substring test gets:
|
|
813
|
-
*
|
|
814
|
-
* `var()` permits whitespace after the opening paren, so testing for `var(<role>` misses `var( --a8c-charts-color-grid, … )`.
|
|
815
|
-
*
|
|
816
|
-
* Several roles are prefixes of others (`--a8c-charts-color-label` of `--a8c-charts-color-label-secondary`), and every role is a prefix of its own theme layer. A prefix match would read a legitimate cross-role pointer as a self-reference and silently drop the override, so the role must be followed by something that cannot continue an identifier — `-` included. A value naming `<role>-theme` is therefore not treated as a self-reference: that cycle is confined to the theme layer, which leaves the role free to fall back to the catalog default.
|
|
817
|
-
*
|
|
818
|
-
* `resolveCssVariable` also accepts a bare custom-property name with no `var()` wrapper (`--a8c-charts-color-grid`), so that is legal `theme` input too. It forms no cycle — custom properties accept arbitrary token streams — so it survives as a literal string and drops silently at the use site instead of falling back to the catalog default.
|
|
819
|
-
*
|
|
820
|
-
* @param value - The consumer's value for the field.
|
|
821
|
-
* @param role - The catalog role this value would override.
|
|
822
|
-
* @return True when the value reads `role`, so it must not be published.
|
|
823
|
-
*/
|
|
824
|
-
const readsOwnRole = (value, role) => value.trim() === role || new RegExp(`var\\(\\s*${role.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(value);
|
|
825
|
-
/**
|
|
826
|
-
* Maps a sparse consumer theme onto the theme-layer variables its overridden catalog roles read, so CSS-painted and JS-resolved colors read one source.
|
|
827
|
-
*
|
|
828
|
-
* A value that reads the role it would override is left unpublished — that is the default theme's own pointer surviving `mergeThemes`, and publishing it would invalidate the role. The role is still reported in `roles`: `withCatalogPointers` restores its theme field to the catalog pointer either way, so CSS and visx agree on the catalog default rather than visx painting a literal CSS never sees.
|
|
829
|
-
*
|
|
830
|
-
* `theme.colors` publishes through the same mechanism, one slot per entry, so a CSS declaration of `--a8c-charts-color-series-N` still beats it and a short array leaves the later slots unset rather than blank.
|
|
831
|
-
*
|
|
832
|
-
* @param theme - The consumer's `theme` prop, before merging with the default theme.
|
|
833
|
-
* @return The wrapper's custom properties, and the roles the consumer overrode.
|
|
834
|
-
*/
|
|
835
|
-
const themeOverrideVars = (theme) => {
|
|
836
|
-
if (!theme) return {
|
|
837
|
-
vars: {},
|
|
838
|
-
roles: []
|
|
839
|
-
};
|
|
840
|
-
if (Array.isArray(theme.colors) && theme.colors.length > 5) warnOnceAboutExtraColors(theme.colors.length);
|
|
841
|
-
const vars = {};
|
|
842
|
-
const roles = [];
|
|
843
|
-
for (const [role, read] of ROLE_FOR_FIELD) {
|
|
844
|
-
const value = read(theme);
|
|
845
|
-
if (typeof value !== "string" || value === "") continue;
|
|
846
|
-
roles.push(role);
|
|
847
|
-
if (!readsOwnRole(value, role)) vars[themeLayerVar(role)] = value;
|
|
848
|
-
}
|
|
849
|
-
return {
|
|
850
|
-
vars,
|
|
851
|
-
roles
|
|
852
|
-
};
|
|
853
|
-
};
|
|
854
|
-
//#endregion
|
|
855
901
|
//#region src/providers/chart-context/themes.ts
|
|
856
902
|
/**
|
|
857
|
-
* Default theme configuration
|
|
903
|
+
* Default theme configuration: the shape and spacing a consumer can override.
|
|
904
|
+
*
|
|
905
|
+
* For a color, set the matching `--a8c-charts-color-*` role in CSS instead; the `var()`
|
|
906
|
+
* chains that deliver those live in `private/catalog-pointers.ts`.
|
|
858
907
|
*/
|
|
859
908
|
const defaultTheme = {
|
|
860
|
-
|
|
861
|
-
labelBackgroundColor: "var(--a8c-charts-color-label-background, transparent)",
|
|
862
|
-
labelTextColor: "var(--a8c-charts-color-label-on-fill, #FFFFFF)",
|
|
863
|
-
colors: [...SERIES_PALETTE_POINTERS],
|
|
864
|
-
gridStyles: {
|
|
865
|
-
stroke: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
866
|
-
strokeWidth: 1
|
|
867
|
-
},
|
|
909
|
+
gridStyles: { strokeWidth: 1 },
|
|
868
910
|
tickLength: 4,
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
xTickLineStyles: {
|
|
872
|
-
stroke: "var(--a8c-charts-color-tick, #dbdbdb)",
|
|
873
|
-
strokeWidth: 1
|
|
874
|
-
},
|
|
875
|
-
xAxisLineStyles: {
|
|
876
|
-
stroke: "var(--a8c-charts-color-axis, #dbdbdb)",
|
|
877
|
-
strokeWidth: 1
|
|
878
|
-
},
|
|
911
|
+
xTickLineStyles: { strokeWidth: 1 },
|
|
912
|
+
xAxisLineStyles: { strokeWidth: 1 },
|
|
879
913
|
legend: {
|
|
880
|
-
labelStyles: {
|
|
914
|
+
labelStyles: {},
|
|
881
915
|
containerStyles: {},
|
|
882
916
|
shapeStyles: []
|
|
883
917
|
},
|
|
884
918
|
seriesLineStyles: [],
|
|
885
919
|
glyphs: [],
|
|
886
|
-
svgLabelSmall: {
|
|
887
|
-
fill: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
888
|
-
fontFamily: "inherit"
|
|
889
|
-
},
|
|
920
|
+
svgLabelSmall: { fontFamily: "inherit" },
|
|
890
921
|
svgLabelBig: { fontFamily: "inherit" },
|
|
891
|
-
annotationStyles: {
|
|
892
|
-
|
|
893
|
-
anchorLineStroke: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
894
|
-
backgroundFill: "var(--a8c-charts-color-surface, #fff)"
|
|
895
|
-
},
|
|
896
|
-
connector: { stroke: "var(--a8c-charts-color-annotation, #1e1e1e)" },
|
|
897
|
-
circleSubject: {
|
|
898
|
-
stroke: "transparent",
|
|
899
|
-
fill: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
900
|
-
radius: 5
|
|
901
|
-
}
|
|
902
|
-
},
|
|
903
|
-
geoChart: { featureFillColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)" },
|
|
904
|
-
leaderboardChart: {
|
|
905
|
-
rowGap: 12,
|
|
906
|
-
columnGap: 4,
|
|
907
|
-
labelSpacing: "xs",
|
|
908
|
-
deltaColors: [
|
|
909
|
-
"var(--a8c-charts-color-trend-down, #cc1818)",
|
|
910
|
-
"var(--a8c-charts-color-trend-neutral, #707070)",
|
|
911
|
-
"var(--a8c-charts-color-trend-up, #008030)"
|
|
912
|
-
]
|
|
913
|
-
},
|
|
914
|
-
conversionFunnelChart: {
|
|
915
|
-
backgroundColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
916
|
-
positiveChangeColor: "var(--a8c-charts-color-trend-up, #008030)",
|
|
917
|
-
negativeChangeColor: "var(--a8c-charts-color-trend-down, #cc1818)"
|
|
918
|
-
},
|
|
922
|
+
annotationStyles: {},
|
|
923
|
+
leaderboardChart: { labelSpacing: "xs" },
|
|
919
924
|
lineChart: { lineStyles: { comparison: {
|
|
920
925
|
strokeDasharray: "4 4",
|
|
921
926
|
strokeLinecap: "square"
|
|
@@ -939,70 +944,9 @@ const defaultTheme = {
|
|
|
939
944
|
}
|
|
940
945
|
};
|
|
941
946
|
//#endregion
|
|
942
|
-
//#region src/providers/chart-context/private/with-catalog-pointers.ts
|
|
943
|
-
/**
|
|
944
|
-
* The pointer one palette slot is restored to.
|
|
945
|
-
*
|
|
946
|
-
* Unlike the other roles, this keeps the consumer's own color as the pointer's terminal literal instead of the catalog's. The literal is only ever reached where `getComputedStyle` resolves nothing — SSR and jsdom — and there the palette is the one field where falling back to the catalog default would be visible: every series would paint the same seeded blue. In a browser the slot resolves first, so a CSS declaration of it still outranks the consumer's `theme.colors`.
|
|
947
|
-
*
|
|
948
|
-
* @param index - The slot's zero-based index in `colors`.
|
|
949
|
-
* @param value - The merged theme's entry for it.
|
|
950
|
-
* @return The catalog pointer for that slot.
|
|
951
|
-
*/
|
|
952
|
-
const seriesPointer = (index, value) => {
|
|
953
|
-
const role = seriesRole(index + 1);
|
|
954
|
-
if (typeof value === "string" && value.startsWith(`var(${role}`)) return value;
|
|
955
|
-
if (typeof value !== "string" || value === "") return SERIES_PALETTE_POINTERS[index];
|
|
956
|
-
return `var(${role}, ${value})`;
|
|
957
|
-
};
|
|
958
|
-
const CATALOG_RESTORE_FOR_ROLE = {
|
|
959
|
-
...Object.fromEntries(Array.from({ length: 5 }, (_, index) => [seriesRole(index + 1), (theme) => ({ colors: SERIES_PALETTE_POINTERS.map((_pointer, slot) => seriesPointer(slot, theme.colors?.[slot])) })])),
|
|
960
|
-
"--a8c-charts-color-background": () => ({ backgroundColor: defaultTheme.backgroundColor }),
|
|
961
|
-
"--a8c-charts-color-grid": (theme) => ({ gridStyles: {
|
|
962
|
-
...theme.gridStyles,
|
|
963
|
-
stroke: defaultTheme.gridStyles.stroke
|
|
964
|
-
} }),
|
|
965
|
-
"--a8c-charts-color-axis": (theme) => ({ xAxisLineStyles: {
|
|
966
|
-
...theme.xAxisLineStyles,
|
|
967
|
-
stroke: defaultTheme.xAxisLineStyles.stroke
|
|
968
|
-
} }),
|
|
969
|
-
"--a8c-charts-color-tick": (theme) => ({ xTickLineStyles: {
|
|
970
|
-
...theme.xTickLineStyles,
|
|
971
|
-
stroke: defaultTheme.xTickLineStyles.stroke
|
|
972
|
-
} }),
|
|
973
|
-
"--a8c-charts-color-label-axis": (theme) => ({ svgLabelSmall: {
|
|
974
|
-
...theme.svgLabelSmall,
|
|
975
|
-
fill: defaultTheme.svgLabelSmall.fill
|
|
976
|
-
} }),
|
|
977
|
-
"--a8c-charts-color-label-background": () => ({ labelBackgroundColor: defaultTheme.labelBackgroundColor }),
|
|
978
|
-
"--a8c-charts-color-label-on-fill": () => ({ labelTextColor: defaultTheme.labelTextColor })
|
|
979
|
-
};
|
|
980
|
-
/**
|
|
981
|
-
* Restores the mapped theme fields of `overriddenRoles` to their catalog pointer, so the theme-layer variable `themeOverrideVars` writes on the provider wrapper is the only carrier for an overridden role — CSS and the JS bridge (`useXYChartTheme`) then resolve it through the same cascade instead of visx reading a baked literal that can disagree with a closer CSS override.
|
|
982
|
-
*
|
|
983
|
-
* This covers roles `themeOverrideVars` deliberately left unpublished as well as the ones it published. A value that reads its own role is not publishable, but leaving visx the consumer's literal is what the whole mechanism exists to prevent: `theme={ { gridStyles: { stroke: 'var(--brand, var(--a8c-charts-color-grid, red))' } } }` would have CSS paint the catalog default while visx painted `--brand`.
|
|
984
|
-
*
|
|
985
|
-
* Every field outside the mapped roles is left exactly as `merged` provided it: those aren't published as theme-layer vars, so rewriting them would erase a consumer's override with no replacement carrier.
|
|
986
|
-
*
|
|
987
|
-
* @param merged - The consumer theme merged onto `defaultTheme` (`mergeThemes` output).
|
|
988
|
-
* @param overriddenRoles - The catalog roles the consumer overrode, from `themeOverrideVars`.
|
|
989
|
-
* @return A new theme object; `merged` is not mutated.
|
|
990
|
-
*/
|
|
991
|
-
const withCatalogPointers = (merged, overriddenRoles) => {
|
|
992
|
-
let result = merged;
|
|
993
|
-
for (const role of overriddenRoles) {
|
|
994
|
-
const restore = CATALOG_RESTORE_FOR_ROLE[role];
|
|
995
|
-
if (restore) result = {
|
|
996
|
-
...result,
|
|
997
|
-
...restore(result)
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
return result;
|
|
1001
|
-
};
|
|
1002
|
-
//#endregion
|
|
1003
947
|
//#region src/providers/chart-context/global-charts-provider.tsx
|
|
1004
948
|
const GlobalChartsContext = createContext(null);
|
|
1005
|
-
const GlobalChartsProvider = ({ children, theme }) => {
|
|
949
|
+
const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
1006
950
|
const [charts, setCharts] = useState(() => /* @__PURE__ */ new Map());
|
|
1007
951
|
const [hiddenSeries, setHiddenSeries] = useState(() => /* @__PURE__ */ new Map());
|
|
1008
952
|
const seededCharts = useRef(/* @__PURE__ */ new Set());
|
|
@@ -1012,11 +956,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1012
956
|
wrapperRef.current = node;
|
|
1013
957
|
setScopeNode(node);
|
|
1014
958
|
}, []);
|
|
1015
|
-
const
|
|
1016
|
-
const providerTheme = useMemo(() => {
|
|
1017
|
-
if (!theme) return defaultTheme;
|
|
1018
|
-
return withCatalogPointers(mergeThemes(defaultTheme, theme), overriddenRoles);
|
|
1019
|
-
}, [theme, overriddenRoles]);
|
|
959
|
+
const providerTheme = useMemo(() => theme ? mergeThemes(defaultTheme, theme) : defaultTheme, [theme]);
|
|
1020
960
|
const [colorCache, setColorCache] = useState(() => ({
|
|
1021
961
|
colors: [],
|
|
1022
962
|
hues: [],
|
|
@@ -1032,7 +972,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1032
972
|
const existingHslColors = [];
|
|
1033
973
|
let minHue = 360;
|
|
1034
974
|
let maxHue = 0;
|
|
1035
|
-
for (const color of
|
|
975
|
+
for (const color of SERIES_PALETTE_POINTERS) {
|
|
1036
976
|
const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
|
|
1037
977
|
if (normalizedColor.startsWith("#")) {
|
|
1038
978
|
resolvedColors.push(normalizedColor);
|
|
@@ -1057,7 +997,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1057
997
|
minHue,
|
|
1058
998
|
maxHue
|
|
1059
999
|
});
|
|
1060
|
-
}, [
|
|
1000
|
+
}, []);
|
|
1061
1001
|
useEffect(() => {
|
|
1062
1002
|
if (colorCache.colors.length > 0) setIsColorPaletteResolved(true);
|
|
1063
1003
|
}, [colorCache]);
|
|
@@ -1149,12 +1089,17 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1149
1089
|
const set = hiddenSeries.get(chartId);
|
|
1150
1090
|
return set ? new Set(set) : /* @__PURE__ */ new Set();
|
|
1151
1091
|
}, [hiddenSeries]);
|
|
1092
|
+
const formatting = useMemo(() => sanitizeFormatting({
|
|
1093
|
+
locale,
|
|
1094
|
+
timeZone
|
|
1095
|
+
}), [locale, timeZone]);
|
|
1152
1096
|
const value = useMemo(() => ({
|
|
1153
1097
|
charts,
|
|
1154
1098
|
registerChart,
|
|
1155
1099
|
unregisterChart,
|
|
1156
1100
|
getChartData,
|
|
1157
1101
|
theme: providerTheme,
|
|
1102
|
+
formatting,
|
|
1158
1103
|
getElementStyles,
|
|
1159
1104
|
toggleSeriesVisibility,
|
|
1160
1105
|
setSeriesVisibility,
|
|
@@ -1170,6 +1115,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1170
1115
|
unregisterChart,
|
|
1171
1116
|
getChartData,
|
|
1172
1117
|
providerTheme,
|
|
1118
|
+
formatting,
|
|
1173
1119
|
getElementStyles,
|
|
1174
1120
|
toggleSeriesVisibility,
|
|
1175
1121
|
setSeriesVisibility,
|
|
@@ -1185,10 +1131,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1185
1131
|
children: /* @__PURE__ */ jsx("div", {
|
|
1186
1132
|
ref: setWrapperNode,
|
|
1187
1133
|
className: CHART_SCOPE_CLASS,
|
|
1188
|
-
style: {
|
|
1189
|
-
display: "contents",
|
|
1190
|
-
...overrideVars
|
|
1191
|
-
},
|
|
1134
|
+
style: { display: "contents" },
|
|
1192
1135
|
children: /* @__PURE__ */ jsx(ChartScopeContext.Provider, {
|
|
1193
1136
|
value: scopeNode,
|
|
1194
1137
|
children
|
|
@@ -1252,6 +1195,39 @@ const useDeepMemo = (value) => {
|
|
|
1252
1195
|
return ref.current;
|
|
1253
1196
|
};
|
|
1254
1197
|
//#endregion
|
|
1198
|
+
//#region src/providers/chart-context/private/catalog-pointers.ts
|
|
1199
|
+
const CATALOG_POINTERS = {
|
|
1200
|
+
background: "var(--a8c-charts-color-background, #fff)",
|
|
1201
|
+
labelAxis: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
1202
|
+
grid: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
1203
|
+
axisX: "var(--a8c-charts-color-axis-x, #dbdbdb)",
|
|
1204
|
+
tickX: "var(--a8c-charts-color-tick-x, #dbdbdb)",
|
|
1205
|
+
axisY: "var(--a8c-charts-color-axis-y, none)",
|
|
1206
|
+
tickY: "var(--a8c-charts-color-tick-y, none)",
|
|
1207
|
+
annotation: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
1208
|
+
surface: "var(--a8c-charts-color-surface, #fff)",
|
|
1209
|
+
surfaceSecondary: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
1210
|
+
trendUp: "var(--a8c-charts-color-trend-up, #008030)",
|
|
1211
|
+
trendDown: "var(--a8c-charts-color-trend-down, #cc1818)",
|
|
1212
|
+
series: SERIES_PALETTE_POINTERS
|
|
1213
|
+
};
|
|
1214
|
+
/**
|
|
1215
|
+
* The annotation parts visx paints, in the shape `@visx/annotation` takes. `radius`
|
|
1216
|
+
* rides along as the base the theme and the per-datum styles merge onto.
|
|
1217
|
+
*/
|
|
1218
|
+
const ANNOTATION_POINTERS = {
|
|
1219
|
+
label: {
|
|
1220
|
+
anchorLineStroke: CATALOG_POINTERS.annotation,
|
|
1221
|
+
backgroundFill: CATALOG_POINTERS.surface
|
|
1222
|
+
},
|
|
1223
|
+
connector: { stroke: CATALOG_POINTERS.annotation },
|
|
1224
|
+
circleSubject: {
|
|
1225
|
+
stroke: "transparent",
|
|
1226
|
+
fill: CATALOG_POINTERS.annotation,
|
|
1227
|
+
radius: 5
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
//#endregion
|
|
1255
1231
|
//#region src/providers/chart-scope/use-chart-scope-element.ts
|
|
1256
1232
|
/**
|
|
1257
1233
|
* Returns the nearest chart scope element, or `null` when rendered outside any scope (and during SSR, before the ref is attached).
|
|
@@ -1278,13 +1254,34 @@ const useXYChartTheme = (data) => {
|
|
|
1278
1254
|
return useMemo(() => {
|
|
1279
1255
|
const resolve = createCssVariableResolver(scopeElement);
|
|
1280
1256
|
const resolveColor = (value) => value ? resolve(value) ?? value : value;
|
|
1281
|
-
const paletteColors = [...JSON.parse(seriesColorKey), ...
|
|
1282
|
-
const
|
|
1257
|
+
const paletteColors = [...JSON.parse(seriesColorKey), ...CATALOG_POINTERS.series].map((color) => resolveColor(color)).filter((color) => Boolean(color) && !color.includes("var("));
|
|
1258
|
+
const resolvedLabelColor = resolveColor(CATALOG_POINTERS.labelAxis);
|
|
1259
|
+
const htmlLabelColor = resolvedLabelColor ? normalizeColorToHex(resolvedLabelColor) || resolvedLabelColor : resolvedLabelColor;
|
|
1283
1260
|
return buildChartTheme({
|
|
1284
1261
|
...theme,
|
|
1262
|
+
gridColor: "",
|
|
1263
|
+
gridColorDark: "",
|
|
1285
1264
|
colors: paletteColors,
|
|
1286
|
-
backgroundColor: resolveColor(
|
|
1287
|
-
htmlLabel: htmlLabelColor ? { color: htmlLabelColor } : void 0
|
|
1265
|
+
backgroundColor: resolveColor(CATALOG_POINTERS.background),
|
|
1266
|
+
htmlLabel: htmlLabelColor ? { color: htmlLabelColor } : void 0,
|
|
1267
|
+
gridStyles: {
|
|
1268
|
+
...theme.gridStyles,
|
|
1269
|
+
stroke: CATALOG_POINTERS.grid
|
|
1270
|
+
},
|
|
1271
|
+
xAxisLineStyles: {
|
|
1272
|
+
...theme.xAxisLineStyles,
|
|
1273
|
+
stroke: CATALOG_POINTERS.axisX
|
|
1274
|
+
},
|
|
1275
|
+
xTickLineStyles: {
|
|
1276
|
+
...theme.xTickLineStyles,
|
|
1277
|
+
stroke: CATALOG_POINTERS.tickX
|
|
1278
|
+
},
|
|
1279
|
+
yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
|
|
1280
|
+
yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
|
|
1281
|
+
svgLabelSmall: {
|
|
1282
|
+
...theme.svgLabelSmall,
|
|
1283
|
+
fill: CATALOG_POINTERS.labelAxis
|
|
1284
|
+
}
|
|
1288
1285
|
});
|
|
1289
1286
|
}, [
|
|
1290
1287
|
theme,
|
|
@@ -1689,6 +1686,21 @@ const useGlobalChartsTheme = () => {
|
|
|
1689
1686
|
return useContext(GlobalChartsContext)?.theme ?? defaultTheme;
|
|
1690
1687
|
};
|
|
1691
1688
|
//#endregion
|
|
1689
|
+
//#region src/providers/chart-context/hooks/use-chart-formatting.ts
|
|
1690
|
+
const RUNTIME_FORMATTING = {};
|
|
1691
|
+
/**
|
|
1692
|
+
* The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
|
|
1693
|
+
*
|
|
1694
|
+
* Falls back to the runtime's own rather than throwing: charts render outside a
|
|
1695
|
+
* provider, and a host that sets neither gets exactly the browser-default
|
|
1696
|
+
* behavior this package had before the context existed.
|
|
1697
|
+
*
|
|
1698
|
+
* @return The host's formatting context.
|
|
1699
|
+
*/
|
|
1700
|
+
const useChartFormatting = () => {
|
|
1701
|
+
return useContext(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
|
|
1702
|
+
};
|
|
1703
|
+
//#endregion
|
|
1692
1704
|
//#region src/components/legend/utils/value-or-identity.ts
|
|
1693
1705
|
/**
|
|
1694
1706
|
* Returns an object's value if defined, or the object.
|
|
@@ -2126,15 +2138,311 @@ const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipCon
|
|
|
2126
2138
|
});
|
|
2127
2139
|
};
|
|
2128
2140
|
//#endregion
|
|
2141
|
+
//#region src/components/tooltip/private/bounded-tooltip.tsx
|
|
2142
|
+
const DEFAULT_OFFSET = 10;
|
|
2143
|
+
const isClipping = (element) => {
|
|
2144
|
+
const { overflow, overflowX, overflowY } = getComputedStyle(element);
|
|
2145
|
+
return [
|
|
2146
|
+
overflow,
|
|
2147
|
+
overflowX,
|
|
2148
|
+
overflowY
|
|
2149
|
+
].some((value) => value && value !== "visible");
|
|
2150
|
+
};
|
|
2151
|
+
const findClippingAncestor = (wrapper) => {
|
|
2152
|
+
let element = wrapper.parentElement;
|
|
2153
|
+
while (element && element !== document.body) {
|
|
2154
|
+
if (isClipping(element)) return element;
|
|
2155
|
+
element = element.parentElement;
|
|
2156
|
+
}
|
|
2157
|
+
return null;
|
|
2158
|
+
};
|
|
2159
|
+
/**
|
|
2160
|
+
* Where the box goes, in wrapper coordinates. Below and to the right of the
|
|
2161
|
+
* anchor; flipped to the other side when that side clips less, as visx's
|
|
2162
|
+
* `TooltipWithBounds` decides it; then clamped so the box stays inside
|
|
2163
|
+
* `bounds` whenever it fits at all.
|
|
2164
|
+
*
|
|
2165
|
+
* @param params - Anchor, offsets, the box size and the bounds to keep inside.
|
|
2166
|
+
* @param params.left - Anchor x, in wrapper coordinates.
|
|
2167
|
+
* @param params.top - Anchor y, in wrapper coordinates.
|
|
2168
|
+
* @param params.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2169
|
+
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2170
|
+
* @param params.box - Rendered size of the box.
|
|
2171
|
+
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2172
|
+
* @return The box's top-left corner, rounded to whole pixels.
|
|
2173
|
+
*/
|
|
2174
|
+
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) => {
|
|
2175
|
+
const rightX = left + offsetLeft;
|
|
2176
|
+
const leftX = left - offsetLeft - box.width;
|
|
2177
|
+
const rightOverflow = rightX + box.width - bounds.right;
|
|
2178
|
+
const leftOverflow = bounds.left - leftX;
|
|
2179
|
+
let x = rightOverflow > 0 && rightOverflow > leftOverflow ? leftX : rightX;
|
|
2180
|
+
const downY = top + offsetTop;
|
|
2181
|
+
const upY = top - offsetTop - box.height;
|
|
2182
|
+
const downOverflow = downY + box.height - bounds.bottom;
|
|
2183
|
+
const upOverflow = bounds.top - upY;
|
|
2184
|
+
let y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2185
|
+
x = Math.min(Math.max(x, bounds.left), Math.max(bounds.left, bounds.right - box.width));
|
|
2186
|
+
y = Math.min(Math.max(y, bounds.top), Math.max(bounds.top, bounds.bottom - box.height));
|
|
2187
|
+
return {
|
|
2188
|
+
x: Math.round(x),
|
|
2189
|
+
y: Math.round(y)
|
|
2190
|
+
};
|
|
2191
|
+
};
|
|
2192
|
+
/**
|
|
2193
|
+
* visx's `Tooltip`, positioned like its `TooltipWithBounds` but kept inside the
|
|
2194
|
+
* nearest clipping ancestor — or the viewport when there is none — rather than
|
|
2195
|
+
* inside its own parent. Rendered in-tree, a tooltip's parent is the chart
|
|
2196
|
+
* wrapper, which is often narrower than the box; measuring against the parent
|
|
2197
|
+
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2198
|
+
*
|
|
2199
|
+
* Re-measures on every render, so a box whose content changes width between
|
|
2200
|
+
* two hovers is placed for its current size.
|
|
2201
|
+
*
|
|
2202
|
+
* @param props - visx `Tooltip` props.
|
|
2203
|
+
* @param props.left - Anchor x, in wrapper coordinates.
|
|
2204
|
+
* @param props.top - Anchor y, in wrapper coordinates.
|
|
2205
|
+
* @param props.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2206
|
+
* @param props.offsetTop - Gap between the anchor and the box, vertically.
|
|
2207
|
+
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2208
|
+
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2209
|
+
* @param props.children - Box content.
|
|
2210
|
+
* @return The tooltip box.
|
|
2211
|
+
*/
|
|
2212
|
+
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = defaultStyles, unstyled = false, children, ...rest }) => {
|
|
2213
|
+
const nodeRef = useRef(null);
|
|
2214
|
+
const clipRef = useRef(null);
|
|
2215
|
+
const [position, setPosition] = useState(null);
|
|
2216
|
+
useLayoutEffect(() => {
|
|
2217
|
+
const node = nodeRef.current;
|
|
2218
|
+
const wrapper = node?.parentElement;
|
|
2219
|
+
if (!node || !wrapper) return;
|
|
2220
|
+
if (clipRef.current?.wrapper !== wrapper) clipRef.current = {
|
|
2221
|
+
wrapper,
|
|
2222
|
+
clip: findClippingAncestor(wrapper)
|
|
2223
|
+
};
|
|
2224
|
+
const own = node.getBoundingClientRect();
|
|
2225
|
+
const wrapperRect = wrapper.getBoundingClientRect();
|
|
2226
|
+
const clipRect = clipRef.current.clip?.getBoundingClientRect() ?? {
|
|
2227
|
+
left: 0,
|
|
2228
|
+
top: 0,
|
|
2229
|
+
right: window.innerWidth,
|
|
2230
|
+
bottom: window.innerHeight
|
|
2231
|
+
};
|
|
2232
|
+
const next = getBoundedPosition({
|
|
2233
|
+
left,
|
|
2234
|
+
top,
|
|
2235
|
+
offsetLeft,
|
|
2236
|
+
offsetTop,
|
|
2237
|
+
box: {
|
|
2238
|
+
width: own.width,
|
|
2239
|
+
height: own.height
|
|
2240
|
+
},
|
|
2241
|
+
bounds: {
|
|
2242
|
+
left: clipRect.left - wrapperRect.left,
|
|
2243
|
+
top: clipRect.top - wrapperRect.top,
|
|
2244
|
+
right: clipRect.right - wrapperRect.left,
|
|
2245
|
+
bottom: clipRect.bottom - wrapperRect.top
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
setPosition((current) => current && current.x === next.x && current.y === next.y ? current : next);
|
|
2249
|
+
}, [
|
|
2250
|
+
left,
|
|
2251
|
+
top,
|
|
2252
|
+
offsetLeft,
|
|
2253
|
+
offsetTop,
|
|
2254
|
+
children
|
|
2255
|
+
]);
|
|
2256
|
+
const x = position?.x ?? left + offsetLeft;
|
|
2257
|
+
const y = position?.y ?? top + offsetTop;
|
|
2258
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
2259
|
+
ref: nodeRef,
|
|
2260
|
+
style: {
|
|
2261
|
+
position: "absolute",
|
|
2262
|
+
left: 0,
|
|
2263
|
+
top: 0,
|
|
2264
|
+
transform: `translate(${x}px, ${y}px)`,
|
|
2265
|
+
...!unstyled && style
|
|
2266
|
+
},
|
|
2267
|
+
...rest,
|
|
2268
|
+
children
|
|
2269
|
+
});
|
|
2270
|
+
};
|
|
2271
|
+
//#endregion
|
|
2272
|
+
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2273
|
+
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2274
|
+
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2275
|
+
const FALLBACK_COLOR = "#222";
|
|
2276
|
+
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
2277
|
+
const PORTAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
2278
|
+
"scroll",
|
|
2279
|
+
"debounce",
|
|
2280
|
+
"resizeObserverPolyfill"
|
|
2281
|
+
]);
|
|
2282
|
+
const isValidNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2283
|
+
const scaleBandwidth = (scale) => {
|
|
2284
|
+
const bandwidth = scale?.bandwidth;
|
|
2285
|
+
return typeof bandwidth === "function" ? Number(bandwidth()) : 0;
|
|
2286
|
+
};
|
|
2287
|
+
const DefaultGlyph$1 = ({ x, y, size, color, glyphStyle, seriesKey }) => {
|
|
2288
|
+
const { theme } = useContext(DataContext) || {};
|
|
2289
|
+
return /* @__PURE__ */ jsx("circle", {
|
|
2290
|
+
cx: x,
|
|
2291
|
+
cy: y,
|
|
2292
|
+
r: size,
|
|
2293
|
+
fill: color,
|
|
2294
|
+
stroke: theme?.backgroundColor,
|
|
2295
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2296
|
+
paintOrder: "fill",
|
|
2297
|
+
...glyphStyle
|
|
2298
|
+
});
|
|
2299
|
+
};
|
|
2300
|
+
const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ jsx(DefaultGlyph$1, {
|
|
2301
|
+
seriesKey: key,
|
|
2302
|
+
...props
|
|
2303
|
+
}, key);
|
|
2304
|
+
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, zIndex = DEFAULT_TOOLTIP_Z_INDEX, ...rest }) => {
|
|
2305
|
+
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2306
|
+
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = useContext(DataContext) || {};
|
|
2307
|
+
const tooltipContent = renderTooltip ? renderTooltip({
|
|
2308
|
+
...tooltipContext,
|
|
2309
|
+
colorScale
|
|
2310
|
+
}) : null;
|
|
2311
|
+
if (tooltipContent == null) return null;
|
|
2312
|
+
const scaleX = xScale;
|
|
2313
|
+
const scaleY = yScale;
|
|
2314
|
+
const getDatumLeftTop = (key, datum) => {
|
|
2315
|
+
const entry = dataRegistry?.get(key);
|
|
2316
|
+
return {
|
|
2317
|
+
left: scaleX && entry?.xAccessor ? Number(scaleX(entry.xAccessor(datum))) + scaleBandwidth(xScale) / 2 : void 0,
|
|
2318
|
+
top: scaleY && entry?.yAccessor ? Number(scaleY(entry.yAccessor(datum))) + scaleBandwidth(yScale) / 2 : void 0
|
|
2319
|
+
};
|
|
2320
|
+
};
|
|
2321
|
+
const nearestDatum = tooltipContext.tooltipData?.nearestDatum;
|
|
2322
|
+
let { tooltipLeft, tooltipTop } = tooltipContext;
|
|
2323
|
+
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY)) {
|
|
2324
|
+
const { left, top } = getDatumLeftTop(nearestDatum.key, nearestDatum.datum);
|
|
2325
|
+
if (snapTooltipToDatumX && isValidNumber(left)) tooltipLeft = left;
|
|
2326
|
+
if (snapTooltipToDatumY && isValidNumber(top)) tooltipTop = top;
|
|
2327
|
+
}
|
|
2328
|
+
const glyphs = [];
|
|
2329
|
+
if (showDatumGlyph || showSeriesGlyphs) {
|
|
2330
|
+
const size = Number(glyphStyle?.radius ?? DEFAULT_GLYPH_RADIUS);
|
|
2331
|
+
const labelColor = theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2332
|
+
const fallbackColor = showSeriesGlyphs ? labelColor : theme?.gridStyles?.stroke ?? labelColor;
|
|
2333
|
+
let entries = [];
|
|
2334
|
+
if (showSeriesGlyphs) entries = Object.values(tooltipContext.tooltipData?.datumByKey ?? {});
|
|
2335
|
+
else if (nearestDatum) entries = [nearestDatum];
|
|
2336
|
+
for (const { key, datum, index } of entries) {
|
|
2337
|
+
const { left, top } = getDatumLeftTop(key, datum);
|
|
2338
|
+
if (!isValidNumber(left) || !isValidNumber(top)) continue;
|
|
2339
|
+
glyphs.push(/* @__PURE__ */ jsx("g", {
|
|
2340
|
+
className: "visx-tooltip-glyph",
|
|
2341
|
+
transform: `translate(${left}, ${top})`,
|
|
2342
|
+
children: renderGlyph({
|
|
2343
|
+
key,
|
|
2344
|
+
color: colorScale?.(key) ?? fallbackColor,
|
|
2345
|
+
datum,
|
|
2346
|
+
index,
|
|
2347
|
+
size,
|
|
2348
|
+
x: 0,
|
|
2349
|
+
y: 0,
|
|
2350
|
+
glyphStyle,
|
|
2351
|
+
isNearestDatum: nearestDatum?.key === key
|
|
2352
|
+
})
|
|
2353
|
+
}, key));
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2357
|
+
const marginTop = margin?.top ?? 0;
|
|
2358
|
+
const marginLeft = margin?.left ?? 0;
|
|
2359
|
+
const TooltipComponent = detectBounds ? BoundedTooltip : Tooltip;
|
|
2360
|
+
const boxStyle = {
|
|
2361
|
+
...defaultStyles,
|
|
2362
|
+
zIndex,
|
|
2363
|
+
background: theme?.backgroundColor ?? "white",
|
|
2364
|
+
boxShadow: `0 1px 2px ${theme?.htmlLabel?.color ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2365
|
+
...theme?.htmlLabel
|
|
2366
|
+
};
|
|
2367
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("g", {
|
|
2368
|
+
className: "visx-tooltip-overlay",
|
|
2369
|
+
pointerEvents: "none",
|
|
2370
|
+
children: [
|
|
2371
|
+
showVerticalCrosshair && isValidNumber(tooltipLeft) && /* @__PURE__ */ jsx("line", {
|
|
2372
|
+
className: "visx-crosshair visx-crosshair-vertical",
|
|
2373
|
+
x1: tooltipLeft,
|
|
2374
|
+
x2: tooltipLeft,
|
|
2375
|
+
y1: marginTop,
|
|
2376
|
+
y2: marginTop + innerHeight,
|
|
2377
|
+
stroke: crosshairStroke,
|
|
2378
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2379
|
+
...verticalCrosshairStyle
|
|
2380
|
+
}),
|
|
2381
|
+
showHorizontalCrosshair && isValidNumber(tooltipTop) && /* @__PURE__ */ jsx("line", {
|
|
2382
|
+
className: "visx-crosshair visx-crosshair-horizontal",
|
|
2383
|
+
x1: marginLeft,
|
|
2384
|
+
x2: marginLeft + innerWidth,
|
|
2385
|
+
y1: tooltipTop,
|
|
2386
|
+
y2: tooltipTop,
|
|
2387
|
+
stroke: crosshairStroke,
|
|
2388
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2389
|
+
...horizontalCrosshairStyle
|
|
2390
|
+
}),
|
|
2391
|
+
glyphs
|
|
2392
|
+
]
|
|
2393
|
+
}), container && createPortal(/* @__PURE__ */ jsx(TooltipComponent, {
|
|
2394
|
+
left: tooltipLeft,
|
|
2395
|
+
top: tooltipTop,
|
|
2396
|
+
style: boxStyle,
|
|
2397
|
+
applyPositionStyle: true,
|
|
2398
|
+
...tooltipProps,
|
|
2399
|
+
children: tooltipContent
|
|
2400
|
+
}), container)] });
|
|
2401
|
+
};
|
|
2402
|
+
/**
|
|
2403
|
+
* In-tree replacement for `@visx/xychart`'s `Tooltip`.
|
|
2404
|
+
*
|
|
2405
|
+
* visx renders its tooltip box, glyphs and crosshairs through portals appended
|
|
2406
|
+
* to `document.body`. That puts them in the page's root stacking context, where
|
|
2407
|
+
* they paint above every sticky or fixed element that lives inside a nested
|
|
2408
|
+
* stacking context, and no z-index on that element can change the order. This
|
|
2409
|
+
* component draws the glyphs and crosshairs straight into the chart SVG and
|
|
2410
|
+
* renders the tooltip box into the SVG's parent element, so all of them stack
|
|
2411
|
+
* as ordinary descendants of the chart.
|
|
2412
|
+
*
|
|
2413
|
+
* Render it as a child of `XYChart`. The element wrapping that `XYChart` must
|
|
2414
|
+
* be `position: relative` with the SVG at its origin, and `isolation: isolate`:
|
|
2415
|
+
* the box is placed with the SVG-local coordinates visx reports, and the
|
|
2416
|
+
* isolation keeps the box's `zIndex` from competing with page chrome. The box
|
|
2417
|
+
* flips and clamps to stay inside the nearest ancestor that clips its overflow
|
|
2418
|
+
* (or the viewport), so it may extend past the chart wrapper but is never cut
|
|
2419
|
+
* off unless that ancestor is smaller than the box itself.
|
|
2420
|
+
*
|
|
2421
|
+
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2422
|
+
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
2423
|
+
*/
|
|
2424
|
+
const XyChartTooltip = (props) => {
|
|
2425
|
+
const tooltipContext = useContext(TooltipContext);
|
|
2426
|
+
const [container, setContainer] = useState(null);
|
|
2427
|
+
const anchorRef = useCallback((node) => {
|
|
2428
|
+
setContainer(node?.ownerSVGElement?.parentElement ?? null);
|
|
2429
|
+
}, []);
|
|
2430
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("g", { ref: anchorRef }), tooltipContext?.tooltipOpen && /* @__PURE__ */ jsx(XyChartTooltipContent, {
|
|
2431
|
+
...props,
|
|
2432
|
+
tooltipContext,
|
|
2433
|
+
container
|
|
2434
|
+
})] });
|
|
2435
|
+
};
|
|
2436
|
+
//#endregion
|
|
2129
2437
|
//#region src/components/tooltip/accessible-tooltip.tsx
|
|
2130
2438
|
const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
|
|
2131
2439
|
const tooltipContext = useContext(TooltipContext);
|
|
2132
2440
|
const scopeElement = useChartScopeElement();
|
|
2133
|
-
const gridStroke = useGlobalChartsTheme().gridStyles?.stroke;
|
|
2134
2441
|
const crosshairStroke = useMemo(() => {
|
|
2135
|
-
const stroke =
|
|
2442
|
+
const stroke = resolveCssVariable(CATALOG_POINTERS.grid, scopeElement);
|
|
2136
2443
|
return stroke ? { stroke } : void 0;
|
|
2137
|
-
}, [
|
|
2444
|
+
}, [scopeElement]);
|
|
2445
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2138
2446
|
const tooltipData = useMemo(() => {
|
|
2139
2447
|
if (mode !== "individual") return [];
|
|
2140
2448
|
if (series.length === 0) return [];
|
|
@@ -2195,11 +2503,11 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2195
2503
|
tabIndex: -1,
|
|
2196
2504
|
role: "tooltip",
|
|
2197
2505
|
"aria-atomic": "true",
|
|
2198
|
-
className: clsx(
|
|
2506
|
+
className: clsx(standaloneScopeClass, keyboardFocusedClassName),
|
|
2199
2507
|
children: tooltipContent
|
|
2200
2508
|
}, `chart-tooltip-${selectedIndex}`);
|
|
2201
2509
|
return /* @__PURE__ */ jsx("div", {
|
|
2202
|
-
className:
|
|
2510
|
+
className: standaloneScopeClass,
|
|
2203
2511
|
role: "tooltip",
|
|
2204
2512
|
"aria-live": "polite",
|
|
2205
2513
|
children: tooltipContent
|
|
@@ -2209,9 +2517,10 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2209
2517
|
renderTooltip,
|
|
2210
2518
|
selectedIndex,
|
|
2211
2519
|
tooltipRef,
|
|
2212
|
-
keyboardFocusedClassName
|
|
2520
|
+
keyboardFocusedClassName,
|
|
2521
|
+
standaloneScopeClass
|
|
2213
2522
|
]);
|
|
2214
|
-
return /* @__PURE__ */ jsx(
|
|
2523
|
+
return /* @__PURE__ */ jsx(XyChartTooltip, {
|
|
2215
2524
|
...props,
|
|
2216
2525
|
verticalCrosshairStyle: {
|
|
2217
2526
|
...crosshairStroke,
|
|
@@ -2559,72 +2868,90 @@ const getCurveType = (type, smoothing) => {
|
|
|
2559
2868
|
default: return curveLinear;
|
|
2560
2869
|
}
|
|
2561
2870
|
};
|
|
2562
|
-
const
|
|
2563
|
-
|
|
2564
|
-
return (timestamp) => {
|
|
2565
|
-
if (!Number.isFinite(Number(timestamp))) return new Date(timestamp).toLocaleDateString();
|
|
2566
|
-
formatter = formatter ?? new Intl.DateTimeFormat(void 0, options);
|
|
2567
|
-
return formatter.format(timestamp);
|
|
2568
|
-
};
|
|
2569
|
-
};
|
|
2570
|
-
const formatYearTick = dateTimeFormat({ year: "numeric" });
|
|
2571
|
-
const formatDateTick = dateTimeFormat({
|
|
2871
|
+
const YEAR_TICK = { year: "numeric" };
|
|
2872
|
+
const DATE_TICK = {
|
|
2572
2873
|
month: "short",
|
|
2573
2874
|
day: "numeric"
|
|
2574
|
-
}
|
|
2575
|
-
const
|
|
2576
|
-
|
|
2577
|
-
hour12: true
|
|
2578
|
-
});
|
|
2579
|
-
const formatMonthTick = dateTimeFormat({ month: "short" });
|
|
2875
|
+
};
|
|
2876
|
+
const HOUR_TICK = { hour: "numeric" };
|
|
2877
|
+
const MONTH_TICK = { month: "short" };
|
|
2580
2878
|
const boundaryFormat = (isAnchor, atBoundary, between) => {
|
|
2581
2879
|
const format = (timestamp) => isAnchor(new Date(timestamp)) ? atBoundary(timestamp) : between(timestamp);
|
|
2582
2880
|
format.isAnchor = isAnchor;
|
|
2583
2881
|
return format;
|
|
2584
2882
|
};
|
|
2585
|
-
const
|
|
2586
|
-
const
|
|
2883
|
+
const tickFormats = (formatting) => {
|
|
2884
|
+
const clock = createZonedClock(formatting.timeZone);
|
|
2885
|
+
const year = createDateFormatter(YEAR_TICK, formatting);
|
|
2886
|
+
const date = createDateFormatter(DATE_TICK, formatting);
|
|
2887
|
+
const hour = createDateFormatter(HOUR_TICK, formatting);
|
|
2888
|
+
const month = createDateFormatter(MONTH_TICK, formatting);
|
|
2889
|
+
const datedTick = (timestamp) => date(timestamp);
|
|
2890
|
+
datedTick.anchorsAtLabelChange = true;
|
|
2891
|
+
return {
|
|
2892
|
+
year,
|
|
2893
|
+
date: datedTick,
|
|
2894
|
+
dateOrHour: boundaryFormat((value) => clock(value).hour === 0, date, hour),
|
|
2895
|
+
hour,
|
|
2896
|
+
monthOrYear: boundaryFormat((value) => clock(value).month === 1, year, month)
|
|
2897
|
+
};
|
|
2898
|
+
};
|
|
2587
2899
|
const getSpan = (sortedData) => {
|
|
2588
|
-
const bounds = sortedData.map((datom) => [datom.data.at(0)?.date, datom.data.at(-1)?.date]).filter(([first, last]) => first
|
|
2900
|
+
const bounds = sortedData.map((datom) => [datom.data.at(0)?.date, datom.data.at(-1)?.date]).filter(([first, last]) => Number.isFinite(Number(first)) && Number.isFinite(Number(last)));
|
|
2589
2901
|
if (!bounds.length) return null;
|
|
2590
2902
|
return {
|
|
2591
2903
|
minX: Math.min(...bounds.map(([first]) => Number(first))),
|
|
2592
2904
|
maxX: Math.max(...bounds.map(([, last]) => Number(last)))
|
|
2593
2905
|
};
|
|
2594
2906
|
};
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
const
|
|
2605
|
-
|
|
2606
|
-
const spacingInHours = getPointSpacingInHours(sortedData);
|
|
2607
|
-
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
2608
|
-
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
2609
|
-
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
2610
|
-
};
|
|
2611
|
-
const getFormatter = (sortedData, tickResolution) => {
|
|
2907
|
+
/**
|
|
2908
|
+
* The most informative tick format for a bucket resolution and the span on screen.
|
|
2909
|
+
*
|
|
2910
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
2911
|
+
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
2912
|
+
* @param formatting - Host locale and time zone.
|
|
2913
|
+
* @param domain - The effective scale domain, or undefined for the data's own extent.
|
|
2914
|
+
* @return The formatter the axis labels its ticks with.
|
|
2915
|
+
*/
|
|
2916
|
+
const getFormatter = (sortedData, tickResolution, formatting = {}, domain) => {
|
|
2917
|
+
const format = tickFormats(formatting);
|
|
2612
2918
|
const resolution = getBucketResolution(sortedData, tickResolution);
|
|
2613
|
-
if (resolution === "year") return
|
|
2614
|
-
if (resolution === "month") return
|
|
2615
|
-
const span =
|
|
2616
|
-
|
|
2919
|
+
if (resolution === "year") return format.year;
|
|
2920
|
+
if (resolution === "month") return format.monthOrYear;
|
|
2921
|
+
const span = domain ? {
|
|
2922
|
+
minX: domain[0].getTime(),
|
|
2923
|
+
maxX: domain[1].getTime()
|
|
2924
|
+
} : getSpan(sortedData);
|
|
2925
|
+
if (!span) return format.date;
|
|
2617
2926
|
const diffInHours = Math.abs(differenceInHours(span.maxX, span.minX));
|
|
2618
2927
|
if (resolution === "hour") {
|
|
2619
|
-
if (diffInHours
|
|
2620
|
-
if (diffInHours <= 168) return
|
|
2928
|
+
if (diffInHours < 24) return format.hour;
|
|
2929
|
+
if (diffInHours <= 168) return format.dateOrHour;
|
|
2621
2930
|
}
|
|
2622
|
-
return Math.abs(differenceInYears(span.maxX, span.minX)) <= 1 ?
|
|
2931
|
+
return Math.abs(differenceInYears(span.maxX, span.minX)) <= 1 ? format.date : format.year;
|
|
2932
|
+
};
|
|
2933
|
+
/**
|
|
2934
|
+
* The instants a set of series spans, as a scale domain.
|
|
2935
|
+
*
|
|
2936
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
2937
|
+
* @return Earliest and latest dated point, or undefined when nothing is dated.
|
|
2938
|
+
*/
|
|
2939
|
+
const getSeriesExtent = (sortedData) => {
|
|
2940
|
+
const span = getSpan(sortedData);
|
|
2941
|
+
return span ? [new Date(span.minX), new Date(span.maxX)] : void 0;
|
|
2942
|
+
};
|
|
2943
|
+
const getAnchorIndices = (domain, tickFormatter, labels) => {
|
|
2944
|
+
if (tickFormatter.anchorsAtLabelChange) return labels.reduce((indices, label, index) => {
|
|
2945
|
+
if (index === 0 || label !== labels[index - 1]) indices.push(index);
|
|
2946
|
+
return indices;
|
|
2947
|
+
}, []);
|
|
2948
|
+
const { isAnchor } = tickFormatter;
|
|
2949
|
+
if (!isAnchor) return [];
|
|
2950
|
+
return domain.reduce((indices, date, index) => {
|
|
2951
|
+
if (isAnchor(date)) indices.push(index);
|
|
2952
|
+
return indices;
|
|
2953
|
+
}, []);
|
|
2623
2954
|
};
|
|
2624
|
-
const getAnchorIndices = (domain, isAnchor) => domain.reduce((indices, date, index) => {
|
|
2625
|
-
if (isAnchor(date)) indices.push(index);
|
|
2626
|
-
return indices;
|
|
2627
|
-
}, []);
|
|
2628
2955
|
const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
2629
2956
|
const steps = /* @__PURE__ */ new Set();
|
|
2630
2957
|
for (let count = maxTicks; count > 1; count--) {
|
|
@@ -2639,26 +2966,25 @@ const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
|
2639
2966
|
return steps;
|
|
2640
2967
|
};
|
|
2641
2968
|
/**
|
|
2642
|
-
* Tick values for
|
|
2969
|
+
* Tick values sampled by index, for the bar chart's band axis and for evenly
|
|
2970
|
+
* spaced points on a continuous one.
|
|
2643
2971
|
*
|
|
2644
|
-
* visx samples
|
|
2645
|
-
*
|
|
2646
|
-
*
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
* identical labels side by side.
|
|
2972
|
+
* visx samples by index from offset zero, blind to which labels carry a boundary
|
|
2973
|
+
* and without collapsing repeats — so the tick that prints the year or the date
|
|
2974
|
+
* often isn't sampled at all, and a long series can show the same label twice.
|
|
2975
|
+
* Choose the values instead: sweep the evenly spaced candidates, including those
|
|
2976
|
+
* that step from anchor to anchor, and keep the one that reaches the most anchors
|
|
2977
|
+
* without thinning the axis or putting two identical labels side by side.
|
|
2651
2978
|
*
|
|
2652
|
-
* @param domain -
|
|
2979
|
+
* @param domain - Buckets in axis order.
|
|
2653
2980
|
* @param tickFormatter - Formatter the axis will render these values with.
|
|
2654
2981
|
* @param maxTicks - Most ticks the axis should carry.
|
|
2655
2982
|
* @return Values to hand the axis as `tickValues`.
|
|
2656
2983
|
*/
|
|
2657
2984
|
const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
2658
2985
|
if (!domain.length) return [];
|
|
2659
|
-
const { isAnchor } = tickFormatter;
|
|
2660
|
-
const anchorIndices = isAnchor ? getAnchorIndices(domain, isAnchor) : [];
|
|
2661
2986
|
const domainLabels = domain.map((date) => tickFormatter(date.getTime()));
|
|
2987
|
+
const anchorIndices = getAnchorIndices(domain, tickFormatter, domainLabels);
|
|
2662
2988
|
const candidates = [];
|
|
2663
2989
|
const consider = (indices) => {
|
|
2664
2990
|
if (!indices.length || indices.length > maxTicks) return;
|
|
@@ -2670,15 +2996,108 @@ const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
|
2670
2996
|
for (let index = offset; index < domain.length; index += step) indices.push(index);
|
|
2671
2997
|
consider(indices);
|
|
2672
2998
|
}
|
|
2673
|
-
|
|
2999
|
+
const minStride = Math.max(1, Math.ceil(anchorIndices.length / maxTicks));
|
|
3000
|
+
for (let stride = minStride; stride <= anchorIndices.length; stride++) {
|
|
3001
|
+
const stepped = [];
|
|
3002
|
+
for (let position = 0; position < anchorIndices.length; position += stride) stepped.push(anchorIndices[position]);
|
|
3003
|
+
consider(stepped);
|
|
3004
|
+
}
|
|
2674
3005
|
if (!candidates.length) return [domain[0]];
|
|
2675
3006
|
const densest = candidates.reduce((most, indices) => Math.max(most, indices.length), 0);
|
|
2676
|
-
const
|
|
3007
|
+
const anchorIndexSet = new Set(anchorIndices);
|
|
3008
|
+
const anchorsIn = (indices) => indices.filter((index) => anchorIndexSet.has(index)).length;
|
|
2677
3009
|
return candidates.filter((indices) => indices.length >= densest - 1).reduce((chosen, indices) => {
|
|
2678
3010
|
const gain = anchorsIn(indices) - anchorsIn(chosen);
|
|
2679
3011
|
return gain > 0 || gain === 0 && indices.length > chosen.length ? indices : chosen;
|
|
2680
3012
|
}).map((index) => domain[index]);
|
|
2681
3013
|
};
|
|
3014
|
+
/**
|
|
3015
|
+
* The most x-axis ticks a chart of this width has room for.
|
|
3016
|
+
*
|
|
3017
|
+
* @param chartWidth - Chart width in pixels.
|
|
3018
|
+
* @return A tick budget of at least one.
|
|
3019
|
+
*/
|
|
3020
|
+
const getMaxTicksForWidth = (chartWidth) => Math.max(1, Math.floor(chartWidth / X_TICK_WIDTH));
|
|
3021
|
+
const MIN_GAP_IN_LABELS = .9;
|
|
3022
|
+
const nearestValue = (sorted, target) => {
|
|
3023
|
+
let low = 0;
|
|
3024
|
+
let high = sorted.length - 1;
|
|
3025
|
+
while (low < high) {
|
|
3026
|
+
const middle = Math.floor((low + high) / 2);
|
|
3027
|
+
if (sorted[middle] < target) low = middle + 1;
|
|
3028
|
+
else high = middle;
|
|
3029
|
+
}
|
|
3030
|
+
const above = sorted[low];
|
|
3031
|
+
const below = low > 0 ? sorted[low - 1] : above;
|
|
3032
|
+
return Math.abs(above - target) <= Math.abs(below - target) ? above : below;
|
|
3033
|
+
};
|
|
3034
|
+
const getPositionTickValues = (points, tickFormatter, maxTicks, axis) => {
|
|
3035
|
+
const times = points.map((point) => point.getTime());
|
|
3036
|
+
const { first, last } = axis;
|
|
3037
|
+
if (maxTicks <= 1 || times.length === 1 || first === last) return [points[0]];
|
|
3038
|
+
const step = (last - first) / (maxTicks - 1);
|
|
3039
|
+
const labels = points.map((point) => tickFormatter(point.getTime()));
|
|
3040
|
+
const minGap = (last - first) / maxTicks * MIN_GAP_IN_LABELS;
|
|
3041
|
+
const anchors = getAnchorIndices(points, tickFormatter, labels).map((index) => times[index]);
|
|
3042
|
+
const chosen = [];
|
|
3043
|
+
let lastLabel = null;
|
|
3044
|
+
for (let index = 0; index < maxTicks; index++) {
|
|
3045
|
+
const target = first + index * step;
|
|
3046
|
+
const anchor = anchors.length ? nearestValue(anchors, target) : null;
|
|
3047
|
+
let tick = anchor !== null && Math.abs(anchor - target) <= step / 2 ? anchor : null;
|
|
3048
|
+
if (tick === null) {
|
|
3049
|
+
const point = nearestValue(times, target);
|
|
3050
|
+
tick = Math.abs(point - target) <= step / 2 ? point : target;
|
|
3051
|
+
}
|
|
3052
|
+
const previous = chosen[chosen.length - 1];
|
|
3053
|
+
if (previous !== void 0 && (tick <= previous || tick - previous < minGap)) continue;
|
|
3054
|
+
const label = tickFormatter(tick);
|
|
3055
|
+
if (label === lastLabel) continue;
|
|
3056
|
+
chosen.push(tick);
|
|
3057
|
+
lastLabel = label;
|
|
3058
|
+
}
|
|
3059
|
+
return chosen.map((timestamp) => new Date(timestamp));
|
|
3060
|
+
};
|
|
3061
|
+
const isIndexSamplingUnusable = (ticks, points, maxTicks, axis) => {
|
|
3062
|
+
if (ticks.length < 2 || points.length < 2) return false;
|
|
3063
|
+
const span = axis.last - axis.first;
|
|
3064
|
+
if (!span) return false;
|
|
3065
|
+
return ticks.slice(1).reduce((nearest, tick, index) => Math.min(nearest, tick.getTime() - ticks[index].getTime()), Infinity) < span / maxTicks * MIN_GAP_IN_LABELS || ticks.length < Math.min(maxTicks, points.length) / 3;
|
|
3066
|
+
};
|
|
3067
|
+
/**
|
|
3068
|
+
* Tick values for a continuous time axis, chosen from the points it draws.
|
|
3069
|
+
*
|
|
3070
|
+
* Sampled by index while the points are evenly spaced, which keeps the axis on
|
|
3071
|
+
* the calendar boundaries `getBandTickValues` steers towards, and by position
|
|
3072
|
+
* once they are not, where an index stride crowds one end of the scale.
|
|
3073
|
+
*
|
|
3074
|
+
* Values are taken from the data wherever there is one to take, so a local time
|
|
3075
|
+
* that does not exist cannot become a tick and DST needs no special case. Only a
|
|
3076
|
+
* target stranded in a gap is constructed, as a plain instant.
|
|
3077
|
+
*
|
|
3078
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
3079
|
+
* @param domain - The effective scale domain, or undefined for all data.
|
|
3080
|
+
* @param tickFormatter - The formatter the ticks will be labeled with.
|
|
3081
|
+
* @param maxTicks - The most ticks the axis has room for.
|
|
3082
|
+
* @return Tick dates, or null when no series carries a usable date.
|
|
3083
|
+
*/
|
|
3084
|
+
const getTimeAxisTickValues = (sortedData, domain, tickFormatter, maxTicks) => {
|
|
3085
|
+
const byTimestamp = /* @__PURE__ */ new Map();
|
|
3086
|
+
for (const series of sortedData) for (const point of series.data) {
|
|
3087
|
+
const date = point.date;
|
|
3088
|
+
if (date instanceof Date && Number.isFinite(date.getTime())) byTimestamp.set(date.getTime(), date);
|
|
3089
|
+
}
|
|
3090
|
+
if (!byTimestamp.size) return null;
|
|
3091
|
+
const min = domain?.[0]?.getTime();
|
|
3092
|
+
const max = domain?.[1]?.getTime();
|
|
3093
|
+
const visible = [...byTimestamp.keys()].sort((a, b) => a - b).filter((timestamp) => (min === void 0 || timestamp >= min) && (max === void 0 || timestamp <= max)).map((timestamp) => byTimestamp.get(timestamp));
|
|
3094
|
+
const axis = {
|
|
3095
|
+
first: min ?? visible[0].getTime(),
|
|
3096
|
+
last: max ?? visible[visible.length - 1].getTime()
|
|
3097
|
+
};
|
|
3098
|
+
const ticks = getBandTickValues(visible, tickFormatter, maxTicks);
|
|
3099
|
+
return isIndexSamplingUnusable(ticks, visible, maxTicks, axis) ? getPositionTickValues(visible, tickFormatter, maxTicks, axis) : ticks;
|
|
3100
|
+
};
|
|
2682
3101
|
const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
2683
3102
|
const span = getSpan(data);
|
|
2684
3103
|
if (!span) return 1;
|
|
@@ -2693,7 +3112,43 @@ const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
|
2693
3112
|
if (ticks.some((tick, idx) => idx > 0 && tick === ticks[idx - 1])) continue;
|
|
2694
3113
|
return ticks.length;
|
|
2695
3114
|
}
|
|
2696
|
-
return secondBestGuess;
|
|
3115
|
+
return Math.max(1, secondBestGuess);
|
|
3116
|
+
};
|
|
3117
|
+
//#endregion
|
|
3118
|
+
//#region src/charts/private/time-axis-options.ts
|
|
3119
|
+
const toDateDomain = (domain) => domain ? [new Date(domain[0]), new Date(domain[1])] : void 0;
|
|
3120
|
+
/**
|
|
3121
|
+
* The x-axis options for a continuous time chart, shared by LineChart and AreaChart.
|
|
3122
|
+
*
|
|
3123
|
+
* Kept in one place so the tick-selection logic isn't duplicated between them.
|
|
3124
|
+
*
|
|
3125
|
+
* @param args - Named arguments.
|
|
3126
|
+
* @param args.dataSorted - Series as returned by `useChartDataTransform`.
|
|
3127
|
+
* @param args.width - Chart width in pixels, which bounds how many ticks fit.
|
|
3128
|
+
* @param args.axisOptions - The caller's `options.axis.x`.
|
|
3129
|
+
* @param args.scaleDomain - The caller's `options.xScale.domain`.
|
|
3130
|
+
* @param args.zoomDomain - The chart's current zoom window, when zoomed.
|
|
3131
|
+
* @param args.formatting - Host locale and time zone.
|
|
3132
|
+
* @param args.isSeriesRendered - Whether visx mounts a series, i.e. the legend shows it. Defaults to all of them.
|
|
3133
|
+
* @return Options ready to spread into the chart's `axis.x`; `orientation` is always set.
|
|
3134
|
+
*/
|
|
3135
|
+
const buildTimeAxisOptions = ({ dataSorted, width, axisOptions, scaleDomain, zoomDomain, formatting, isSeriesRendered }) => {
|
|
3136
|
+
const { tickResolution, tickFormat, tickValues: callerTickValues, numTicks: callerNumTicks, orientation: callerOrientation, display: callerDisplay, ...rest } = axisOptions ?? {};
|
|
3137
|
+
const rendered = isSeriesRendered ? dataSorted.filter(isSeriesRendered) : dataSorted;
|
|
3138
|
+
const effectiveDomain = zoomDomain ?? toDateDomain(scaleDomain) ?? getSeriesExtent(rendered);
|
|
3139
|
+
const ownFormatter = getFormatter(rendered, tickResolution, formatting, effectiveDomain);
|
|
3140
|
+
const formatter = tickFormat || ownFormatter;
|
|
3141
|
+
const ownTickValues = tickFormat || callerTickValues ? null : getTimeAxisTickValues(rendered, effectiveDomain, ownFormatter, callerNumTicks ?? getMaxTicksForWidth(width));
|
|
3142
|
+
const tickValues = callerTickValues ?? (ownTickValues?.length ? ownTickValues : void 0);
|
|
3143
|
+
const numTicks = callerNumTicks ?? (tickValues ? void 0 : guessOptimalNumTicks(rendered, width, formatter));
|
|
3144
|
+
return {
|
|
3145
|
+
orientation: callerOrientation ?? "bottom",
|
|
3146
|
+
tickFormat: formatter,
|
|
3147
|
+
display: callerDisplay ?? true,
|
|
3148
|
+
...rest,
|
|
3149
|
+
...tickValues ? { tickValues } : {},
|
|
3150
|
+
...numTicks === void 0 ? {} : { numTicks }
|
|
3151
|
+
};
|
|
2697
3152
|
};
|
|
2698
3153
|
//#endregion
|
|
2699
3154
|
//#region src/charts/private/with-responsive/with-responsive.module.scss
|
|
@@ -2974,6 +3429,9 @@ function ZoomResetButton({ onClick }) {
|
|
|
2974
3429
|
});
|
|
2975
3430
|
}
|
|
2976
3431
|
//#endregion
|
|
3432
|
+
//#region src/charts/private/xy-plot/xy-plot.module.scss
|
|
3433
|
+
var xy_plot_module_default = { "xy-plot": "a8ccharts-bIyhgG-xy-plot" };
|
|
3434
|
+
//#endregion
|
|
2977
3435
|
//#region src/charts/line-chart/line-chart.module.scss
|
|
2978
3436
|
var line_chart_module_default = {
|
|
2979
3437
|
"line-chart": "a8ccharts-inuQka-line-chart",
|
|
@@ -3214,12 +3672,14 @@ const getVerticalAnchor = (subjectType, isFlippedVertically, y, yMax, height) =>
|
|
|
3214
3672
|
};
|
|
3215
3673
|
const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", styles: datumStyles, testId, renderLabel, renderLabelPopover }) => {
|
|
3216
3674
|
const providerTheme = useGlobalChartsTheme();
|
|
3217
|
-
const scopeElement = useChartScopeElement();
|
|
3218
3675
|
const { xScale, yScale } = useContext(DataContext) || {};
|
|
3219
3676
|
const labelRef = useRef(null);
|
|
3220
3677
|
const [height, setHeight] = useState(null);
|
|
3221
|
-
const styles =
|
|
3222
|
-
|
|
3678
|
+
const styles = useMemo(() => deepmerge.all([
|
|
3679
|
+
ANNOTATION_POINTERS,
|
|
3680
|
+
providerTheme.annotationStyles ?? {},
|
|
3681
|
+
datumStyles ?? {}
|
|
3682
|
+
]), [providerTheme.annotationStyles, datumStyles]);
|
|
3223
3683
|
useEffect(() => {
|
|
3224
3684
|
if (labelRef.current?.getBBox) {
|
|
3225
3685
|
const bbox = labelRef.current.getBBox();
|
|
@@ -3305,15 +3765,8 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3305
3765
|
dx,
|
|
3306
3766
|
dy,
|
|
3307
3767
|
children: [
|
|
3308
|
-
/* @__PURE__ */ jsx(Connector, {
|
|
3309
|
-
|
|
3310
|
-
stroke: resolveColor(styles?.connector?.stroke)
|
|
3311
|
-
}),
|
|
3312
|
-
subjectType === "circle" && /* @__PURE__ */ jsx(CircleSubject, {
|
|
3313
|
-
...styles?.circleSubject,
|
|
3314
|
-
fill: resolveColor(styles?.circleSubject?.fill),
|
|
3315
|
-
stroke: resolveColor(styles?.circleSubject?.stroke)
|
|
3316
|
-
}),
|
|
3768
|
+
/* @__PURE__ */ jsx(Connector, { ...styles?.connector }),
|
|
3769
|
+
subjectType === "circle" && /* @__PURE__ */ jsx(CircleSubject, { ...styles?.circleSubject }),
|
|
3317
3770
|
subjectType === "line-vertical" && /* @__PURE__ */ jsx(LineSubject, {
|
|
3318
3771
|
min: yMax,
|
|
3319
3772
|
max: yMin,
|
|
@@ -3347,8 +3800,6 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3347
3800
|
title,
|
|
3348
3801
|
subtitle,
|
|
3349
3802
|
...styles?.label,
|
|
3350
|
-
anchorLineStroke: resolveColor(styles?.label?.anchorLineStroke),
|
|
3351
|
-
backgroundFill: resolveColor(styles?.label?.backgroundFill),
|
|
3352
3803
|
...labelPosition,
|
|
3353
3804
|
horizontalAnchor: getHorizontalAnchor(subjectType, isFlippedHorizontally),
|
|
3354
3805
|
verticalAnchor: getVerticalAnchor(subjectType, isFlippedVertically, y, yMax, height ?? ANNOTATION_INIT_HEIGHT)
|
|
@@ -3396,16 +3847,33 @@ const toNumber = (val) => {
|
|
|
3396
3847
|
const num = typeof val === "number" ? val : parseFloat(val);
|
|
3397
3848
|
return isNaN(num) ? void 0 : num;
|
|
3398
3849
|
};
|
|
3850
|
+
const TOOLTIP_DATE = {};
|
|
3851
|
+
const TOOLTIP_FORMAT_BY_RESOLUTION$1 = {
|
|
3852
|
+
hour: {
|
|
3853
|
+
year: "numeric",
|
|
3854
|
+
month: "numeric",
|
|
3855
|
+
day: "numeric",
|
|
3856
|
+
hour: "numeric"
|
|
3857
|
+
},
|
|
3858
|
+
day: TOOLTIP_DATE,
|
|
3859
|
+
month: TOOLTIP_DATE,
|
|
3860
|
+
year: TOOLTIP_DATE
|
|
3861
|
+
};
|
|
3862
|
+
const TooltipDate = ({ date, displayResolution }) => {
|
|
3863
|
+
const formatting = useChartFormatting();
|
|
3864
|
+
const format = useMemo(() => createDateFormatter(TOOLTIP_FORMAT_BY_RESOLUTION$1[displayResolution], formatting), [displayResolution, formatting]);
|
|
3865
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: date ? format(date) : null });
|
|
3866
|
+
};
|
|
3399
3867
|
/**
|
|
3400
3868
|
* Default visx-tooltip render that prints the hovered date as a heading and
|
|
3401
3869
|
* one row per visible series (label + formatted value), sorted descending by
|
|
3402
3870
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
3403
3871
|
*
|
|
3404
|
-
* @param params - visx `RenderTooltipParams< DataPointDate
|
|
3872
|
+
* @param params - visx `RenderTooltipParams< DataPointDate >`, plus the chart's optional `bucketInfo`.
|
|
3405
3873
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
3406
3874
|
*/
|
|
3407
3875
|
const renderDefaultTooltip = (params) => {
|
|
3408
|
-
const { tooltipData } = params;
|
|
3876
|
+
const { tooltipData, bucketInfo } = params;
|
|
3409
3877
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
3410
3878
|
if (!nearestDatum) return null;
|
|
3411
3879
|
const tooltipPoints = Object.entries(tooltipData?.datumByKey || {}).map(([key, { datum }]) => ({
|
|
@@ -3416,7 +3884,10 @@ const renderDefaultTooltip = (params) => {
|
|
|
3416
3884
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
3417
3885
|
children: [/* @__PURE__ */ jsx("div", {
|
|
3418
3886
|
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
3419
|
-
children:
|
|
3887
|
+
children: /* @__PURE__ */ jsx(TooltipDate, {
|
|
3888
|
+
date: nearestDatum.date,
|
|
3889
|
+
displayResolution: bucketInfo?.displayResolution ?? "day"
|
|
3890
|
+
})
|
|
3420
3891
|
}), tooltipPoints.map((point) => /* @__PURE__ */ jsxs(Stack, {
|
|
3421
3892
|
direction: "row",
|
|
3422
3893
|
align: "center",
|
|
@@ -3465,9 +3936,9 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3465
3936
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
3466
3937
|
const legendShape = legend.shape ?? "line";
|
|
3467
3938
|
const legendPosition = legend.position ?? "bottom";
|
|
3468
|
-
const
|
|
3939
|
+
const formatting = useChartFormatting();
|
|
3469
3940
|
const theme = useXYChartTheme(data);
|
|
3470
|
-
const resolvedBackgroundColor = theme.backgroundColor
|
|
3941
|
+
const resolvedBackgroundColor = theme.backgroundColor;
|
|
3471
3942
|
const chartId = useChartId(providedChartId);
|
|
3472
3943
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
3473
3944
|
const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
|
|
@@ -3541,17 +4012,17 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3541
4012
|
onActivate: activateSelectedPoint
|
|
3542
4013
|
});
|
|
3543
4014
|
const chartOptions = useMemo(() => {
|
|
3544
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
3545
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
3546
4015
|
return {
|
|
3547
4016
|
axis: {
|
|
3548
|
-
x: {
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
4017
|
+
x: buildTimeAxisOptions({
|
|
4018
|
+
dataSorted,
|
|
4019
|
+
width,
|
|
4020
|
+
axisOptions: options?.axis?.x,
|
|
4021
|
+
scaleDomain: options?.xScale?.domain,
|
|
4022
|
+
zoomDomain: zoom.domain,
|
|
4023
|
+
formatting,
|
|
4024
|
+
isSeriesRendered: (series) => isSeriesVisible(series.label)
|
|
4025
|
+
}),
|
|
3555
4026
|
y: {
|
|
3556
4027
|
orientation: "left",
|
|
3557
4028
|
numTicks: 4,
|
|
@@ -3578,7 +4049,14 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3578
4049
|
dataSorted,
|
|
3579
4050
|
width,
|
|
3580
4051
|
zoom.domain,
|
|
3581
|
-
stableYDomain
|
|
4052
|
+
stableYDomain,
|
|
4053
|
+
formatting,
|
|
4054
|
+
isSeriesVisible
|
|
4055
|
+
]);
|
|
4056
|
+
const bucketInfo = useMemo(() => getBucketInfo(dataSorted.filter((series) => isSeriesVisible(series.label)), options?.axis?.x?.tickResolution), [
|
|
4057
|
+
dataSorted,
|
|
4058
|
+
isSeriesVisible,
|
|
4059
|
+
options?.axis?.x?.tickResolution
|
|
3582
4060
|
]);
|
|
3583
4061
|
const tooltipRenderGlyph = useMemo(() => {
|
|
3584
4062
|
return (props) => {
|
|
@@ -3640,6 +4118,10 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3640
4118
|
xAccessor: (d) => d?.date,
|
|
3641
4119
|
yAccessor: (d) => d?.value
|
|
3642
4120
|
};
|
|
4121
|
+
const tooltipRenderer = useMemo(() => (params) => renderTooltip({
|
|
4122
|
+
...params,
|
|
4123
|
+
bucketInfo
|
|
4124
|
+
}), [renderTooltip, bucketInfo]);
|
|
3643
4125
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
3644
4126
|
className: clsx("line-chart", line_chart_module_default["line-chart"]),
|
|
3645
4127
|
children: error
|
|
@@ -3688,7 +4170,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3688
4170
|
onBlur: onChartBlur,
|
|
3689
4171
|
children: chartHeight > 0 && /* @__PURE__ */ jsxs("div", {
|
|
3690
4172
|
ref: chartRef,
|
|
3691
|
-
|
|
4173
|
+
className: xy_plot_module_default["xy-plot"],
|
|
3692
4174
|
children: [zoomable && zoom.domain && /* @__PURE__ */ jsx(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ jsxs(XYChart, {
|
|
3693
4175
|
theme,
|
|
3694
4176
|
width,
|
|
@@ -3780,7 +4262,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3780
4262
|
snapTooltipToDatumX: true,
|
|
3781
4263
|
snapTooltipToDatumY: true,
|
|
3782
4264
|
showSeriesGlyphs: true,
|
|
3783
|
-
renderTooltip,
|
|
4265
|
+
renderTooltip: tooltipRenderer,
|
|
3784
4266
|
renderGlyph: tooltipRenderGlyph,
|
|
3785
4267
|
glyphStyle,
|
|
3786
4268
|
showVerticalCrosshair: withTooltipCrosshairs?.showVertical,
|
|
@@ -3918,12 +4400,11 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
|
|
|
3918
4400
|
};
|
|
3919
4401
|
//#endregion
|
|
3920
4402
|
//#region src/charts/area-chart/area-chart.tsx
|
|
3921
|
-
const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange
|
|
4403
|
+
const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
3922
4404
|
const legendInteractive = legend.interactive ?? false;
|
|
3923
4405
|
const legendShape = legend.shape ?? "rect";
|
|
3924
4406
|
const legendPosition = legend.position ?? "bottom";
|
|
3925
|
-
const
|
|
3926
|
-
const providerTheme = useGlobalChartsTheme();
|
|
4407
|
+
const formatting = useChartFormatting();
|
|
3927
4408
|
const theme = useXYChartTheme(data);
|
|
3928
4409
|
const chartId = useChartId(providedChartId);
|
|
3929
4410
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -3973,7 +4454,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3973
4454
|
totalPoints: dataSorted[0]?.data.length || 0
|
|
3974
4455
|
});
|
|
3975
4456
|
const fixedYDomain = useMemo(() => {
|
|
3976
|
-
if (
|
|
4457
|
+
if (rescaleYOnVisibilityChange || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
|
|
3977
4458
|
if (stacked) {
|
|
3978
4459
|
const numPoints = Math.max(...dataSorted.map((s) => s.data.length));
|
|
3979
4460
|
let posMax = 0;
|
|
@@ -4007,20 +4488,19 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4007
4488
|
dataSorted,
|
|
4008
4489
|
stacked,
|
|
4009
4490
|
stackOffset,
|
|
4010
|
-
|
|
4491
|
+
rescaleYOnVisibilityChange
|
|
4011
4492
|
]);
|
|
4012
4493
|
const chartOptions = useMemo(() => {
|
|
4013
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
4014
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
4015
4494
|
return {
|
|
4016
4495
|
axis: {
|
|
4017
|
-
x: {
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4496
|
+
x: buildTimeAxisOptions({
|
|
4497
|
+
dataSorted,
|
|
4498
|
+
width,
|
|
4499
|
+
axisOptions: options?.axis?.x,
|
|
4500
|
+
scaleDomain: options?.xScale?.domain,
|
|
4501
|
+
zoomDomain: zoom.domain,
|
|
4502
|
+
formatting
|
|
4503
|
+
}),
|
|
4024
4504
|
y: {
|
|
4025
4505
|
orientation: "left",
|
|
4026
4506
|
numTicks: 4,
|
|
@@ -4048,7 +4528,8 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4048
4528
|
width,
|
|
4049
4529
|
stacked,
|
|
4050
4530
|
fixedYDomain,
|
|
4051
|
-
zoom.domain
|
|
4531
|
+
zoom.domain,
|
|
4532
|
+
formatting
|
|
4052
4533
|
]);
|
|
4053
4534
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme);
|
|
4054
4535
|
const error = validateData$3(dataSorted);
|
|
@@ -4084,9 +4565,17 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4084
4565
|
};
|
|
4085
4566
|
const zeroYAccessor = useCallback(() => 0, []);
|
|
4086
4567
|
const visibleLabels = useMemo(() => new Set(seriesWithVisibility.filter((s) => s.isVisible).map((s) => s.series.label)), [seriesWithVisibility]);
|
|
4568
|
+
const bucketInfo = useMemo(() => getBucketInfo(dataSorted.filter((series) => visibleLabels.has(series.label)), options?.axis?.x?.tickResolution), [
|
|
4569
|
+
dataSorted,
|
|
4570
|
+
visibleLabels,
|
|
4571
|
+
options?.axis?.x?.tickResolution
|
|
4572
|
+
]);
|
|
4087
4573
|
const filteredRenderTooltip = useCallback((params) => {
|
|
4088
4574
|
const datumByKey = params?.tooltipData?.datumByKey;
|
|
4089
|
-
if (!datumByKey) return renderTooltip(
|
|
4575
|
+
if (!datumByKey) return renderTooltip({
|
|
4576
|
+
...params,
|
|
4577
|
+
bucketInfo
|
|
4578
|
+
});
|
|
4090
4579
|
const filtered = Object.fromEntries(Object.entries(datumByKey).filter(([key]) => visibleLabels.has(key)));
|
|
4091
4580
|
if (Object.keys(filtered).length === 0) return null;
|
|
4092
4581
|
const nearestDatum = params?.tooltipData?.nearestDatum;
|
|
@@ -4096,13 +4585,18 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4096
4585
|
};
|
|
4097
4586
|
return renderTooltip({
|
|
4098
4587
|
...params,
|
|
4588
|
+
bucketInfo,
|
|
4099
4589
|
tooltipData: {
|
|
4100
4590
|
...params.tooltipData,
|
|
4101
4591
|
datumByKey: filtered,
|
|
4102
4592
|
nearestDatum: nextNearest
|
|
4103
4593
|
}
|
|
4104
4594
|
});
|
|
4105
|
-
}, [
|
|
4595
|
+
}, [
|
|
4596
|
+
renderTooltip,
|
|
4597
|
+
visibleLabels,
|
|
4598
|
+
bucketInfo
|
|
4599
|
+
]);
|
|
4106
4600
|
const resolvedFillOpacity = fillOpacity ?? (stacked ? .85 : .4);
|
|
4107
4601
|
const resolvedWithStroke = withStroke ?? !stacked;
|
|
4108
4602
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
@@ -4177,7 +4671,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4177
4671
|
onBlur: onChartBlur,
|
|
4178
4672
|
children: chartHeight > 0 && /* @__PURE__ */ jsxs("div", {
|
|
4179
4673
|
ref: chartRef,
|
|
4180
|
-
|
|
4674
|
+
className: xy_plot_module_default["xy-plot"],
|
|
4181
4675
|
children: [zoomable && zoom.domain && /* @__PURE__ */ jsx(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ jsxs(XYChart, {
|
|
4182
4676
|
theme,
|
|
4183
4677
|
width,
|
|
@@ -4233,7 +4727,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4233
4727
|
stacked,
|
|
4234
4728
|
stackOffset,
|
|
4235
4729
|
getElementStyles,
|
|
4236
|
-
strokeColor: theme.backgroundColor
|
|
4730
|
+
strokeColor: theme.backgroundColor
|
|
4237
4731
|
})] }),
|
|
4238
4732
|
/* @__PURE__ */ jsx(AreaChartScalesRef, {
|
|
4239
4733
|
chartRef: internalChartRef,
|
|
@@ -4401,8 +4895,7 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4401
4895
|
year: "numeric",
|
|
4402
4896
|
month: "long",
|
|
4403
4897
|
day: "numeric",
|
|
4404
|
-
hour: "numeric"
|
|
4405
|
-
hour12: true
|
|
4898
|
+
hour: "numeric"
|
|
4406
4899
|
},
|
|
4407
4900
|
day: {
|
|
4408
4901
|
year: "numeric",
|
|
@@ -4421,16 +4914,16 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4421
4914
|
*
|
|
4422
4915
|
* @param data - Date-based series, already parsed and sorted by `useChartDataTransform`.
|
|
4423
4916
|
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
4917
|
+
* @param formatting - Host locale and time zone.
|
|
4424
4918
|
* @return Tooltip label formatter.
|
|
4425
4919
|
*/
|
|
4426
|
-
const getTooltipFormatter = (data, tickResolution) => {
|
|
4427
|
-
if (tickResolution === "week")
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
}));
|
|
4920
|
+
const getTooltipFormatter = (data, tickResolution, formatting) => {
|
|
4921
|
+
if (tickResolution === "week") {
|
|
4922
|
+
const formatDay = createDateFormatter(TOOLTIP_FORMAT_BY_RESOLUTION.day, formatting);
|
|
4923
|
+
return (timestamp) => sprintf(__("Week of %s", "jetpack-charts"), formatDay(timestamp));
|
|
4924
|
+
}
|
|
4432
4925
|
const format = TOOLTIP_FORMAT_BY_RESOLUTION[getBucketResolution(data, tickResolution)] ?? TOOLTIP_FORMAT_BY_RESOLUTION.day;
|
|
4433
|
-
return (
|
|
4926
|
+
return createDateFormatter(format, formatting);
|
|
4434
4927
|
};
|
|
4435
4928
|
const identity = (label) => label;
|
|
4436
4929
|
const byBucket = (format) => (bucket) => typeof bucket === "string" ? bucket : format(Number(bucket));
|
|
@@ -4481,6 +4974,7 @@ const getGroupPadding = (scale) => {
|
|
|
4481
4974
|
*/
|
|
4482
4975
|
function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = ALL_RENDERED) {
|
|
4483
4976
|
const stableOptions = useDeepMemo(options);
|
|
4977
|
+
const formatting = useChartFormatting();
|
|
4484
4978
|
const axisConfig = useMemo(() => {
|
|
4485
4979
|
const { labelOverflow: xLabelOverflow, tickResolution: xTickResolution, tickFormat: xTickFormat, ...xAxisOptions } = stableOptions.axis?.x || {};
|
|
4486
4980
|
const { labelOverflow: yLabelOverflow, tickResolution: yTickResolution, tickFormat: yTickFormat, ...yAxisOptions } = stableOptions.axis?.y || {};
|
|
@@ -4507,9 +5001,9 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4507
5001
|
zero: false
|
|
4508
5002
|
};
|
|
4509
5003
|
const hasLabels = Boolean(data?.[0]?.data?.[0]?.label);
|
|
4510
|
-
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution);
|
|
5004
|
+
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution, formatting);
|
|
4511
5005
|
const labelFormatter = timeTickFormatter ? byBucket(timeTickFormatter) : identity;
|
|
4512
|
-
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution));
|
|
5006
|
+
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution, formatting));
|
|
4513
5007
|
const valueFormatter = formatNumberCompact;
|
|
4514
5008
|
const bandDomain = timeTickFormatter ? getBandDomain(data, isSeriesRendered) : null;
|
|
4515
5009
|
const valueAccessor = (d) => {
|
|
@@ -4545,7 +5039,8 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4545
5039
|
}, [
|
|
4546
5040
|
data,
|
|
4547
5041
|
tickResolution,
|
|
4548
|
-
isSeriesRendered
|
|
5042
|
+
isSeriesRendered,
|
|
5043
|
+
formatting
|
|
4549
5044
|
]);
|
|
4550
5045
|
return useMemo(() => {
|
|
4551
5046
|
const { xTickFormat: defaultXTickFormat, yTickFormat: defaultYTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
|
|
@@ -5054,6 +5549,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5054
5549
|
onBlur: onChartBlur,
|
|
5055
5550
|
children: chartHeight > 0 && /* @__PURE__ */ jsx("div", {
|
|
5056
5551
|
ref: chartRef,
|
|
5552
|
+
className: xy_plot_module_default["xy-plot"],
|
|
5057
5553
|
children: /* @__PURE__ */ jsxs(XYChart, {
|
|
5058
5554
|
theme,
|
|
5059
5555
|
width,
|
|
@@ -5221,7 +5717,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5221
5717
|
right: 20,
|
|
5222
5718
|
bottom: 0,
|
|
5223
5719
|
top: 0
|
|
5224
|
-
}, ...rest }) => {
|
|
5720
|
+
}, className, ...rest }) => {
|
|
5225
5721
|
const { getElementStyles } = useGlobalChartsContext();
|
|
5226
5722
|
const tintedData = useMemo(() => {
|
|
5227
5723
|
if (data.length > 1) return data;
|
|
@@ -5273,6 +5769,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5273
5769
|
return /* @__PURE__ */ jsx(BarChart, {
|
|
5274
5770
|
orientation: "horizontal",
|
|
5275
5771
|
gridVisibility: "none",
|
|
5772
|
+
className: clsx("bar-list-chart", className),
|
|
5276
5773
|
data: tintedData,
|
|
5277
5774
|
width,
|
|
5278
5775
|
height,
|
|
@@ -5309,6 +5806,9 @@ const BarListChartResponsive = withResponsive(BarListChart);
|
|
|
5309
5806
|
var conversion_funnel_chart_module_default = {
|
|
5310
5807
|
"bar-container": "a8ccharts-mGEVca-bar-container",
|
|
5311
5808
|
"change-indicator": "a8ccharts-mGEVca-change-indicator",
|
|
5809
|
+
"change-indicator--negative": "a8ccharts-mGEVca-change-indicator--negative",
|
|
5810
|
+
"change-indicator--positive": "a8ccharts-mGEVca-change-indicator--positive",
|
|
5811
|
+
"conversion-funnel-chart": "a8ccharts-mGEVca-conversion-funnel-chart",
|
|
5312
5812
|
"conversion-funnel-chart--loading": "a8ccharts-mGEVca-conversion-funnel-chart--loading",
|
|
5313
5813
|
"empty-state": "a8ccharts-mGEVca-empty-state",
|
|
5314
5814
|
"funnel-bar": "a8ccharts-mGEVca-funnel-bar",
|
|
@@ -5389,23 +5889,14 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
5389
5889
|
*/
|
|
5390
5890
|
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip }) => {
|
|
5391
5891
|
const chartId = useChartId(providedChartId);
|
|
5392
|
-
const { conversionFunnelChart: conversionFunnelChartSettings } = useGlobalChartsTheme();
|
|
5393
5892
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
5394
5893
|
const chartRef = useRef(null);
|
|
5395
5894
|
const selectedBarRef = useRef(null);
|
|
5396
5895
|
const [scopeNode, setScopeNode] = useState(null);
|
|
5397
5896
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = useTooltip();
|
|
5398
5897
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
|
|
5399
|
-
const
|
|
5400
|
-
detectBounds: true,
|
|
5401
|
-
scroll: true
|
|
5402
|
-
});
|
|
5403
|
-
const portalContainerRefRef = useRef(portalContainerRef);
|
|
5404
|
-
useEffect(() => {
|
|
5405
|
-
portalContainerRefRef.current = portalContainerRef;
|
|
5406
|
-
}, [portalContainerRef]);
|
|
5898
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
5407
5899
|
const setChartRef = useCallback((node) => {
|
|
5408
|
-
portalContainerRefRef.current(node);
|
|
5409
5900
|
chartRef.current = node;
|
|
5410
5901
|
setScopeNode(node);
|
|
5411
5902
|
}, []);
|
|
@@ -5422,30 +5913,22 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5422
5913
|
});
|
|
5423
5914
|
}, [showTooltip]);
|
|
5424
5915
|
const getMouseTooltipCoords = useCallback((event) => {
|
|
5425
|
-
|
|
5916
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5917
|
+
if (!bounds) return null;
|
|
5426
5918
|
return {
|
|
5427
|
-
x: event.clientX -
|
|
5428
|
-
y: event.clientY -
|
|
5919
|
+
x: event.clientX - bounds.left,
|
|
5920
|
+
y: event.clientY - bounds.top
|
|
5429
5921
|
};
|
|
5430
|
-
}, [
|
|
5431
|
-
containerBounds.width,
|
|
5432
|
-
containerBounds.height,
|
|
5433
|
-
containerBounds.left,
|
|
5434
|
-
containerBounds.top
|
|
5435
|
-
]);
|
|
5922
|
+
}, []);
|
|
5436
5923
|
const getKeyboardTooltipCoords = useCallback((event) => {
|
|
5437
|
-
|
|
5924
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5925
|
+
if (!bounds) return null;
|
|
5438
5926
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
5439
5927
|
return {
|
|
5440
|
-
x: rect.left + rect.width / 2 -
|
|
5441
|
-
y: rect.top -
|
|
5928
|
+
x: rect.left + rect.width / 2 - bounds.left,
|
|
5929
|
+
y: rect.top - bounds.top
|
|
5442
5930
|
};
|
|
5443
|
-
}, [
|
|
5444
|
-
containerBounds.width,
|
|
5445
|
-
containerBounds.height,
|
|
5446
|
-
containerBounds.left,
|
|
5447
|
-
containerBounds.top
|
|
5448
|
-
]);
|
|
5931
|
+
}, []);
|
|
5449
5932
|
const handleStepInteraction = useCallback((step, event, interactionType) => {
|
|
5450
5933
|
selectedBarRef.current = event.currentTarget;
|
|
5451
5934
|
const { isClicked } = getStepState(step.id);
|
|
@@ -5506,19 +5989,14 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5506
5989
|
};
|
|
5507
5990
|
}, [clearSelectionAndRef]);
|
|
5508
5991
|
const resolvedHeight = height ?? style?.height ?? "100%";
|
|
5509
|
-
const {
|
|
5510
|
-
const
|
|
5511
|
-
|
|
5512
|
-
overrideColor: primaryColor
|
|
5513
|
-
}) : { color: primaryColor || "#000000" };
|
|
5514
|
-
const changeColor = changeIndicator?.startsWith("+") ? positiveChangeColor : negativeChangeColor;
|
|
5515
|
-
const barBackgroundColor = backgroundColor || hexToRgba(barColor, .08) || "rgba(0, 0, 0, 0.08)";
|
|
5992
|
+
const { color: barColor } = getElementStyles ? getElementStyles({ index: 0 }) : { color: "#000000" };
|
|
5993
|
+
const isPositiveChange = changeIndicator?.startsWith("+");
|
|
5994
|
+
const changeColor = isPositiveChange ? CATALOG_POINTERS.trendUp : CATALOG_POINTERS.trendDown;
|
|
5516
5995
|
const renderDefaultMainMetric = () => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
5517
5996
|
className: conversion_funnel_chart_module_default["main-rate"],
|
|
5518
5997
|
children: formatPercentage(mainRate)
|
|
5519
5998
|
}), changeIndicator && /* @__PURE__ */ jsx("span", {
|
|
5520
|
-
className: conversion_funnel_chart_module_default["change-indicator"],
|
|
5521
|
-
style: { color: changeColor },
|
|
5999
|
+
className: clsx(conversion_funnel_chart_module_default["change-indicator"], conversion_funnel_chart_module_default[isPositiveChange ? "change-indicator--positive" : "change-indicator--negative"]),
|
|
5522
6000
|
children: changeIndicator
|
|
5523
6001
|
})] });
|
|
5524
6002
|
const renderDefaultTooltip = (step) => /* @__PURE__ */ jsxs(Stack, {
|
|
@@ -5556,7 +6034,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5556
6034
|
align: "center",
|
|
5557
6035
|
justify: "center",
|
|
5558
6036
|
ref: setScopeNode,
|
|
5559
|
-
className: clsx(conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
6037
|
+
className: clsx("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
5560
6038
|
style: {
|
|
5561
6039
|
...style,
|
|
5562
6040
|
height: resolvedHeight
|
|
@@ -5567,16 +6045,16 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5567
6045
|
})
|
|
5568
6046
|
});
|
|
5569
6047
|
const maxRate = Math.max(...steps.map((step) => step.rate));
|
|
5570
|
-
return /* @__PURE__ */ jsxs(
|
|
6048
|
+
return /* @__PURE__ */ jsxs(Stack, {
|
|
5571
6049
|
direction: "column",
|
|
5572
6050
|
gap: "xl",
|
|
5573
6051
|
ref: setChartRef,
|
|
5574
|
-
className: clsx(conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
6052
|
+
className: clsx("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
5575
6053
|
style: {
|
|
5576
6054
|
...style,
|
|
5577
6055
|
height: resolvedHeight
|
|
5578
6056
|
},
|
|
5579
|
-
children: /* @__PURE__ */ jsxs(ChartScopeContext.Provider, {
|
|
6057
|
+
children: [/* @__PURE__ */ jsxs(ChartScopeContext.Provider, {
|
|
5580
6058
|
value: scopeNode,
|
|
5581
6059
|
children: [renderMainMetric ? renderMainMetric({
|
|
5582
6060
|
mainRate,
|
|
@@ -5628,7 +6106,6 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5628
6106
|
role: "button",
|
|
5629
6107
|
tabIndex: isBlurred ? -1 : 0,
|
|
5630
6108
|
"aria-label": step.label,
|
|
5631
|
-
style: { backgroundColor: barBackgroundColor },
|
|
5632
6109
|
children: /* @__PURE__ */ jsx("div", {
|
|
5633
6110
|
className: clsx(conversion_funnel_chart_module_default["funnel-bar"], { [conversion_funnel_chart_module_default["funnel-bar--animated"]]: animation && !loading && !prefersReducedMotion }),
|
|
5634
6111
|
style: {
|
|
@@ -5640,23 +6117,23 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5640
6117
|
}, step.id);
|
|
5641
6118
|
})
|
|
5642
6119
|
})]
|
|
5643
|
-
})
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
}
|
|
5659
|
-
})
|
|
6120
|
+
}), tooltipOpen && tooltipData && (() => {
|
|
6121
|
+
const tooltipContent = renderTooltip ? renderTooltip({
|
|
6122
|
+
step: tooltipData,
|
|
6123
|
+
index: steps.findIndex((s) => s.id === tooltipData.id),
|
|
6124
|
+
top: tooltipTop,
|
|
6125
|
+
left: tooltipLeft,
|
|
6126
|
+
className: conversion_funnel_chart_module_default["tooltip-wrapper"]
|
|
6127
|
+
}) : renderDefaultTooltip(tooltipData);
|
|
6128
|
+
if (!tooltipContent) return null;
|
|
6129
|
+
return /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
6130
|
+
top: tooltipTop,
|
|
6131
|
+
left: tooltipLeft,
|
|
6132
|
+
className: clsx(standaloneScopeClass, conversion_funnel_chart_module_default["tooltip-wrapper"]),
|
|
6133
|
+
children: tooltipContent
|
|
6134
|
+
});
|
|
6135
|
+
})()]
|
|
6136
|
+
});
|
|
5660
6137
|
};
|
|
5661
6138
|
/**
|
|
5662
6139
|
* ConversionFunnelChart component with provider wrapper
|
|
@@ -5802,7 +6279,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
5802
6279
|
* @return A React component displaying an interactive map with data visualization
|
|
5803
6280
|
*/
|
|
5804
6281
|
const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", onError, renderPlaceholder }) => {
|
|
5805
|
-
const { getElementStyles
|
|
6282
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
5806
6283
|
const scopeElement = useChartScopeElement();
|
|
5807
6284
|
const containerRef = useRef(null);
|
|
5808
6285
|
const reportedErrorIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
@@ -5836,8 +6313,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5836
6313
|
});
|
|
5837
6314
|
const fullColorHex = getElementStyles({ index: 0 }).color;
|
|
5838
6315
|
const lightColorHex = lightenHexColor(fullColorHex, .8);
|
|
5839
|
-
const backgroundColorHex = normalizeColorToHex(
|
|
5840
|
-
const defaultFillColorHex = normalizeColorToHex(
|
|
6316
|
+
const backgroundColorHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable) || DEFAULT_BACKGROUND_COLOR;
|
|
6317
|
+
const defaultFillColorHex = normalizeColorToHex(CATALOG_POINTERS.surfaceSecondary, scopeElement, resolveCssVariable) || DEFAULT_FEATURE_FILL_COLOR;
|
|
5841
6318
|
const sanitizedData = useMemo(() => {
|
|
5842
6319
|
if (data.length === 0) return {
|
|
5843
6320
|
data,
|
|
@@ -5898,8 +6375,7 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5898
6375
|
className: clsx("geo-chart", geo_chart_module_default.container, className),
|
|
5899
6376
|
style: {
|
|
5900
6377
|
width,
|
|
5901
|
-
height
|
|
5902
|
-
backgroundColor
|
|
6378
|
+
height
|
|
5903
6379
|
},
|
|
5904
6380
|
children: /* @__PURE__ */ jsx(Chart, {
|
|
5905
6381
|
chartType: "GeoChart",
|
|
@@ -5949,6 +6425,7 @@ var heatmap_chart_module_default = {
|
|
|
5949
6425
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
5950
6426
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
5951
6427
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
6428
|
+
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
5952
6429
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
5953
6430
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
5954
6431
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
@@ -6091,7 +6568,7 @@ const HeatmapContext = createContext(null);
|
|
|
6091
6568
|
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6092
6569
|
const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
6093
6570
|
const context = useContext(HeatmapContext);
|
|
6094
|
-
const { legend
|
|
6571
|
+
const { legend } = useGlobalChartsTheme();
|
|
6095
6572
|
if (!context) return null;
|
|
6096
6573
|
const { primaryColorHex } = context;
|
|
6097
6574
|
const labelStyle = legend.labelStyles;
|
|
@@ -6102,6 +6579,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6102
6579
|
children: [
|
|
6103
6580
|
/* @__PURE__ */ jsx(Text$1, {
|
|
6104
6581
|
variant: "body-sm",
|
|
6582
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6105
6583
|
style: labelStyle,
|
|
6106
6584
|
children: lessLabel ?? __("Less", "jetpack-charts")
|
|
6107
6585
|
}),
|
|
@@ -6115,7 +6593,6 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6115
6593
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6116
6594
|
style: {
|
|
6117
6595
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6118
|
-
"--a8c-charts-color-heatmap-background": backgroundColor,
|
|
6119
6596
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
6120
6597
|
}
|
|
6121
6598
|
}, index);
|
|
@@ -6123,6 +6600,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6123
6600
|
}),
|
|
6124
6601
|
/* @__PURE__ */ jsx(Text$1, {
|
|
6125
6602
|
variant: "body-sm",
|
|
6603
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6126
6604
|
style: labelStyle,
|
|
6127
6605
|
children: moreLabel ?? __("More", "jetpack-charts")
|
|
6128
6606
|
})
|
|
@@ -6140,17 +6618,14 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6140
6618
|
const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
|
|
6141
6619
|
const [selectedIndex, setSelectedIndex] = useState();
|
|
6142
6620
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = useTooltip();
|
|
6143
|
-
const
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
});
|
|
6147
|
-
const containerBoundsRef = useRef(containerBounds);
|
|
6148
|
-
containerBoundsRef.current = containerBounds;
|
|
6621
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
6622
|
+
const containerRef = useRef(null);
|
|
6623
|
+
const getTooltipOrigin = useCallback(() => containerRef.current?.closest(`[data-chart-id="heatmap-chart-${chartId}"]`)?.getBoundingClientRect() ?? null, [chartId]);
|
|
6149
6624
|
const { color: primaryColorHex } = getElementStyles({
|
|
6150
6625
|
index: 0,
|
|
6151
|
-
overrideColor: primaryColor
|
|
6626
|
+
overrideColor: primaryColor
|
|
6152
6627
|
});
|
|
6153
|
-
const chartBackgroundHex = normalizeColorToHex(
|
|
6628
|
+
const chartBackgroundHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable);
|
|
6154
6629
|
const primaryHex = normalizeColorToHex(primaryColorHex);
|
|
6155
6630
|
const cellHasLightText = (intensity) => isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) && prefersLightText(mixHexColors(primaryHex, chartBackgroundHex, 1 - (CELL_MIX_FLOOR + .85 * intensity)));
|
|
6156
6631
|
const extent = useMemo(() => getValueExtent(data), [data]);
|
|
@@ -6226,19 +6701,21 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6226
6701
|
]);
|
|
6227
6702
|
const handleCellMouseMove = useCallback((event) => {
|
|
6228
6703
|
if (!withTooltips) return;
|
|
6704
|
+
const origin = getTooltipOrigin();
|
|
6705
|
+
if (!origin) return;
|
|
6229
6706
|
const target = event.currentTarget;
|
|
6230
6707
|
const columnIndex = Number(target.dataset.column);
|
|
6231
6708
|
const rowIndex = Number(target.dataset.row);
|
|
6232
|
-
const bounds = containerBoundsRef.current;
|
|
6233
6709
|
showTooltip({
|
|
6234
|
-
tooltipLeft: event.clientX -
|
|
6235
|
-
tooltipTop: event.clientY -
|
|
6710
|
+
tooltipLeft: event.clientX - origin.left,
|
|
6711
|
+
tooltipTop: event.clientY - origin.top,
|
|
6236
6712
|
tooltipData: buildTooltipData(columnIndex, rowIndex)
|
|
6237
6713
|
});
|
|
6238
6714
|
}, [
|
|
6239
6715
|
withTooltips,
|
|
6240
6716
|
showTooltip,
|
|
6241
|
-
buildTooltipData
|
|
6717
|
+
buildTooltipData,
|
|
6718
|
+
getTooltipOrigin
|
|
6242
6719
|
]);
|
|
6243
6720
|
const handleCellMouseLeave = useCallback(() => {
|
|
6244
6721
|
if (withTooltips && selectedIndex === void 0) hideTooltip();
|
|
@@ -6249,13 +6726,14 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6249
6726
|
]);
|
|
6250
6727
|
useEffect(() => {
|
|
6251
6728
|
if (!withTooltips || selectedIndex === void 0) return;
|
|
6729
|
+
const origin = getTooltipOrigin();
|
|
6730
|
+
if (!origin) return;
|
|
6252
6731
|
const col = Math.floor(selectedIndex / rows);
|
|
6253
6732
|
const row = selectedIndex % rows;
|
|
6254
6733
|
const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
|
|
6255
|
-
const bounds = containerBoundsRef.current;
|
|
6256
6734
|
showTooltip({
|
|
6257
|
-
tooltipLeft: rect ? rect.left + rect.width / 2 -
|
|
6258
|
-
tooltipTop: rect ? rect.top + rect.height / 2 -
|
|
6735
|
+
tooltipLeft: rect ? rect.left + rect.width / 2 - origin.left : 0,
|
|
6736
|
+
tooltipTop: rect ? rect.top + rect.height / 2 - origin.top : 0,
|
|
6259
6737
|
tooltipData: buildTooltipData(col, row)
|
|
6260
6738
|
});
|
|
6261
6739
|
}, [
|
|
@@ -6264,7 +6742,8 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6264
6742
|
rows,
|
|
6265
6743
|
chartId,
|
|
6266
6744
|
buildTooltipData,
|
|
6267
|
-
showTooltip
|
|
6745
|
+
showTooltip,
|
|
6746
|
+
getTooltipOrigin
|
|
6268
6747
|
]);
|
|
6269
6748
|
const defaultRenderTooltip = useCallback((info) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim() }), /* @__PURE__ */ jsx("div", { children: info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value) })] }), []);
|
|
6270
6749
|
if (!columns || !rows) return /* @__PURE__ */ jsx(Center, {
|
|
@@ -6282,7 +6761,6 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6282
6761
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
6283
6762
|
const gridStyle = {
|
|
6284
6763
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6285
|
-
"--a8c-charts-color-heatmap-background": theme.backgroundColor,
|
|
6286
6764
|
gridTemplateColumns: `auto repeat(${columns}, ${columnTrack})`,
|
|
6287
6765
|
gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
|
|
6288
6766
|
};
|
|
@@ -6380,11 +6858,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6380
6858
|
})]
|
|
6381
6859
|
}, `row-${rowIndex}`);
|
|
6382
6860
|
})]
|
|
6383
|
-
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(
|
|
6861
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
6384
6862
|
top: tooltipTop,
|
|
6385
6863
|
left: tooltipLeft,
|
|
6386
6864
|
children: /* @__PURE__ */ jsx("div", {
|
|
6387
|
-
className:
|
|
6865
|
+
className: standaloneScopeClass,
|
|
6388
6866
|
role: "tooltip",
|
|
6389
6867
|
tabIndex: -1,
|
|
6390
6868
|
children: (renderTooltip ?? defaultRenderTooltip)(tooltipData)
|
|
@@ -6408,7 +6886,7 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ jsx(HeatmapChartW
|
|
|
6408
6886
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
6409
6887
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
6410
6888
|
//#endregion
|
|
6411
|
-
//#region ../../../node_modules/.pnpm/is-plain-object@5.
|
|
6889
|
+
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
6412
6890
|
/*!
|
|
6413
6891
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
6414
6892
|
*
|
|
@@ -6475,7 +6953,7 @@ function paramCase(input, options) {
|
|
|
6475
6953
|
return dotCase(input, __assign({ delimiter: "-" }, options));
|
|
6476
6954
|
}
|
|
6477
6955
|
//#endregion
|
|
6478
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
6956
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
|
|
6479
6957
|
function useUpdateEffect(effect, deps) {
|
|
6480
6958
|
const mountedRef = useRef$1(false);
|
|
6481
6959
|
useEffect$1(() => {
|
|
@@ -8045,7 +8523,7 @@ _createEmotion.css;
|
|
|
8045
8523
|
_createEmotion.sheet;
|
|
8046
8524
|
_createEmotion.cache;
|
|
8047
8525
|
//#endregion
|
|
8048
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8526
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
|
|
8049
8527
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
8050
8528
|
var useCx = () => {
|
|
8051
8529
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8152,7 +8630,7 @@ function memize(fn, options) {
|
|
|
8152
8630
|
return memoized;
|
|
8153
8631
|
}
|
|
8154
8632
|
//#endregion
|
|
8155
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8633
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
|
|
8156
8634
|
var white = "#fff";
|
|
8157
8635
|
var GRAY = {
|
|
8158
8636
|
900: "#1e1e1e",
|
|
@@ -8231,7 +8709,7 @@ var COLORS = Object.freeze({
|
|
|
8231
8709
|
ui: UI
|
|
8232
8710
|
});
|
|
8233
8711
|
//#endregion
|
|
8234
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8712
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/config-values.mjs
|
|
8235
8713
|
var CONTROL_HEIGHT = "36px";
|
|
8236
8714
|
var CONTROL_PROPS = {
|
|
8237
8715
|
controlPaddingX: 12,
|
|
@@ -8246,9 +8724,6 @@ var CONTROL_PROPS = {
|
|
|
8246
8724
|
};
|
|
8247
8725
|
var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
8248
8726
|
colorDivider: "rgba(0, 0, 0, 0.1)",
|
|
8249
|
-
colorScrollbarThumb: "rgba(0, 0, 0, 0.2)",
|
|
8250
|
-
colorScrollbarThumbHover: "rgba(0, 0, 0, 0.5)",
|
|
8251
|
-
colorScrollbarTrack: "rgba(0, 0, 0, 0.04)",
|
|
8252
8727
|
elevationIntensity: 1,
|
|
8253
8728
|
radiusXSmall: "1px",
|
|
8254
8729
|
radiusSmall: "2px",
|
|
@@ -8259,7 +8734,6 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
|
8259
8734
|
borderWidth: "1px",
|
|
8260
8735
|
borderWidthFocus: "1.5px",
|
|
8261
8736
|
borderWidthTab: "4px",
|
|
8262
|
-
spinnerSize: 16,
|
|
8263
8737
|
fontSize: "13px",
|
|
8264
8738
|
fontSizeH1: "calc(2.44 * 13px)",
|
|
8265
8739
|
fontSizeH2: "calc(1.95 * 13px)",
|
|
@@ -8336,10 +8810,10 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
8336
8810
|
};
|
|
8337
8811
|
}));
|
|
8338
8812
|
//#endregion
|
|
8339
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.
|
|
8813
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
8340
8814
|
var logged = /* @__PURE__ */ new Set();
|
|
8341
8815
|
//#endregion
|
|
8342
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.
|
|
8816
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
8343
8817
|
function isDev() {
|
|
8344
8818
|
return globalThis.SCRIPT_DEBUG === true;
|
|
8345
8819
|
}
|
|
@@ -8353,7 +8827,7 @@ function warning(message) {
|
|
|
8353
8827
|
logged.add(message);
|
|
8354
8828
|
}
|
|
8355
8829
|
//#endregion
|
|
8356
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8830
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
8357
8831
|
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
8358
8832
|
var ComponentsContext = createContext$1(
|
|
8359
8833
|
/** @type {Record<string, any>} */
|
|
@@ -8380,18 +8854,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
8380
8854
|
};
|
|
8381
8855
|
memo(BaseContextSystemProvider);
|
|
8382
8856
|
//#endregion
|
|
8383
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8857
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/constants.mjs
|
|
8384
8858
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
8385
8859
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
8386
8860
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
8387
8861
|
//#endregion
|
|
8388
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8862
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
|
|
8389
8863
|
function getStyledClassName(namespace) {
|
|
8390
8864
|
return `components-${paramCase(namespace)}`;
|
|
8391
8865
|
}
|
|
8392
8866
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
8393
8867
|
//#endregion
|
|
8394
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8868
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/context-connect.mjs
|
|
8395
8869
|
function contextConnect(Component, namespace) {
|
|
8396
8870
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
8397
8871
|
}
|
|
@@ -8408,7 +8882,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
8408
8882
|
});
|
|
8409
8883
|
}
|
|
8410
8884
|
//#endregion
|
|
8411
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8885
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/utils.mjs
|
|
8412
8886
|
function getNamespace(componentName) {
|
|
8413
8887
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
8414
8888
|
}
|
|
@@ -8416,7 +8890,7 @@ function getConnectedNamespace() {
|
|
|
8416
8890
|
return { [CONNECTED_NAMESPACE]: true };
|
|
8417
8891
|
}
|
|
8418
8892
|
//#endregion
|
|
8419
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8893
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
|
|
8420
8894
|
function useContextSystem(props, namespace) {
|
|
8421
8895
|
const contextSystemProps = useComponentsContext();
|
|
8422
8896
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -8436,7 +8910,7 @@ function useContextSystem(props, namespace) {
|
|
|
8436
8910
|
return finalComponentProps;
|
|
8437
8911
|
}
|
|
8438
8912
|
//#endregion
|
|
8439
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8913
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
|
|
8440
8914
|
var visuallyHidden = {
|
|
8441
8915
|
border: 0,
|
|
8442
8916
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -8452,7 +8926,7 @@ var visuallyHidden = {
|
|
|
8452
8926
|
wordBreak: "normal"
|
|
8453
8927
|
};
|
|
8454
8928
|
//#endregion
|
|
8455
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8929
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
|
|
8456
8930
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
8457
8931
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
8458
8932
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -8542,7 +9016,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
8542
9016
|
}
|
|
8543
9017
|
var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
|
|
8544
9018
|
//#endregion
|
|
8545
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9019
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/view/component.mjs
|
|
8546
9020
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
8547
9021
|
return /* @__PURE__ */ jsx(PolymorphicElement, {
|
|
8548
9022
|
ref,
|
|
@@ -8551,7 +9025,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
8551
9025
|
}
|
|
8552
9026
|
var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
|
|
8553
9027
|
//#endregion
|
|
8554
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9028
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
|
|
8555
9029
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
8556
9030
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
8557
9031
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -8566,7 +9040,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
8566
9040
|
}
|
|
8567
9041
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
8568
9042
|
//#endregion
|
|
8569
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9043
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
|
|
8570
9044
|
var breakpoints = [
|
|
8571
9045
|
"40em",
|
|
8572
9046
|
"52em",
|
|
@@ -8600,7 +9074,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
8600
9074
|
return array[index >= array.length ? array.length - 1 : index];
|
|
8601
9075
|
}
|
|
8602
9076
|
//#endregion
|
|
8603
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9077
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/grid/utils.mjs
|
|
8604
9078
|
var ALIGNMENTS = {
|
|
8605
9079
|
bottom: {
|
|
8606
9080
|
alignItems: "flex-end",
|
|
@@ -8648,7 +9122,7 @@ function getAlignmentProps(alignment) {
|
|
|
8648
9122
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
8649
9123
|
}
|
|
8650
9124
|
//#endregion
|
|
8651
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9125
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/grid/hook.mjs
|
|
8652
9126
|
function useGrid(props) {
|
|
8653
9127
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
8654
9128
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -8669,7 +9143,7 @@ function useGrid(props) {
|
|
|
8669
9143
|
justifyContent: justify,
|
|
8670
9144
|
verticalAlign: isInline ? "middle" : void 0,
|
|
8671
9145
|
...alignmentProps
|
|
8672
|
-
}, process.env.NODE_ENV === "production" ? "" : ";label:gridClasses;", process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
9146
|
+
}, process.env.NODE_ENV === "production" ? "" : ";label:gridClasses;", process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImhvb2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBNENzQiIsImZpbGUiOiJob29rLnRzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3NzIH0gZnJvbSAnQGVtb3Rpb24vcmVhY3QnO1xuaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ0B3b3JkcHJlc3MvZWxlbWVudCc7XG5pbXBvcnQgdHlwZSB7IFdvcmRQcmVzc0NvbXBvbmVudFByb3BzIH0gZnJvbSAnLi4vY29udGV4dCc7XG5pbXBvcnQgeyB1c2VDb250ZXh0U3lzdGVtIH0gZnJvbSAnLi4vY29udGV4dCc7XG5pbXBvcnQgeyBnZXRBbGlnbm1lbnRQcm9wcyB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgdXNlUmVzcG9uc2l2ZVZhbHVlIH0gZnJvbSAnLi4vdXRpbHMvdXNlLXJlc3BvbnNpdmUtdmFsdWUnO1xuaW1wb3J0IENPTkZJRyBmcm9tICcuLi91dGlscy9jb25maWctdmFsdWVzJztcbmltcG9ydCB7IHVzZUN4IH0gZnJvbSAnLi4vdXRpbHMvaG9va3MvdXNlLWN4JztcbmltcG9ydCB0eXBlIHsgR3JpZFByb3BzIH0gZnJvbSAnLi90eXBlcyc7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVzZUdyaWQoXG5cdHByb3BzOiBXb3JkUHJlc3NDb21wb25lbnRQcm9wczwgR3JpZFByb3BzLCAnZGl2JyA+XG4pIHtcblx0Y29uc3Qge1xuXHRcdGFsaWduLFxuXHRcdGFsaWdubWVudCxcblx0XHRjbGFzc05hbWUsXG5cdFx0Y29sdW1uR2FwLFxuXHRcdGNvbHVtbnMgPSAyLFxuXHRcdGdhcCA9IDMsXG5cdFx0aXNJbmxpbmUgPSBmYWxzZSxcblx0XHRqdXN0aWZ5LFxuXHRcdHJvd0dhcCxcblx0XHRyb3dzLFxuXHRcdHRlbXBsYXRlQ29sdW1ucyxcblx0XHR0ZW1wbGF0ZVJvd3MsXG5cdFx0Li4ub3RoZXJQcm9wc1xuXHR9ID0gdXNlQ29udGV4dFN5c3RlbSggcHJvcHMsICdHcmlkJyApO1xuXG5cdGNvbnN0IGNvbHVtbnNBc0FycmF5ID0gQXJyYXkuaXNBcnJheSggY29sdW1ucyApID8gY29sdW1ucyA6IFsgY29sdW1ucyBdO1xuXHRjb25zdCBjb2x1bW4gPSB1c2VSZXNwb25zaXZlVmFsdWUoIGNvbHVtbnNBc0FycmF5ICk7XG5cdGNvbnN0IHJvd3NBc0FycmF5ID0gQXJyYXkuaXNBcnJheSggcm93cyApID8gcm93cyA6IFsgcm93cyBdO1xuXHRjb25zdCByb3cgPSB1c2VSZXNwb25zaXZlVmFsdWUoIHJvd3NBc0FycmF5ICk7XG5cblx0Y29uc3QgZ3JpZFRlbXBsYXRlQ29sdW1ucyA9XG5cdFx0dGVtcGxhdGVDb2x1bW5zIHx8ICggISEgY29sdW1ucyAmJiBgcmVwZWF0KCAkeyBjb2x1bW4gfSwgMWZyIClgICk7XG5cdGNvbnN0IGdyaWRUZW1wbGF0ZVJvd3MgPVxuXHRcdHRlbXBsYXRlUm93cyB8fCAoICEhIHJvd3MgJiYgYHJlcGVhdCggJHsgcm93IH0sIDFmciApYCApO1xuXG5cdGNvbnN0IGN4ID0gdXNlQ3goKTtcblxuXHRjb25zdCBjbGFzc2VzID0gdXNlTWVtbyggKCkgPT4ge1xuXHRcdGNvbnN0IGFsaWdubWVudFByb3BzID0gZ2V0QWxpZ25tZW50UHJvcHMoIGFsaWdubWVudCApO1xuXG5cdFx0Y29uc3QgZ3JpZENsYXNzZXMgPSBjc3MoIHtcblx0XHRcdGFsaWduSXRlbXM6IGFsaWduLFxuXHRcdFx0ZGlzcGxheTogaXNJbmxpbmUgPyAnaW5saW5lLWdyaWQnIDogJ2dyaWQnLFxuXHRcdFx0Z2FwOiBgY2FsYyggJHsgQ09ORklHLmdyaWRCYXNlIH0gKiAkeyBnYXAgfSApYCxcblx0XHRcdGdyaWRUZW1wbGF0ZUNvbHVtbnM6IGdyaWRUZW1wbGF0ZUNvbHVtbnMgfHwgdW5kZWZpbmVkLFxuXHRcdFx0Z3JpZFRlbXBsYXRlUm93czogZ3JpZFRlbXBsYXRlUm93cyB8fCB1bmRlZmluZWQsXG5cdFx0XHRncmlkUm93R2FwOiByb3dHYXAsXG5cdFx0XHRncmlkQ29sdW1uR2FwOiBjb2x1bW5HYXAsXG5cdFx0XHRqdXN0aWZ5Q29udGVudDoganVzdGlmeSxcblx0XHRcdHZlcnRpY2FsQWxpZ246IGlzSW5saW5lID8gJ21pZGRsZScgOiB1bmRlZmluZWQsXG5cdFx0XHQuLi5hbGlnbm1lbnRQcm9wcyxcblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gY3goIGdyaWRDbGFzc2VzLCBjbGFzc05hbWUgKTtcblx0fSwgW1xuXHRcdGFsaWduLFxuXHRcdGFsaWdubWVudCxcblx0XHRjbGFzc05hbWUsXG5cdFx0Y29sdW1uR2FwLFxuXHRcdGN4LFxuXHRcdGdhcCxcblx0XHRncmlkVGVtcGxhdGVDb2x1bW5zLFxuXHRcdGdyaWRUZW1wbGF0ZVJvd3MsXG5cdFx0aXNJbmxpbmUsXG5cdFx0anVzdGlmeSxcblx0XHRyb3dHYXAsXG5cdF0gKTtcblxuXHRyZXR1cm4geyAuLi5vdGhlclByb3BzLCBjbGFzc05hbWU6IGNsYXNzZXMgfTtcbn1cbiJdfQ== */");
|
|
8673
9147
|
return cx(gridClasses, className);
|
|
8674
9148
|
}, [
|
|
8675
9149
|
align,
|
|
@@ -8690,7 +9164,7 @@ function useGrid(props) {
|
|
|
8690
9164
|
};
|
|
8691
9165
|
}
|
|
8692
9166
|
//#endregion
|
|
8693
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9167
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/grid/component.mjs
|
|
8694
9168
|
function UnconnectedGrid(props, forwardedRef) {
|
|
8695
9169
|
const gridProps = useGrid(props);
|
|
8696
9170
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -8713,8 +9187,8 @@ const SUBPIXEL_TOLERANCE = .5;
|
|
|
8713
9187
|
* Counts how many leading rows fit inside the content container.
|
|
8714
9188
|
*
|
|
8715
9189
|
* Rows are read from the DOM rather than derived from constants: row height
|
|
8716
|
-
* depends on
|
|
8717
|
-
* as a label, so any restated number would drift.
|
|
9190
|
+
* depends on `--a8c-charts-dimension-leaderboard-row-gap`, label wrapping, and
|
|
9191
|
+
* whatever a caller renders as a label, so any restated number would drift.
|
|
8718
9192
|
*
|
|
8719
9193
|
* Every row is a direct grid child marked with `data-row-index`; interactive rows
|
|
8720
9194
|
* use a button wrapper and non-interactive rows use a div wrapper.
|
|
@@ -8799,14 +9273,13 @@ function useFittedRowCount(enabled, rowCount, data) {
|
|
|
8799
9273
|
* @return Array of legend items for the leaderboard chart
|
|
8800
9274
|
*/
|
|
8801
9275
|
function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withComparison = false, withOverlayLabel = false, legendLabels }) {
|
|
8802
|
-
const { leaderboardChart: leaderboardChartSettings } = useGlobalChartsTheme();
|
|
8803
9276
|
const { getElementStyles } = useGlobalChartsContext();
|
|
8804
9277
|
return useMemo(() => {
|
|
8805
9278
|
if (!data || data.length === 0) return [];
|
|
8806
9279
|
const items = [];
|
|
8807
9280
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
8808
9281
|
index: 0,
|
|
8809
|
-
overrideColor: primaryColor
|
|
9282
|
+
overrideColor: primaryColor
|
|
8810
9283
|
});
|
|
8811
9284
|
items.push({
|
|
8812
9285
|
label: legendLabels?.primary || __("Current period", "jetpack-charts"),
|
|
@@ -8815,7 +9288,7 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
8815
9288
|
if (withComparison && !withOverlayLabel) {
|
|
8816
9289
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
8817
9290
|
index: 1,
|
|
8818
|
-
overrideColor: secondaryColor
|
|
9291
|
+
overrideColor: secondaryColor
|
|
8819
9292
|
});
|
|
8820
9293
|
items.push({
|
|
8821
9294
|
label: legendLabels?.comparison || __("Previous period", "jetpack-charts"),
|
|
@@ -8829,7 +9302,6 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
8829
9302
|
secondaryColor,
|
|
8830
9303
|
withComparison,
|
|
8831
9304
|
legendLabels,
|
|
8832
|
-
leaderboardChartSettings,
|
|
8833
9305
|
getElementStyles,
|
|
8834
9306
|
withOverlayLabel
|
|
8835
9307
|
]);
|
|
@@ -8843,6 +9315,9 @@ var leaderboard_chart_module_default = {
|
|
|
8843
9315
|
"chevron": "a8ccharts-GovfoW-chevron",
|
|
8844
9316
|
"deltaPlaceholder": "a8ccharts-GovfoW-deltaPlaceholder",
|
|
8845
9317
|
"deltaValue": "a8ccharts-GovfoW-deltaValue",
|
|
9318
|
+
"deltaValue--down": "a8ccharts-GovfoW-deltaValue--down",
|
|
9319
|
+
"deltaValue--neutral": "a8ccharts-GovfoW-deltaValue--neutral",
|
|
9320
|
+
"deltaValue--up": "a8ccharts-GovfoW-deltaValue--up",
|
|
8846
9321
|
"emptyState": "a8ccharts-GovfoW-emptyState",
|
|
8847
9322
|
"fitEmptyState": "a8ccharts-GovfoW-fitEmptyState",
|
|
8848
9323
|
"interactiveRow": "a8ccharts-GovfoW-interactiveRow",
|
|
@@ -8861,6 +9336,14 @@ var leaderboard_chart_module_default = {
|
|
|
8861
9336
|
};
|
|
8862
9337
|
//#endregion
|
|
8863
9338
|
//#region src/charts/leaderboard-chart/leaderboard-chart.tsx
|
|
9339
|
+
const ROW_GAP = "var(--a8c-charts-dimension-leaderboard-row-gap, 12px)";
|
|
9340
|
+
const COLUMN_GAP = "var(--a8c-charts-dimension-leaderboard-column-gap, 4px)";
|
|
9341
|
+
/** Indexed by `Math.sign( delta ) + 1`, so [negative, neutral, positive]. */
|
|
9342
|
+
const DELTA_TREND_CLASS = [
|
|
9343
|
+
"deltaValue--down",
|
|
9344
|
+
"deltaValue--neutral",
|
|
9345
|
+
"deltaValue--up"
|
|
9346
|
+
];
|
|
8864
9347
|
/**
|
|
8865
9348
|
* Default value formatter using formatMetricValue
|
|
8866
9349
|
*
|
|
@@ -8963,15 +9446,15 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
8963
9446
|
...legend.shapeStyles
|
|
8964
9447
|
};
|
|
8965
9448
|
const { legendChildren, nonLegendChildren } = useChartChildren(children, "LeaderboardChart");
|
|
8966
|
-
const { labelSpacing
|
|
9449
|
+
const { labelSpacing } = leaderboardChartSettings;
|
|
8967
9450
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
8968
9451
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
8969
9452
|
index: 0,
|
|
8970
|
-
overrideColor: primaryColor
|
|
9453
|
+
overrideColor: primaryColor
|
|
8971
9454
|
});
|
|
8972
9455
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
8973
9456
|
index: 1,
|
|
8974
|
-
overrideColor: secondaryColor
|
|
9457
|
+
overrideColor: secondaryColor
|
|
8975
9458
|
});
|
|
8976
9459
|
const legendItems = useLeaderboardLegendItems({
|
|
8977
9460
|
data: data || [],
|
|
@@ -9027,7 +9510,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9027
9510
|
legendPosition,
|
|
9028
9511
|
legendElement: false,
|
|
9029
9512
|
legendChildren,
|
|
9030
|
-
className: clsx(leaderboard_chart_module_default.leaderboardChart, {
|
|
9513
|
+
className: clsx("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
9031
9514
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
9032
9515
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
9033
9516
|
}, className),
|
|
@@ -9062,7 +9545,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9062
9545
|
legendPosition,
|
|
9063
9546
|
legendElement,
|
|
9064
9547
|
legendChildren,
|
|
9065
|
-
className: clsx(leaderboard_chart_module_default.leaderboardChart, {
|
|
9548
|
+
className: clsx("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
9066
9549
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
9067
9550
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
9068
9551
|
}, className),
|
|
@@ -9084,8 +9567,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9084
9567
|
children: getAllHiddenMessage(legendInteractive, "series")
|
|
9085
9568
|
}) : /* @__PURE__ */ jsx(component_default, {
|
|
9086
9569
|
templateColumns: "minmax(0, 1fr) auto",
|
|
9087
|
-
rowGap,
|
|
9088
|
-
columnGap,
|
|
9570
|
+
rowGap: ROW_GAP,
|
|
9571
|
+
columnGap: COLUMN_GAP,
|
|
9089
9572
|
"data-leaderboard-grid": true,
|
|
9090
9573
|
children: data.map((entry, rowIndex) => {
|
|
9091
9574
|
const rowStyle = shouldFitRows && rowIndex >= fittedCount ? { visibility: "hidden" } : void 0;
|
|
@@ -9094,8 +9577,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9094
9577
|
const hasDelta = hasDeltaValue(entry);
|
|
9095
9578
|
const showComparisonValue = showComparisonColumn && hasDelta;
|
|
9096
9579
|
const showComparisonPlaceholder = showComparisonColumn && !hasDelta;
|
|
9097
|
-
const
|
|
9098
|
-
const deltaColor = deltaColors[colorIndex];
|
|
9580
|
+
const deltaTrendClass = leaderboard_chart_module_default[DELTA_TREND_CLASS[showComparisonValue ? Math.sign(entry.delta) + 1 : 1]];
|
|
9099
9581
|
const rowCells = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Stack, {
|
|
9100
9582
|
direction: "column",
|
|
9101
9583
|
gap: labelSpacing,
|
|
@@ -9116,13 +9598,11 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9116
9598
|
children: [
|
|
9117
9599
|
isPrimaryVisible && /* @__PURE__ */ jsx(Text$1, { children: valueFormatter(entry.currentValue) }),
|
|
9118
9600
|
showComparisonValue && /* @__PURE__ */ jsx(Text$1, {
|
|
9119
|
-
className: leaderboard_chart_module_default.deltaValue,
|
|
9120
|
-
style: { color: deltaColor },
|
|
9601
|
+
className: clsx(leaderboard_chart_module_default.deltaValue, deltaTrendClass),
|
|
9121
9602
|
children: deltaFormatter(entry.delta)
|
|
9122
9603
|
}),
|
|
9123
9604
|
showComparisonPlaceholder && /* @__PURE__ */ jsxs(Text$1, {
|
|
9124
|
-
className: clsx(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder),
|
|
9125
|
-
style: { color: deltaColor },
|
|
9605
|
+
className: clsx(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder, deltaTrendClass),
|
|
9126
9606
|
children: [/* @__PURE__ */ jsx("span", {
|
|
9127
9607
|
"aria-hidden": "true",
|
|
9128
9608
|
children: "—"
|
|
@@ -9206,7 +9686,9 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
9206
9686
|
//#endregion
|
|
9207
9687
|
//#region src/charts/pie-chart/pie-chart.module.scss
|
|
9208
9688
|
var pie_chart_module_default = {
|
|
9209
|
-
"pie-
|
|
9689
|
+
"pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
|
|
9690
|
+
"pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
|
|
9691
|
+
"pie-chart__plot": "a8ccharts-gnszbG-pie-chart__plot",
|
|
9210
9692
|
"pie-chart--responsive": "a8ccharts-gnszbG-pie-chart--responsive"
|
|
9211
9693
|
};
|
|
9212
9694
|
//#endregion
|
|
@@ -9261,11 +9743,8 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9261
9743
|
const providerTheme = useGlobalChartsTheme();
|
|
9262
9744
|
const chartId = useChartId(providedChartId);
|
|
9263
9745
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = useTooltip();
|
|
9264
|
-
const
|
|
9265
|
-
|
|
9266
|
-
scroll: true,
|
|
9267
|
-
debounce: 0
|
|
9268
|
-
});
|
|
9746
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
9747
|
+
const containerRef = useRef(null);
|
|
9269
9748
|
const onMouseLeave = useCallback(() => {
|
|
9270
9749
|
if (!withTooltips) return;
|
|
9271
9750
|
hideTooltip();
|
|
@@ -9348,19 +9827,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9348
9827
|
width: propWidth || void 0,
|
|
9349
9828
|
height: propHeight || void 0
|
|
9350
9829
|
},
|
|
9351
|
-
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9352
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(TooltipInPortal, {
|
|
9353
|
-
top: tooltipTop || 0,
|
|
9354
|
-
left: tooltipLeft || 0,
|
|
9355
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
9356
|
-
className: "a8c-charts-scope",
|
|
9357
|
-
role: "tooltip",
|
|
9358
|
-
children: renderTooltip({ tooltipData })
|
|
9359
|
-
})
|
|
9360
|
-
}),
|
|
9361
|
-
htmlChildren,
|
|
9362
|
-
otherChildren
|
|
9363
|
-
] }),
|
|
9830
|
+
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [htmlChildren, otherChildren] }),
|
|
9364
9831
|
children: ({ contentWidth, contentHeight }) => {
|
|
9365
9832
|
const availableSize = Math.min(contentWidth > 0 ? contentWidth : 300, contentHeight > 0 ? contentHeight : 300);
|
|
9366
9833
|
const actualSize = size ? Math.min(size, availableSize) : availableSize;
|
|
@@ -9373,9 +9840,10 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9373
9840
|
const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
|
|
9374
9841
|
const maxCornerRadius = (outerRadius - innerRadius) / 2;
|
|
9375
9842
|
const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
|
|
9376
|
-
return /* @__PURE__ */
|
|
9843
|
+
return /* @__PURE__ */ jsxs(Center, {
|
|
9377
9844
|
ref: containerRef,
|
|
9378
|
-
|
|
9845
|
+
className: pie_chart_module_default["pie-chart__plot"],
|
|
9846
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
9379
9847
|
viewBox: `0 0 ${width} ${height}`,
|
|
9380
9848
|
preserveAspectRatio: "xMidYMid meet",
|
|
9381
9849
|
width,
|
|
@@ -9407,11 +9875,12 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9407
9875
|
const hasSpaceForLabel = arc.endAngle - arc.startAngle >= .25;
|
|
9408
9876
|
const handleMouseMove = (event) => {
|
|
9409
9877
|
if (!withTooltips) return;
|
|
9410
|
-
|
|
9878
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
9879
|
+
if (!bounds) return;
|
|
9411
9880
|
showTooltip({
|
|
9412
9881
|
tooltipData: arc.data,
|
|
9413
|
-
tooltipLeft: event.clientX -
|
|
9414
|
-
tooltipTop: event.clientY -
|
|
9882
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
9883
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9415
9884
|
});
|
|
9416
9885
|
};
|
|
9417
9886
|
const pathProps = {
|
|
@@ -9434,20 +9903,20 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9434
9903
|
const backgroundHeight = fontSize + 12;
|
|
9435
9904
|
return /* @__PURE__ */ jsxs("g", {
|
|
9436
9905
|
...groupProps,
|
|
9437
|
-
children: [/* @__PURE__ */ jsx("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ jsxs("g", { children: [
|
|
9906
|
+
children: [/* @__PURE__ */ jsx("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("rect", {
|
|
9907
|
+
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
9438
9908
|
x: centroidX - backgroundWidth / 2,
|
|
9439
9909
|
y: centroidY - backgroundHeight / 2,
|
|
9440
9910
|
width: backgroundWidth,
|
|
9441
9911
|
height: backgroundHeight,
|
|
9442
|
-
fill: providerTheme.labelBackgroundColor,
|
|
9443
9912
|
rx: 4,
|
|
9444
9913
|
ry: 4,
|
|
9445
9914
|
pointerEvents: "none"
|
|
9446
9915
|
}), /* @__PURE__ */ jsx("text", {
|
|
9916
|
+
className: pie_chart_module_default["pie-chart__label-text"],
|
|
9447
9917
|
x: centroidX,
|
|
9448
9918
|
y: centroidY,
|
|
9449
9919
|
dy: ".33em",
|
|
9450
|
-
fill: providerTheme.labelTextColor || "#333",
|
|
9451
9920
|
fontSize,
|
|
9452
9921
|
textAnchor: "middle",
|
|
9453
9922
|
pointerEvents: "none",
|
|
@@ -9458,7 +9927,15 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9458
9927
|
}
|
|
9459
9928
|
}), !allSegmentsHidden && svgChildren]
|
|
9460
9929
|
})]
|
|
9461
|
-
})
|
|
9930
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
9931
|
+
top: tooltipTop || 0,
|
|
9932
|
+
left: tooltipLeft || 0,
|
|
9933
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
9934
|
+
className: standaloneScopeClass,
|
|
9935
|
+
role: "tooltip",
|
|
9936
|
+
children: renderTooltip({ tooltipData })
|
|
9937
|
+
})
|
|
9938
|
+
})]
|
|
9462
9939
|
});
|
|
9463
9940
|
}
|
|
9464
9941
|
})
|
|
@@ -9485,6 +9962,7 @@ var pie_semi_circle_chart_module_default = {
|
|
|
9485
9962
|
"label": "a8ccharts-YtTOxW-label",
|
|
9486
9963
|
"note": "a8ccharts-YtTOxW-note",
|
|
9487
9964
|
"pie-semi-circle-chart": "a8ccharts-YtTOxW-pie-semi-circle-chart",
|
|
9965
|
+
"pie-semi-circle-chart__plot": "a8ccharts-YtTOxW-pie-semi-circle-chart__plot",
|
|
9488
9966
|
"pie-semi-circle-chart--responsive": "a8ccharts-YtTOxW-pie-semi-circle-chart--responsive"
|
|
9489
9967
|
};
|
|
9490
9968
|
//#endregion
|
|
@@ -9534,23 +10012,17 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9534
10012
|
const legendPosition = legend.position ?? "bottom";
|
|
9535
10013
|
const chartId = useChartId(providedChartId);
|
|
9536
10014
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = useTooltip();
|
|
9537
|
-
const
|
|
9538
|
-
|
|
9539
|
-
scroll: true,
|
|
9540
|
-
debounce: 0
|
|
9541
|
-
});
|
|
10015
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10016
|
+
const containerRef = useRef(null);
|
|
9542
10017
|
const handleMouseMove = useCallback((event, arc) => {
|
|
9543
|
-
|
|
10018
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
10019
|
+
if (!bounds) return;
|
|
9544
10020
|
showTooltip({
|
|
9545
10021
|
tooltipData: arc.data,
|
|
9546
|
-
tooltipLeft: event.clientX -
|
|
9547
|
-
tooltipTop: event.clientY -
|
|
10022
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
10023
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9548
10024
|
});
|
|
9549
10025
|
}, [
|
|
9550
|
-
containerBounds.width,
|
|
9551
|
-
containerBounds.height,
|
|
9552
|
-
containerBounds.left,
|
|
9553
|
-
containerBounds.top,
|
|
9554
10026
|
showTooltip,
|
|
9555
10027
|
tooltipOffsetX,
|
|
9556
10028
|
tooltipOffsetY
|
|
@@ -9599,7 +10071,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9599
10071
|
const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
|
|
9600
10072
|
const errorHeight = errorWidth / 2;
|
|
9601
10073
|
return /* @__PURE__ */ jsx("div", {
|
|
9602
|
-
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart"],
|
|
10074
|
+
className: clsx("pie-semi-circle-chart", pie_semi_circle_chart_module_default["pie-semi-circle-chart"], className),
|
|
9603
10075
|
children: /* @__PURE__ */ jsx("svg", {
|
|
9604
10076
|
width: errorWidth,
|
|
9605
10077
|
height: errorHeight,
|
|
@@ -9646,19 +10118,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9646
10118
|
width: propWidth || void 0,
|
|
9647
10119
|
height: propHeight || void 0
|
|
9648
10120
|
},
|
|
9649
|
-
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9650
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(TooltipInPortal, {
|
|
9651
|
-
top: tooltipTop || 0,
|
|
9652
|
-
left: tooltipLeft || 0,
|
|
9653
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
9654
|
-
className: "a8c-charts-scope",
|
|
9655
|
-
role: "tooltip",
|
|
9656
|
-
children: renderTooltip({ tooltipData })
|
|
9657
|
-
})
|
|
9658
|
-
}),
|
|
9659
|
-
htmlChildren,
|
|
9660
|
-
otherChildren
|
|
9661
|
-
] }),
|
|
10121
|
+
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [htmlChildren, otherChildren] }),
|
|
9662
10122
|
children: ({ contentWidth, contentHeight }) => {
|
|
9663
10123
|
const availableWidth = contentWidth > 0 ? contentWidth : effectiveWidth;
|
|
9664
10124
|
const availableHeight = contentHeight > 0 ? contentHeight : propHeight || effectiveWidth / 2;
|
|
@@ -9666,9 +10126,10 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9666
10126
|
const height = width / 2;
|
|
9667
10127
|
const radius = height;
|
|
9668
10128
|
const innerRadius = radius * (1 - thickness);
|
|
9669
|
-
return /* @__PURE__ */
|
|
10129
|
+
return /* @__PURE__ */ jsxs(Center, {
|
|
9670
10130
|
ref: containerRef,
|
|
9671
|
-
|
|
10131
|
+
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
|
|
10132
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
9672
10133
|
width,
|
|
9673
10134
|
height,
|
|
9674
10135
|
viewBox: `0 0 ${width} ${height}`,
|
|
@@ -9726,7 +10187,15 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9726
10187
|
!allSegmentsHidden && svgChildren
|
|
9727
10188
|
] })
|
|
9728
10189
|
})]
|
|
9729
|
-
})
|
|
10190
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
10191
|
+
top: tooltipTop || 0,
|
|
10192
|
+
left: tooltipLeft || 0,
|
|
10193
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
10194
|
+
className: standaloneScopeClass,
|
|
10195
|
+
role: "tooltip",
|
|
10196
|
+
children: renderTooltip({ tooltipData })
|
|
10197
|
+
})
|
|
10198
|
+
})]
|
|
9730
10199
|
});
|
|
9731
10200
|
}
|
|
9732
10201
|
})
|
|
@@ -9951,6 +10420,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
|
|
|
9951
10420
|
});
|
|
9952
10421
|
}
|
|
9953
10422
|
//#endregion
|
|
9954
|
-
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, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString,
|
|
10423
|
+
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, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
|
|
9955
10424
|
|
|
9956
10425
|
//# sourceMappingURL=index.js.map
|