@coinbase/cds-mobile-visualization 3.3.0 → 3.4.0-beta.10
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 +80 -0
- package/dts/chart/CartesianChart.d.ts +125 -0
- package/dts/chart/CartesianChart.d.ts.map +1 -0
- package/dts/chart/ChartContextBridge.d.ts +28 -0
- package/dts/chart/ChartContextBridge.d.ts.map +1 -0
- package/dts/chart/ChartProvider.d.ts +6 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -0
- package/dts/chart/Path.d.ts +91 -0
- package/dts/chart/Path.d.ts.map +1 -0
- package/dts/chart/PeriodSelector.d.ts +85 -0
- package/dts/chart/PeriodSelector.d.ts.map +1 -0
- package/dts/chart/area/Area.d.ts +77 -0
- package/dts/chart/area/Area.d.ts.map +1 -0
- package/dts/chart/area/AreaChart.d.ts +131 -0
- package/dts/chart/area/AreaChart.d.ts.map +1 -0
- package/dts/chart/area/DottedArea.d.ts +46 -0
- package/dts/chart/area/DottedArea.d.ts.map +1 -0
- package/dts/chart/area/GradientArea.d.ts +36 -0
- package/dts/chart/area/GradientArea.d.ts.map +1 -0
- package/dts/chart/area/SolidArea.d.ts +23 -0
- package/dts/chart/area/SolidArea.d.ts.map +1 -0
- package/dts/chart/area/index.d.ts +6 -0
- package/dts/chart/area/index.d.ts.map +1 -0
- package/dts/chart/axis/Axis.d.ts +194 -0
- package/dts/chart/axis/Axis.d.ts.map +1 -0
- package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
- package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
- package/dts/chart/axis/XAxis.d.ts +16 -0
- package/dts/chart/axis/XAxis.d.ts.map +1 -0
- package/dts/chart/axis/YAxis.d.ts +21 -0
- package/dts/chart/axis/YAxis.d.ts.map +1 -0
- package/dts/chart/axis/index.d.ts +5 -0
- package/dts/chart/axis/index.d.ts.map +1 -0
- package/dts/chart/bar/Bar.d.ts +92 -0
- package/dts/chart/bar/Bar.d.ts.map +1 -0
- package/dts/chart/bar/BarChart.d.ts +113 -0
- package/dts/chart/bar/BarChart.d.ts.map +1 -0
- package/dts/chart/bar/BarPlot.d.ts +30 -0
- package/dts/chart/bar/BarPlot.d.ts.map +1 -0
- package/dts/chart/bar/BarStack.d.ts +102 -0
- package/dts/chart/bar/BarStack.d.ts.map +1 -0
- package/dts/chart/bar/BarStackGroup.d.ts +36 -0
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
- package/dts/chart/bar/DefaultBar.d.ts +7 -0
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
- package/dts/chart/bar/DefaultBarStack.d.ts +7 -0
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
- package/dts/chart/bar/index.d.ts +8 -0
- package/dts/chart/bar/index.d.ts.map +1 -0
- package/dts/chart/gradient/Gradient.d.ts +25 -0
- package/dts/chart/gradient/Gradient.d.ts.map +1 -0
- package/dts/chart/gradient/index.d.ts +2 -0
- package/dts/chart/gradient/index.d.ts.map +1 -0
- package/dts/chart/index.d.ts +15 -0
- package/dts/chart/index.d.ts.map +1 -0
- package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
- package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts +20 -0
- package/dts/chart/line/DottedLine.d.ts.map +1 -0
- package/dts/chart/line/Line.d.ts +115 -0
- package/dts/chart/line/Line.d.ts.map +1 -0
- package/dts/chart/line/LineChart.d.ts +118 -0
- package/dts/chart/line/LineChart.d.ts.map +1 -0
- package/dts/chart/line/ReferenceLine.d.ts +139 -0
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
- package/dts/chart/line/SolidLine.d.ts +15 -0
- package/dts/chart/line/SolidLine.d.ts.map +1 -0
- package/dts/chart/line/index.d.ts +7 -0
- package/dts/chart/line/index.d.ts.map +1 -0
- package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
- package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
- package/dts/chart/point/Point.d.ts +120 -0
- package/dts/chart/point/Point.d.ts.map +1 -0
- package/dts/chart/point/index.d.ts +3 -0
- package/dts/chart/point/index.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +8 -0
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
- package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +11 -0
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
- package/dts/chart/scrubber/Scrubber.d.ts +233 -0
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +44 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +31 -0
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberProvider.d.ts +20 -0
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
- package/dts/chart/scrubber/index.d.ts +5 -0
- package/dts/chart/scrubber/index.d.ts.map +1 -0
- package/dts/chart/text/ChartText.d.ts +164 -0
- package/dts/chart/text/ChartText.d.ts.map +1 -0
- package/dts/chart/text/ChartTextGroup.d.ts +61 -0
- package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
- package/dts/chart/text/index.d.ts +3 -0
- package/dts/chart/text/index.d.ts.map +1 -0
- package/dts/chart/utils/axis.d.ts +342 -0
- package/dts/chart/utils/axis.d.ts.map +1 -0
- package/dts/chart/utils/bar.d.ts +20 -0
- package/dts/chart/utils/bar.d.ts.map +1 -0
- package/dts/chart/utils/chart.d.ts +124 -0
- package/dts/chart/utils/chart.d.ts.map +1 -0
- package/dts/chart/utils/context.d.ts +116 -0
- package/dts/chart/utils/context.d.ts.map +1 -0
- package/dts/chart/utils/gradient.d.ts +117 -0
- package/dts/chart/utils/gradient.d.ts.map +1 -0
- package/dts/chart/utils/index.d.ts +11 -0
- package/dts/chart/utils/index.d.ts.map +1 -0
- package/dts/chart/utils/path.d.ts +160 -0
- package/dts/chart/utils/path.d.ts.map +1 -0
- package/dts/chart/utils/point.d.ts +134 -0
- package/dts/chart/utils/point.d.ts.map +1 -0
- package/dts/chart/utils/scale.d.ts +134 -0
- package/dts/chart/utils/scale.d.ts.map +1 -0
- package/dts/chart/utils/scrubber.d.ts +39 -0
- package/dts/chart/utils/scrubber.d.ts.map +1 -0
- package/dts/chart/utils/transition.d.ts +140 -0
- package/dts/chart/utils/transition.d.ts.map +1 -0
- package/dts/index.d.ts +2 -1
- package/dts/index.d.ts.map +1 -1
- package/dts/sparkline/Counter.d.ts +7 -2
- package/dts/sparkline/Sparkline.d.ts +67 -16
- package/dts/sparkline/Sparkline.d.ts.map +1 -1
- package/dts/sparkline/SparklineArea.d.ts +10 -4
- package/dts/sparkline/SparklineArea.d.ts.map +1 -1
- package/dts/sparkline/SparklineAreaPattern.d.ts +12 -4
- package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -1
- package/dts/sparkline/SparklineGradient.d.ts +21 -10
- package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
- package/dts/sparkline/__figma__/Sparkline.figma.d.ts +1 -1
- package/dts/sparkline/generateSparklineWithId.d.ts +8 -2
- package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -1
- package/dts/sparkline/index.d.ts +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +8 -3
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +132 -110
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +22 -9
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +18 -7
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +9 -4
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +11 -6
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +7 -5
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +22 -10
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +21 -7
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +21 -16
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +29 -23
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +22 -14
- package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +1 -1
- package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +9 -5
- package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +11 -6
- package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +5 -2
- package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +17 -17
- package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +16 -13
- package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +106 -98
- package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +1 -1
- package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +22 -19
- package/esm/chart/CartesianChart.js +335 -0
- package/esm/chart/ChartContextBridge.js +148 -0
- package/esm/chart/ChartProvider.js +10 -0
- package/esm/chart/Path.js +218 -0
- package/esm/chart/PeriodSelector.js +136 -0
- package/esm/chart/__stories__/CartesianChart.stories.js +723 -0
- package/esm/chart/__stories__/Chart.stories.js +77 -0
- package/esm/chart/__stories__/PeriodSelector.stories.js +322 -0
- package/esm/chart/area/Area.js +75 -0
- package/esm/chart/area/AreaChart.js +151 -0
- package/esm/chart/area/DottedArea.js +80 -0
- package/esm/chart/area/GradientArea.js +54 -0
- package/esm/chart/area/SolidArea.js +38 -0
- package/esm/chart/area/__stories__/AreaChart.stories.js +100 -0
- package/esm/chart/area/index.js +7 -0
- package/esm/chart/axis/Axis.js +45 -0
- package/esm/chart/axis/DefaultAxisTickLabel.js +11 -0
- package/esm/chart/axis/XAxis.js +188 -0
- package/esm/chart/axis/YAxis.js +177 -0
- package/esm/chart/axis/__stories__/Axis.stories.js +276 -0
- package/esm/chart/axis/index.js +6 -0
- package/esm/chart/bar/Bar.js +69 -0
- package/esm/chart/bar/BarChart.js +125 -0
- package/esm/chart/bar/BarPlot.js +102 -0
- package/esm/chart/bar/BarStack.js +551 -0
- package/esm/chart/bar/BarStackGroup.js +79 -0
- package/esm/chart/bar/DefaultBar.js +56 -0
- package/esm/chart/bar/DefaultBarStack.js +47 -0
- package/esm/chart/bar/__stories__/BarChart.stories.js +668 -0
- package/esm/chart/bar/index.js +9 -0
- package/esm/chart/gradient/Gradient.js +53 -0
- package/esm/chart/gradient/index.js +1 -0
- package/esm/chart/index.js +16 -0
- package/esm/chart/line/DefaultReferenceLineLabel.js +66 -0
- package/esm/chart/line/DottedLine.js +50 -0
- package/esm/chart/line/Line.js +178 -0
- package/esm/chart/line/LineChart.js +121 -0
- package/esm/chart/line/ReferenceLine.js +132 -0
- package/esm/chart/line/SolidLine.js +46 -0
- package/esm/chart/line/__stories__/LineChart.stories.js +2372 -0
- package/esm/chart/line/__stories__/ReferenceLine.stories.js +132 -0
- package/esm/chart/line/index.js +8 -0
- package/esm/chart/point/DefaultPointLabel.js +39 -0
- package/esm/chart/point/Point.js +188 -0
- package/esm/chart/point/index.js +2 -0
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +179 -0
- package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +43 -0
- package/esm/chart/scrubber/DefaultScrubberLabel.js +28 -0
- package/esm/chart/scrubber/Scrubber.js +166 -0
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +161 -0
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +185 -0
- package/esm/chart/scrubber/ScrubberProvider.js +135 -0
- package/esm/chart/scrubber/index.js +4 -0
- package/esm/chart/text/ChartText.js +305 -0
- package/esm/chart/text/ChartTextGroup.js +211 -0
- package/esm/chart/text/index.js +4 -0
- package/esm/chart/utils/axis.js +592 -0
- package/esm/chart/utils/bar.js +24 -0
- package/esm/chart/utils/chart.js +270 -0
- package/esm/chart/utils/context.js +15 -0
- package/esm/chart/utils/gradient.js +305 -0
- package/esm/chart/utils/index.js +12 -0
- package/esm/chart/utils/path.js +274 -0
- package/esm/chart/utils/point.js +229 -0
- package/esm/chart/utils/scale.js +277 -0
- package/esm/chart/utils/scrubber.js +139 -0
- package/esm/chart/utils/transition.js +185 -0
- package/esm/index.js +4 -1
- package/esm/sparkline/Sparkline.js +129 -16
- package/esm/sparkline/SparklineArea.js +7 -2
- package/esm/sparkline/SparklineAreaPattern.js +4 -2
- package/esm/sparkline/SparklineGradient.js +4 -0
- package/esm/sparkline/__stories__/Sparkline.stories.js +11 -7
- package/esm/sparkline/__stories__/SparklineGradient.stories.js +7 -4
- package/esm/sparkline/generateSparklineWithId.js +3 -2
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +5 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +5 -2
- package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +4 -0
- package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +76 -24
- package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +17 -9
- package/package.json +17 -11
- package/dts/sparkline/__stories__/Sparkline.stories.d.ts +0 -3
- package/dts/sparkline/__stories__/Sparkline.stories.d.ts.map +0 -1
- package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts +0 -3
- package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +0 -3
- package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +0 -4
- package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts.map +0 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { memo, useMemo } from 'react';
|
|
2
|
+
import { runOnJS, useAnimatedReaction, useDerivedValue } from 'react-native-reanimated';
|
|
3
|
+
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
4
|
+
import { FontSlant, FontWeight, Group, Paint, Paragraph, RoundedRect, Shadow, Skia, TextAlign } from '@shopify/react-native-skia';
|
|
5
|
+
import { useCartesianChartContext } from '../ChartProvider';
|
|
6
|
+
import { getChartInset, getColorWithOpacity, unwrapAnimatedValue } from '../utils';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Converts a fontWeight from Theme to a Skia FontWeight
|
|
10
|
+
* @note this only works when the fontWeight is a valid number (ie not 'bold')
|
|
11
|
+
* @param theme - The theme to use
|
|
12
|
+
* @param font - The font to use
|
|
13
|
+
* @returns The FontWeight or undefined if the fontWeight is not a valid number
|
|
14
|
+
*/
|
|
15
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
16
|
+
const getFontWeight = (theme, font) => {
|
|
17
|
+
const themeFontWeight = theme.fontWeight[font];
|
|
18
|
+
const numericWeight = typeof themeFontWeight === 'string' ? Number(themeFontWeight) : themeFontWeight;
|
|
19
|
+
const validFontWeights = Object.values(FontWeight).filter(value => typeof value === 'number');
|
|
20
|
+
return numericWeight !== undefined && validFontWeights.includes(numericWeight) ? numericWeight : undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The supported content types for ChartText.
|
|
25
|
+
* Pass a string for simple text, or a SkParagraph for advanced rich text formatting.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Horizontal alignment options for chart text.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Vertical alignment options for chart text.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export const ChartText = /*#__PURE__*/memo(_ref => {
|
|
37
|
+
var _elevationShadow$shad, _elevationShadow$shad2, _elevationShadow$shad3, _elevationShadow$shad4, _elevationShadow$shad5, _elevationShadow$shad6, _elevationShadow$shad7;
|
|
38
|
+
let {
|
|
39
|
+
children,
|
|
40
|
+
x,
|
|
41
|
+
y,
|
|
42
|
+
dx = 0,
|
|
43
|
+
dy = 0,
|
|
44
|
+
horizontalAlignment = 'center',
|
|
45
|
+
verticalAlignment = 'middle',
|
|
46
|
+
paragraphAlignment = TextAlign.Left,
|
|
47
|
+
disableRepositioning = false,
|
|
48
|
+
bounds,
|
|
49
|
+
color,
|
|
50
|
+
background: backgroundProp,
|
|
51
|
+
borderRadius = 4,
|
|
52
|
+
inset: insetInput,
|
|
53
|
+
onDimensionsChange,
|
|
54
|
+
opacity = 1,
|
|
55
|
+
fontFamilies,
|
|
56
|
+
font = 'label2',
|
|
57
|
+
fontSize,
|
|
58
|
+
fontWeight,
|
|
59
|
+
fontStyle: fontStyleProp = FontSlant.Upright,
|
|
60
|
+
elevated
|
|
61
|
+
} = _ref;
|
|
62
|
+
const theme = useTheme();
|
|
63
|
+
const {
|
|
64
|
+
width: chartWidth,
|
|
65
|
+
height: chartHeight,
|
|
66
|
+
fontFamilies: contextFontFamilies,
|
|
67
|
+
fontProvider
|
|
68
|
+
} = useCartesianChartContext();
|
|
69
|
+
const inset = useMemo(() => getChartInset(insetInput), [insetInput]);
|
|
70
|
+
const background = backgroundProp != null ? backgroundProp : elevated ? theme.color.bgElevation1 : 'transparent';
|
|
71
|
+
const defaultParagraphStyle = useMemo(() => {
|
|
72
|
+
var _ref2;
|
|
73
|
+
return {
|
|
74
|
+
fontFamilies: (_ref2 = fontFamilies != null ? fontFamilies : contextFontFamilies) != null ? _ref2 : [],
|
|
75
|
+
fontSize: fontSize != null ? fontSize : theme.fontSize[font],
|
|
76
|
+
fontStyle: {
|
|
77
|
+
weight: fontWeight != null ? fontWeight : getFontWeight(theme, font),
|
|
78
|
+
slant: fontStyleProp
|
|
79
|
+
},
|
|
80
|
+
color: Skia.Color(color != null ? color : theme.color.fgMuted)
|
|
81
|
+
};
|
|
82
|
+
}, [fontFamilies, contextFontFamilies, fontSize, theme, font, fontWeight, fontStyleProp, color]);
|
|
83
|
+
const paragraph = useDerivedValue(() => {
|
|
84
|
+
const childrenValue = unwrapAnimatedValue(children);
|
|
85
|
+
if (typeof childrenValue !== 'string') {
|
|
86
|
+
return childrenValue;
|
|
87
|
+
}
|
|
88
|
+
const builder = Skia.ParagraphBuilder.Make({
|
|
89
|
+
textAlign: TextAlign.Left
|
|
90
|
+
}, fontProvider);
|
|
91
|
+
builder.pushStyle(defaultParagraphStyle);
|
|
92
|
+
builder.addText(childrenValue);
|
|
93
|
+
builder.pop();
|
|
94
|
+
const para = builder.build();
|
|
95
|
+
para.layout(chartWidth);
|
|
96
|
+
return para;
|
|
97
|
+
}, [children, fontProvider, defaultParagraphStyle, chartWidth]);
|
|
98
|
+
const textDimensions = useDerivedValue(() => {
|
|
99
|
+
const unwrappedParagraph = paragraph.value;
|
|
100
|
+
if (!unwrappedParagraph) return {
|
|
101
|
+
width: 0,
|
|
102
|
+
height: 0
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
width: unwrappedParagraph.getLongestLine(),
|
|
106
|
+
height: unwrappedParagraph.getHeight()
|
|
107
|
+
};
|
|
108
|
+
}, [paragraph]);
|
|
109
|
+
const backgroundRectSize = useDerivedValue(() => ({
|
|
110
|
+
width: textDimensions.value.width + inset.left + inset.right,
|
|
111
|
+
height: textDimensions.value.height + inset.top + inset.bottom
|
|
112
|
+
}), [textDimensions, inset]);
|
|
113
|
+
|
|
114
|
+
// Calculate background rect position based on alignment
|
|
115
|
+
const backgroundRect = useDerivedValue(() => {
|
|
116
|
+
const horAlignment = unwrapAnimatedValue(horizontalAlignment);
|
|
117
|
+
const verAlignment = unwrapAnimatedValue(verticalAlignment);
|
|
118
|
+
// By default the value is top left
|
|
119
|
+
let rectX = unwrapAnimatedValue(x);
|
|
120
|
+
let rectY = unwrapAnimatedValue(y);
|
|
121
|
+
const rectSize = backgroundRectSize.value;
|
|
122
|
+
|
|
123
|
+
// Adjust for horizontal alignment
|
|
124
|
+
switch (horAlignment) {
|
|
125
|
+
case 'center':
|
|
126
|
+
rectX = rectX - rectSize.width / 2;
|
|
127
|
+
break;
|
|
128
|
+
case 'right':
|
|
129
|
+
rectX = rectX - rectSize.width;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Adjust for vertical alignment
|
|
134
|
+
switch (verAlignment) {
|
|
135
|
+
case 'middle':
|
|
136
|
+
rectY = rectY - rectSize.height / 2;
|
|
137
|
+
break;
|
|
138
|
+
case 'bottom':
|
|
139
|
+
rectY = rectY - rectSize.height;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
x: rectX,
|
|
144
|
+
y: rectY,
|
|
145
|
+
width: rectSize.width,
|
|
146
|
+
height: rectSize.height
|
|
147
|
+
};
|
|
148
|
+
}, [x, y, backgroundRectSize, horizontalAlignment, verticalAlignment]);
|
|
149
|
+
|
|
150
|
+
// Paragraph uses top-left positioning
|
|
151
|
+
const textPosition = useDerivedValue(() => {
|
|
152
|
+
const textDims = textDimensions.value;
|
|
153
|
+
|
|
154
|
+
// Calculate horizontal offset based on paragraph alignment
|
|
155
|
+
let horizontalOffset = 0;
|
|
156
|
+
switch (paragraphAlignment) {
|
|
157
|
+
case TextAlign.Center:
|
|
158
|
+
horizontalOffset = -textDims.width / 2;
|
|
159
|
+
break;
|
|
160
|
+
case TextAlign.Right:
|
|
161
|
+
case TextAlign.End:
|
|
162
|
+
horizontalOffset = -textDims.width;
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
// Left-aligned text needs no offset
|
|
166
|
+
horizontalOffset = 0;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
x: backgroundRect.value.x + inset.left + horizontalOffset,
|
|
171
|
+
y: backgroundRect.value.y + inset.top,
|
|
172
|
+
width: textDims.width,
|
|
173
|
+
height: textDims.height
|
|
174
|
+
};
|
|
175
|
+
}, [backgroundRect, textDimensions, inset, paragraphAlignment]);
|
|
176
|
+
|
|
177
|
+
// Calculate overflow and repositioning
|
|
178
|
+
const fullChartBounds = useMemo(() => ({
|
|
179
|
+
x: 0,
|
|
180
|
+
y: 0,
|
|
181
|
+
width: chartWidth,
|
|
182
|
+
height: chartHeight
|
|
183
|
+
}), [chartWidth, chartHeight]);
|
|
184
|
+
const overflowAmount = useDerivedValue(() => {
|
|
185
|
+
if (disableRepositioning) {
|
|
186
|
+
return {
|
|
187
|
+
x: 0,
|
|
188
|
+
y: 0
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const parentBounds = bounds != null ? bounds : fullChartBounds;
|
|
192
|
+
if (!parentBounds || parentBounds.width <= 0 || parentBounds.height <= 0) {
|
|
193
|
+
return {
|
|
194
|
+
x: 0,
|
|
195
|
+
y: 0
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
let offsetX = 0;
|
|
199
|
+
let offsetY = 0;
|
|
200
|
+
|
|
201
|
+
// X-axis overflow
|
|
202
|
+
if (backgroundRect.value.x < parentBounds.x) {
|
|
203
|
+
offsetX = parentBounds.x - backgroundRect.value.x;
|
|
204
|
+
} else if (backgroundRect.value.x + backgroundRect.value.width > parentBounds.x + parentBounds.width) {
|
|
205
|
+
offsetX = parentBounds.x + parentBounds.width - (backgroundRect.value.x + backgroundRect.value.width);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Y-axis overflow
|
|
209
|
+
if (backgroundRect.value.y < parentBounds.y) {
|
|
210
|
+
offsetY = parentBounds.y - backgroundRect.value.y;
|
|
211
|
+
} else if (backgroundRect.value.y + backgroundRect.value.height > parentBounds.y + parentBounds.height) {
|
|
212
|
+
offsetY = parentBounds.y + parentBounds.height - (backgroundRect.value.y + backgroundRect.value.height);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
x: offsetX,
|
|
216
|
+
y: offsetY
|
|
217
|
+
};
|
|
218
|
+
}, [backgroundRect, fullChartBounds, bounds, disableRepositioning]);
|
|
219
|
+
|
|
220
|
+
// Final adjusted positions
|
|
221
|
+
const backgroundRectWithOffset = useDerivedValue(() => {
|
|
222
|
+
const offsetX = unwrapAnimatedValue(dx);
|
|
223
|
+
const offsetY = unwrapAnimatedValue(dy);
|
|
224
|
+
return {
|
|
225
|
+
x: backgroundRect.value.x + overflowAmount.value.x + offsetX,
|
|
226
|
+
y: backgroundRect.value.y + overflowAmount.value.y + offsetY,
|
|
227
|
+
width: backgroundRect.value.width,
|
|
228
|
+
height: backgroundRect.value.height
|
|
229
|
+
};
|
|
230
|
+
}, [backgroundRect, overflowAmount, dx, dy]);
|
|
231
|
+
const textWithOffsetX = useDerivedValue(() => textPosition.value.x + overflowAmount.value.x + unwrapAnimatedValue(dx), [textPosition, overflowAmount, dx]);
|
|
232
|
+
const textWithOffsetY = useDerivedValue(() => textPosition.value.y + overflowAmount.value.y + unwrapAnimatedValue(dy), [textPosition, overflowAmount, dy]);
|
|
233
|
+
useAnimatedReaction(() => backgroundRectWithOffset.value, (rect, previous) => {
|
|
234
|
+
if (onDimensionsChange && rect !== previous) {
|
|
235
|
+
runOnJS(onDimensionsChange)(rect);
|
|
236
|
+
}
|
|
237
|
+
}, [onDimensionsChange]);
|
|
238
|
+
|
|
239
|
+
// Show group if we are ready
|
|
240
|
+
const groupOpacity = useDerivedValue(() => {
|
|
241
|
+
const textSize = textDimensions.value;
|
|
242
|
+
const hasValidContent = paragraph.value && textSize.width > 0 && textSize.height > 0;
|
|
243
|
+
return hasValidContent ? unwrapAnimatedValue(opacity) : 0;
|
|
244
|
+
}, [paragraph, textDimensions, opacity]);
|
|
245
|
+
const backgroundRectHeight = useDerivedValue(() => backgroundRectWithOffset.value.height, [backgroundRectWithOffset]);
|
|
246
|
+
const backgroundRectWidth = useDerivedValue(() => backgroundRectWithOffset.value.width, [backgroundRectWithOffset]);
|
|
247
|
+
const backgroundRectX = useDerivedValue(() => backgroundRectWithOffset.value.x, [backgroundRectWithOffset]);
|
|
248
|
+
const backgroundRectY = useDerivedValue(() => backgroundRectWithOffset.value.y, [backgroundRectWithOffset]);
|
|
249
|
+
const elevationShadow = elevated ? theme.shadow.elevation1 : undefined;
|
|
250
|
+
|
|
251
|
+
// Calculate the paragraph's internal x offset from line metrics based on text alignment
|
|
252
|
+
const paragraphTransform = useDerivedValue(() => {
|
|
253
|
+
if (!paragraph.value || !paragraphAlignment) return [];
|
|
254
|
+
const rects = paragraph.value.getLineMetrics();
|
|
255
|
+
if (rects.length === 0) return [];
|
|
256
|
+
let minOffset;
|
|
257
|
+
switch (paragraphAlignment) {
|
|
258
|
+
case TextAlign.Center:
|
|
259
|
+
// For center-aligned text, account for half the width
|
|
260
|
+
minOffset = Math.min(...rects.map(rect => rect.x - rect.width / 2));
|
|
261
|
+
break;
|
|
262
|
+
case TextAlign.Right:
|
|
263
|
+
case TextAlign.End:
|
|
264
|
+
// For right-aligned text, account for the full width
|
|
265
|
+
minOffset = Math.min(...rects.map(rect => rect.x - rect.width));
|
|
266
|
+
break;
|
|
267
|
+
default:
|
|
268
|
+
// For left-aligned text, use the x position directly
|
|
269
|
+
minOffset = Math.min(...rects.map(rect => rect.x));
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
return [{
|
|
273
|
+
translateX: -minOffset
|
|
274
|
+
}];
|
|
275
|
+
}, [paragraph, paragraphAlignment]);
|
|
276
|
+
|
|
277
|
+
// Opacity on a group doesn't impact the paragraph so we need to apply it to Group
|
|
278
|
+
return /*#__PURE__*/_jsxs(Group, {
|
|
279
|
+
layer: /*#__PURE__*/_jsx(Paint, {
|
|
280
|
+
opacity: groupOpacity
|
|
281
|
+
}),
|
|
282
|
+
children: [background !== 'transparent' && /*#__PURE__*/_jsx(RoundedRect, {
|
|
283
|
+
color: background,
|
|
284
|
+
height: backgroundRectHeight,
|
|
285
|
+
r: borderRadius,
|
|
286
|
+
width: backgroundRectWidth,
|
|
287
|
+
x: backgroundRectX,
|
|
288
|
+
y: backgroundRectY,
|
|
289
|
+
children: elevationShadow && /*#__PURE__*/_jsx(Shadow, {
|
|
290
|
+
blur: Number((_elevationShadow$shad = elevationShadow.shadowRadius) != null ? _elevationShadow$shad : 0),
|
|
291
|
+
color: getColorWithOpacity(String((_elevationShadow$shad2 = elevationShadow.shadowColor) != null ? _elevationShadow$shad2 : '#000000'), Number((_elevationShadow$shad3 = elevationShadow.shadowOpacity) != null ? _elevationShadow$shad3 : 1)),
|
|
292
|
+
dx: Number((_elevationShadow$shad4 = (_elevationShadow$shad5 = elevationShadow.shadowOffset) == null ? void 0 : _elevationShadow$shad5.width) != null ? _elevationShadow$shad4 : 0),
|
|
293
|
+
dy: Number((_elevationShadow$shad6 = (_elevationShadow$shad7 = elevationShadow.shadowOffset) == null ? void 0 : _elevationShadow$shad7.height) != null ? _elevationShadow$shad6 : 0)
|
|
294
|
+
})
|
|
295
|
+
}), /*#__PURE__*/_jsx(Group, {
|
|
296
|
+
transform: paragraphTransform,
|
|
297
|
+
children: /*#__PURE__*/_jsx(Paragraph, {
|
|
298
|
+
paragraph: paragraph,
|
|
299
|
+
width: chartWidth,
|
|
300
|
+
x: textWithOffsetX,
|
|
301
|
+
y: textWithOffsetY
|
|
302
|
+
})
|
|
303
|
+
})]
|
|
304
|
+
});
|
|
305
|
+
});
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const _excluded = ["onDimensionsChange"];
|
|
2
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
3
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
4
|
+
import { memo, useEffect, useMemo, useState } from 'react';
|
|
5
|
+
import { Group } from '@shopify/react-native-skia';
|
|
6
|
+
import { ChartText } from './ChartText';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for a single text label in the display list
|
|
10
|
+
*/
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
/**
|
|
13
|
+
* Overlap check that enforces a minimum pixel gap between two rectangles.
|
|
14
|
+
* We inflate each rect by gap/2 on all sides so two neighbors must be at
|
|
15
|
+
* least `gap` pixels apart to be considered non-overlapping.
|
|
16
|
+
*/
|
|
17
|
+
function doRectsOverlapWithGap(a, b, gap) {
|
|
18
|
+
const g = gap / 2;
|
|
19
|
+
const overlapX = a.x - g < b.x + b.width + g && a.x + a.width + g > b.x - g;
|
|
20
|
+
const overlapY = a.y - g < b.y + b.height + g && a.y + a.height + g > b.y - g;
|
|
21
|
+
return overlapX && overlapY;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Suppress state churn due to sub-pixel jitter in measurements
|
|
25
|
+
const EPSILON_PX = 0.5;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A smart text display component that prevents label overlap through collision detection.
|
|
29
|
+
*
|
|
30
|
+
* This component renders a list of ChartText components and automatically hides overlapping elements
|
|
31
|
+
* to ensure readability.
|
|
32
|
+
*
|
|
33
|
+
* The component focuses solely on overlap prevention logic for better separation of concerns.
|
|
34
|
+
*/
|
|
35
|
+
export const ChartTextGroup = /*#__PURE__*/memo(_ref => {
|
|
36
|
+
let {
|
|
37
|
+
labels,
|
|
38
|
+
minGap = 8,
|
|
39
|
+
prioritizeEndLabels = true,
|
|
40
|
+
chartTextProps,
|
|
41
|
+
LabelComponent = ChartText
|
|
42
|
+
} = _ref;
|
|
43
|
+
const [boundingBoxes, setBoundingBoxes] = useState(new Map());
|
|
44
|
+
const _ref2 = chartTextProps != null ? chartTextProps : {},
|
|
45
|
+
{
|
|
46
|
+
onDimensionsChange: propsOnDimensionsChange
|
|
47
|
+
} = _ref2,
|
|
48
|
+
restChartTextProps = _objectWithoutPropertiesLoose(_ref2, _excluded);
|
|
49
|
+
|
|
50
|
+
// Generate a unique key to reference each label with.
|
|
51
|
+
const labelsWithKeys = useMemo(() => {
|
|
52
|
+
return labels.map((labelData, index) => _extends({}, labelData, {
|
|
53
|
+
key: labelData.label + "-" + index
|
|
54
|
+
}));
|
|
55
|
+
}, [labels]);
|
|
56
|
+
|
|
57
|
+
// Cleans up `boundingBoxes` state so that it only includes entries for the current set of labels
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const allLabelsKeys = new Set(labelsWithKeys.map(l => l.key));
|
|
60
|
+
setBoundingBoxes(prev => {
|
|
61
|
+
let changed = false;
|
|
62
|
+
const next = new Map();
|
|
63
|
+
for (const [k, v] of prev) {
|
|
64
|
+
if (allLabelsKeys.has(k)) next.set(k, v);else changed = true;
|
|
65
|
+
}
|
|
66
|
+
return changed ? next : prev;
|
|
67
|
+
});
|
|
68
|
+
}, [labelsWithKeys]);
|
|
69
|
+
|
|
70
|
+
// Build stable per-label measurement callbacks that recreate when labels change
|
|
71
|
+
const onDimensionsChangeByKey = useMemo(() => {
|
|
72
|
+
const map = new Map();
|
|
73
|
+
for (const labelData of labelsWithKeys) {
|
|
74
|
+
const {
|
|
75
|
+
key,
|
|
76
|
+
chartTextProps: labelChartTextProps
|
|
77
|
+
} = labelData;
|
|
78
|
+
map.set(key, bounds => {
|
|
79
|
+
labelChartTextProps == null || labelChartTextProps.onDimensionsChange == null || labelChartTextProps.onDimensionsChange(bounds);
|
|
80
|
+
propsOnDimensionsChange == null || propsOnDimensionsChange(bounds);
|
|
81
|
+
// Ignore zero-sized bounds and no-op updates (epsilon compare)
|
|
82
|
+
if (bounds.width === 0 || bounds.height === 0) return;
|
|
83
|
+
setBoundingBoxes(prev => {
|
|
84
|
+
const prevRect = prev.get(key);
|
|
85
|
+
const nearlyEqual = (a, b) => Math.abs(a - b) <= EPSILON_PX;
|
|
86
|
+
const isSame = prevRect !== undefined && nearlyEqual(prevRect.x, bounds.x) && nearlyEqual(prevRect.y, bounds.y) && nearlyEqual(prevRect.width, bounds.width) && nearlyEqual(prevRect.height, bounds.height);
|
|
87
|
+
if (isSame) return prev;
|
|
88
|
+
const newMap = new Map(prev);
|
|
89
|
+
newMap.set(key, bounds);
|
|
90
|
+
return newMap;
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return map;
|
|
95
|
+
}, [labelsWithKeys, propsOnDimensionsChange]);
|
|
96
|
+
|
|
97
|
+
// Determine readiness: all current labels have measured bounding boxes
|
|
98
|
+
const isReady = useMemo(() => labelsWithKeys.every(l => boundingBoxes.has(l.key)), [labelsWithKeys, boundingBoxes]);
|
|
99
|
+
|
|
100
|
+
// Compute visible keys using stride attempts then greedy fallback
|
|
101
|
+
const visibleKeySet = useMemo(() => {
|
|
102
|
+
// Build ordered set of labels with rects for collision detection algorithm
|
|
103
|
+
const orderedWithRects = labelsWithKeys.map((l, idx) => _extends({}, l, {
|
|
104
|
+
rect: boundingBoxes.get(l.key)
|
|
105
|
+
})).filter(x => x.rect !== undefined);
|
|
106
|
+
|
|
107
|
+
// 1) Sort by horizontal position so neighbor checks are O(1)
|
|
108
|
+
// For ties, sort bottom-to-top (higher y first) to get stable ordering
|
|
109
|
+
orderedWithRects.sort((a, b) => a.x === b.x ? b.y - a.y : a.x - b.x);
|
|
110
|
+
|
|
111
|
+
// 2) Defer selection until all labels have measured to avoid flicker and early hiding
|
|
112
|
+
if (!isReady) return null;
|
|
113
|
+
const n = orderedWithRects.length;
|
|
114
|
+
// 3) Trivial cases
|
|
115
|
+
if (n === 0) return new Set();
|
|
116
|
+
if (n === 1) return new Set([orderedWithRects[0].key]);
|
|
117
|
+
|
|
118
|
+
// 4) Two-label rule: if overlapping, prefer the first label (original order)
|
|
119
|
+
if (n === 2) {
|
|
120
|
+
const a = orderedWithRects[0];
|
|
121
|
+
const b = orderedWithRects[1];
|
|
122
|
+
const overlap = doRectsOverlapWithGap(a.rect, b.rect, minGap);
|
|
123
|
+
if (overlap) {
|
|
124
|
+
var _labelsWithKeys$;
|
|
125
|
+
const firstOriginal = (_labelsWithKeys$ = labelsWithKeys[0]) == null ? void 0 : _labelsWithKeys$.key;
|
|
126
|
+
return new Set([firstOriginal != null ? firstOriginal : a.key]);
|
|
127
|
+
}
|
|
128
|
+
return new Set([a.key, b.key]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 5) Utility: check only adjacent neighbors in x-order for overlap with gap
|
|
132
|
+
const hasNeighborOverlap = keysOrdered => {
|
|
133
|
+
for (let i = 0; i < keysOrdered.length - 1; i++) {
|
|
134
|
+
const ra = boundingBoxes.get(keysOrdered[i]);
|
|
135
|
+
const rb = boundingBoxes.get(keysOrdered[i + 1]);
|
|
136
|
+
if (doRectsOverlapWithGap(ra, rb, minGap)) return true;
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// 6) Fast path: if every label fits, show them all without reduction
|
|
142
|
+
const allKeys = orderedWithRects.map(l => l.key);
|
|
143
|
+
if (!hasNeighborOverlap(allKeys)) {
|
|
144
|
+
return new Set(allKeys);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 7) Try stride patterns: every 2nd, every 3rd, ... while ensuring ends when prioritized
|
|
148
|
+
const tryStride = stride => {
|
|
149
|
+
const selected = [];
|
|
150
|
+
for (let i = 0; i < n; i += stride) selected.push(orderedWithRects[i].key);
|
|
151
|
+
if (prioritizeEndLabels) {
|
|
152
|
+
const firstKey = orderedWithRects[0].key;
|
|
153
|
+
const lastKey = orderedWithRects[n - 1].key;
|
|
154
|
+
if (selected[0] !== firstKey) selected.unshift(firstKey);
|
|
155
|
+
if (selected[selected.length - 1] !== lastKey) selected.push(lastKey);
|
|
156
|
+
}
|
|
157
|
+
// Deduplicate while preserving order
|
|
158
|
+
const unique = Array.from(new Set(selected));
|
|
159
|
+
return hasNeighborOverlap(unique) ? new Set() : new Set(unique);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// 8) Increase stride until something fits or we exhaust options
|
|
163
|
+
for (let stride = 2; stride <= n; stride++) {
|
|
164
|
+
const attempt = tryStride(stride);
|
|
165
|
+
if (attempt.size > 0) return attempt;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 9) Greedy fallback: walk left-to-right and keep a label only if it
|
|
169
|
+
// does not overlap the previously accepted label. Optionally ensure last.
|
|
170
|
+
const greedy = [];
|
|
171
|
+
const firstKey = orderedWithRects[0].key;
|
|
172
|
+
const lastKey = orderedWithRects[n - 1].key;
|
|
173
|
+
greedy.push(firstKey);
|
|
174
|
+
for (let i = 1; i < n - 1; i++) {
|
|
175
|
+
const k = orderedWithRects[i].key;
|
|
176
|
+
const prevKey = greedy[greedy.length - 1];
|
|
177
|
+
const ra = boundingBoxes.get(prevKey);
|
|
178
|
+
const rb = boundingBoxes.get(k);
|
|
179
|
+
if (!doRectsOverlapWithGap(ra, rb, minGap)) {
|
|
180
|
+
greedy.push(k);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Ensure last key when prioritized
|
|
184
|
+
if (prioritizeEndLabels) {
|
|
185
|
+
const lastIncluded = greedy[greedy.length - 1];
|
|
186
|
+
const ra = boundingBoxes.get(lastIncluded);
|
|
187
|
+
const rb = boundingBoxes.get(lastKey);
|
|
188
|
+
if (doRectsOverlapWithGap(ra, rb, minGap)) {
|
|
189
|
+
// Replace the last conflicting with the lastKey
|
|
190
|
+
greedy[greedy.length - 1] = lastKey;
|
|
191
|
+
} else if (lastIncluded !== lastKey) {
|
|
192
|
+
greedy.push(lastKey);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return new Set(greedy);
|
|
196
|
+
}, [isReady, boundingBoxes, minGap, prioritizeEndLabels, labelsWithKeys]);
|
|
197
|
+
return /*#__PURE__*/_jsx(Group, {
|
|
198
|
+
children: labelsWithKeys.map(labelData => {
|
|
199
|
+
const hasMeasurement = boundingBoxes.has(labelData.key);
|
|
200
|
+
const isVisible = hasMeasurement && isReady && (visibleKeySet == null ? void 0 : visibleKeySet.has(labelData.key));
|
|
201
|
+
return /*#__PURE__*/_jsx(LabelComponent, _extends({
|
|
202
|
+
opacity: isVisible ? 1 : 0,
|
|
203
|
+
x: labelData.x,
|
|
204
|
+
y: labelData.y
|
|
205
|
+
}, restChartTextProps, labelData.chartTextProps, {
|
|
206
|
+
onDimensionsChange: onDimensionsChangeByKey.get(labelData.key),
|
|
207
|
+
children: labelData.label
|
|
208
|
+
}), labelData.key);
|
|
209
|
+
})
|
|
210
|
+
});
|
|
211
|
+
});
|