@coinbase/cds-mobile-visualization 3.4.0-beta.23 → 3.4.0-beta.25

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dts/chart/CartesianChart.d.ts +19 -0
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/Path.d.ts +2 -1
  5. package/dts/chart/Path.d.ts.map +1 -1
  6. package/dts/chart/bar/Bar.d.ts +18 -54
  7. package/dts/chart/bar/Bar.d.ts.map +1 -1
  8. package/dts/chart/bar/BarChart.d.ts +2 -2
  9. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  10. package/dts/chart/bar/BarStack.d.ts +4 -4
  11. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  12. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  13. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  14. package/dts/chart/line/LineChart.d.ts +17 -3
  15. package/dts/chart/line/LineChart.d.ts.map +1 -1
  16. package/dts/chart/point/Point.d.ts +2 -1
  17. package/dts/chart/point/Point.d.ts.map +1 -1
  18. package/dts/chart/scrubber/Scrubber.d.ts +4 -2
  19. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  20. package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts +12 -0
  21. package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts.map +1 -0
  22. package/dts/chart/utils/bar.d.ts +155 -0
  23. package/dts/chart/utils/bar.d.ts.map +1 -1
  24. package/dts/chart/utils/chart.d.ts +2 -1
  25. package/dts/chart/utils/chart.d.ts.map +1 -1
  26. package/dts/chart/utils/path.d.ts.map +1 -1
  27. package/dts/sparkline/Sparkline.d.ts +2 -1
  28. package/dts/sparkline/Sparkline.d.ts.map +1 -1
  29. package/dts/sparkline/SparklineArea.d.ts +2 -1
  30. package/dts/sparkline/SparklineArea.d.ts.map +1 -1
  31. package/dts/sparkline/SparklineGradient.d.ts +2 -1
  32. package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
  33. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +2 -1
  34. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
  35. package/esm/chart/CartesianChart.js +39 -14
  36. package/esm/chart/__stories__/CartesianChart.stories.js +10 -0
  37. package/esm/chart/__stories__/ChartAccessibility.stories.js +721 -0
  38. package/esm/chart/area/__stories__/AreaChart.stories.js +17 -3
  39. package/esm/chart/axis/__stories__/Axis.stories.js +65 -48
  40. package/esm/chart/bar/Bar.js +8 -14
  41. package/esm/chart/bar/BarChart.js +7 -7
  42. package/esm/chart/bar/BarPlot.js +37 -46
  43. package/esm/chart/bar/BarStack.js +71 -604
  44. package/esm/chart/bar/DefaultBar.js +11 -18
  45. package/esm/chart/bar/DefaultBarStack.js +12 -21
  46. package/esm/chart/bar/__stories__/BarChart.stories.js +110 -6
  47. package/esm/chart/line/LineChart.js +22 -1
  48. package/esm/chart/line/__stories__/LineChart.stories.js +84 -46
  49. package/esm/chart/scrubber/ScrubberAccessibilityView.js +177 -0
  50. package/esm/chart/scrubber/__stories__/Scrubber.stories.js +57 -5
  51. package/esm/chart/utils/bar.js +775 -0
  52. package/esm/chart/utils/chart.js +2 -1
  53. package/esm/chart/utils/path.js +5 -12
  54. package/esm/sparkline/Sparkline.js +2 -1
  55. package/esm/sparkline/SparklineArea.js +2 -1
  56. package/esm/sparkline/SparklineGradient.js +2 -1
  57. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +2 -1
  58. package/package.json +5 -5
@@ -1,17 +1,22 @@
1
+ import { useCallback } from 'react';
1
2
  import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
2
3
  import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
3
4
  import { DottedLine } from '../../line';
4
5
  import { Scrubber } from '../../scrubber/Scrubber';
5
6
  import { AreaChart } from '..';
6
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ const basicData = [24, 13, 98, 39, 48, 38, 43];
7
9
  const BasicExample = () => {
10
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + basicData[index], []);
8
11
  return /*#__PURE__*/_jsx(AreaChart, {
9
12
  enableScrubbing: true,
10
13
  showYAxis: true,
14
+ accessibilityLabel: "Area chart with " + basicData.length + " data points. Swipe to navigate.",
15
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
11
16
  height: 400,
12
17
  series: [{
13
18
  id: 'pageViews',
14
- data: [24, 13, 98, 39, 48, 38, 43]
19
+ data: basicData
15
20
  }],
16
21
  yAxis: {
17
22
  showGrid: true,
@@ -22,21 +27,26 @@ const BasicExample = () => {
22
27
  children: /*#__PURE__*/_jsx(Scrubber, {})
23
28
  });
24
29
  };
30
+ const currentRewardsData = [100, 150, 200, 280, 380, 500, 650, 820, 1020, 1250, 1510, 1800, 2120, 2470, 2850, 3260, 3700, 4170];
31
+ const potentialRewardsData = [150, 220, 300, 400, 520, 660, 820, 1000, 1200, 1420, 1660, 1920, 2200, 2500, 2820, 3160, 3520, 3900];
25
32
  const StackedExample = () => {
26
33
  const theme = useTheme();
34
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": current " + currentRewardsData[index] + ", potential " + potentialRewardsData[index], []);
27
35
  return /*#__PURE__*/_jsx(AreaChart, {
28
36
  enableScrubbing: true,
29
37
  showLines: true,
30
38
  stacked: true,
39
+ accessibilityLabel: "Stacked rewards chart with " + currentRewardsData.length + " data points. Swipe to navigate.",
31
40
  curve: "natural",
41
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
32
42
  height: 256,
33
43
  series: [{
34
44
  id: 'currentRewards',
35
- data: [100, 150, 200, 280, 380, 500, 650, 820, 1020, 1250, 1510, 1800, 2120, 2470, 2850, 3260, 3700, 4170],
45
+ data: currentRewardsData,
36
46
  color: theme.color.fg
37
47
  }, {
38
48
  id: 'potentialRewards',
39
- data: [150, 220, 300, 400, 520, 660, 820, 1000, 1200, 1420, 1660, 1920, 2200, 2500, 2820, 3160, 3520, 3900],
49
+ data: potentialRewardsData,
40
50
  color: theme.color.fgPositive,
41
51
  type: 'dotted',
42
52
  LineComponent: DottedLine
@@ -59,6 +69,8 @@ const AreaChartStories = () => {
59
69
  enableScrubbing: true,
60
70
  showLines: true,
61
71
  showYAxis: true,
72
+ accessibilityLabel: "Area chart with negative values. 7 data points. Swipe to navigate.",
73
+ getScrubberAccessibilityLabel: index => "Point " + (index + 1) + ": " + [24, 13, -98, 39, 48, 38, 43][index],
62
74
  height: 150,
63
75
  series: [{
64
76
  id: 'pageViews',
@@ -101,6 +113,8 @@ const AreaChartStories = () => {
101
113
  showLines: true,
102
114
  showXAxis: true,
103
115
  showYAxis: true,
116
+ accessibilityLabel: "Volume by asset. 5 data points. Swipe to navigate.",
117
+ getScrubberAccessibilityLabel: index => ['BTC', 'ETH', 'SOL', 'DOGE', 'ADA'][index] + ": " + [68, 54, 43, 29, 18][index] + "%",
104
118
  height: 280,
105
119
  layout: "horizontal",
106
120
  series: [{
@@ -53,10 +53,14 @@ const Simple = () => {
53
53
  const pageViews = data.map(d => d.pv);
54
54
  const pageNames = data.map(d => d.name);
55
55
  const pageUniqueVisitors = data.map(d => d.uv);
56
+ const chartAccessibilityLabel = "Page views and unique visitors across " + pageNames.length + " pages. Swipe to navigate.";
57
+ const getScrubberAccessibilityLabel = useCallback(index => pageNames[index] + ": " + pageViews[index] + " views, " + pageUniqueVisitors[index] + " unique visitors", [pageNames, pageViews, pageUniqueVisitors]);
56
58
  return /*#__PURE__*/_jsx(LineChart, {
57
59
  enableScrubbing: true,
58
60
  showXAxis: true,
59
61
  showYAxis: true,
62
+ accessibilityLabel: chartAccessibilityLabel,
63
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
60
64
  height: defaultChartHeight,
61
65
  inset: 32,
62
66
  series: [{
@@ -97,8 +101,8 @@ const Simple = () => {
97
101
  };
98
102
  const TimeOfDayAxesExample = () => {
99
103
  const theme = useTheme();
100
- const lineA = [5, 5, 10, 90, 85, 70, 30, 25, 25];
101
- const lineB = [90, 85, 70, 25, 23, 40, 45, 40, 50];
104
+ const lineA = useMemo(() => [5, 5, 10, 90, 85, 70, 30, 25, 25], []);
105
+ const lineB = useMemo(() => [90, 85, 70, 25, 23, 40, 45, 40, 50], []);
102
106
  const timeData = useMemo(() => [new Date(2023, 7, 31), new Date(2023, 7, 31, 12), new Date(2023, 8, 1), new Date(2023, 8, 1, 12), new Date(2023, 8, 2), new Date(2023, 8, 2, 12), new Date(2023, 8, 3), new Date(2023, 8, 3, 12), new Date(2023, 8, 4)].map(d => d.getTime()), []);
103
107
  const dateFormatter = useCallback(index => {
104
108
  return new Date(timeData[index]).toLocaleDateString('en-US', {
@@ -117,8 +121,12 @@ const TimeOfDayAxesExample = () => {
117
121
  const dateTicks = useMemo(() => {
118
122
  return timeData.map((d, index) => index).filter(d => d % 2 === 0);
119
123
  }, [timeData]);
124
+ const chartAccessibilityLabel = "Chart with " + lineA.length + " data points. Swipe to navigate.";
125
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": lineA " + lineA[index] + ", lineB " + lineB[index], [lineA, lineB]);
120
126
  return /*#__PURE__*/_jsxs(LineChart, {
121
127
  enableScrubbing: true,
128
+ accessibilityLabel: chartAccessibilityLabel,
129
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
122
130
  height: defaultChartHeight,
123
131
  series: [{
124
132
  id: 'lineA',
@@ -150,51 +158,57 @@ const TimeOfDayAxesExample = () => {
150
158
  }), /*#__PURE__*/_jsx(Scrubber, {})]
151
159
  });
152
160
  };
153
- const MultipleYAxesExample = () => /*#__PURE__*/_jsxs(CartesianChart, {
154
- enableScrubbing: true,
155
- height: defaultChartHeight,
156
- series: [{
157
- id: 'linear',
158
- yAxisId: 'linearAxis',
159
- data: [1, 10, 30, 50, 70, 90, 100],
160
- label: 'linear'
161
- }, {
162
- id: 'log',
163
- yAxisId: 'logAxis',
164
- data: [1, 10, 30, 50, 70, 90, 100],
165
- label: 'log'
166
- }],
167
- xAxis: {
168
- data: [1, 10, 30, 50, 70, 90, 100]
169
- },
170
- yAxis: [{
171
- id: 'linearAxis',
172
- scaleType: 'linear'
173
- }, {
174
- id: 'logAxis',
175
- scaleType: 'log'
176
- }],
177
- children: [/*#__PURE__*/_jsx(XAxis, {
178
- showLine: true,
179
- showTickMarks: true
180
- }), /*#__PURE__*/_jsx(YAxis, {
181
- showLine: true,
182
- showTickMarks: true,
183
- axisId: "logAxis",
184
- position: "left"
185
- }), /*#__PURE__*/_jsx(YAxis, {
186
- showLine: true,
187
- showTickMarks: true,
188
- axisId: "linearAxis",
189
- position: "left"
190
- }), /*#__PURE__*/_jsx(Line, {
191
- curve: "natural",
192
- seriesId: "linear"
193
- }), /*#__PURE__*/_jsx(Line, {
194
- curve: "natural",
195
- seriesId: "log"
196
- }), /*#__PURE__*/_jsx(Scrubber, {})]
197
- });
161
+ const multipleYAxesData = [1, 10, 30, 50, 70, 90, 100];
162
+ const MultipleYAxesExample = () => {
163
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": linear " + multipleYAxesData[index] + ", log " + multipleYAxesData[index], []);
164
+ return /*#__PURE__*/_jsxs(CartesianChart, {
165
+ enableScrubbing: true,
166
+ accessibilityLabel: "Chart with linear and log axes. 7 data points. Swipe to navigate.",
167
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
168
+ height: defaultChartHeight,
169
+ series: [{
170
+ id: 'linear',
171
+ yAxisId: 'linearAxis',
172
+ data: multipleYAxesData,
173
+ label: 'linear'
174
+ }, {
175
+ id: 'log',
176
+ yAxisId: 'logAxis',
177
+ data: multipleYAxesData,
178
+ label: 'log'
179
+ }],
180
+ xAxis: {
181
+ data: multipleYAxesData
182
+ },
183
+ yAxis: [{
184
+ id: 'linearAxis',
185
+ scaleType: 'linear'
186
+ }, {
187
+ id: 'logAxis',
188
+ scaleType: 'log'
189
+ }],
190
+ children: [/*#__PURE__*/_jsx(XAxis, {
191
+ showLine: true,
192
+ showTickMarks: true
193
+ }), /*#__PURE__*/_jsx(YAxis, {
194
+ showLine: true,
195
+ showTickMarks: true,
196
+ axisId: "logAxis",
197
+ position: "left"
198
+ }), /*#__PURE__*/_jsx(YAxis, {
199
+ showLine: true,
200
+ showTickMarks: true,
201
+ axisId: "linearAxis",
202
+ position: "left"
203
+ }), /*#__PURE__*/_jsx(Line, {
204
+ curve: "natural",
205
+ seriesId: "linear"
206
+ }), /*#__PURE__*/_jsx(Line, {
207
+ curve: "natural",
208
+ seriesId: "log"
209
+ }), /*#__PURE__*/_jsx(Scrubber, {})]
210
+ });
211
+ };
198
212
  const AxesOnAllSides = () => {
199
213
  const theme = useTheme();
200
214
  const data = [30, 45, 60, 80, 55, 40, 65];
@@ -298,9 +312,12 @@ const DomainLimitType = _ref => {
298
312
  let {
299
313
  limit
300
314
  } = _ref;
301
- const exponentialData = [1, 2, 4, 8, 15, 30, 65, 140, 280, 580, 1200, 2400, 4800, 9500, 19000, 38000, 75000, 150000];
315
+ const exponentialData = useMemo(() => [1, 2, 4, 8, 15, 30, 65, 140, 280, 580, 1200, 2400, 4800, 9500, 19000, 38000, 75000, 150000], []);
316
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + exponentialData[index], [exponentialData]);
302
317
  return /*#__PURE__*/_jsxs(CartesianChart, {
303
318
  enableScrubbing: true,
319
+ accessibilityLabel: "Exponential growth chart with " + exponentialData.length + " data points. Swipe to navigate.",
320
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
304
321
  height: defaultChartHeight,
305
322
  series: [{
306
323
  id: 'growthLinear',
@@ -34,6 +34,7 @@ export const Bar = /*#__PURE__*/memo(_ref => {
34
34
  borderRadius = 4,
35
35
  roundTop = true,
36
36
  roundBottom = true,
37
+ minSize,
37
38
  transitions,
38
39
  transition
39
40
  } = _ref;
@@ -41,28 +42,21 @@ export const Bar = /*#__PURE__*/memo(_ref => {
41
42
  const {
42
43
  layout
43
44
  } = useCartesianChartContext();
44
-
45
- // Use theme color as default if no fill is provided
46
- const effectiveFill = fill != null ? fill : theme.color.fgPrimary;
47
- const borderRadiusPixels = useMemo(() => borderRadius != null ? borderRadius : 0, [borderRadius]);
48
45
  const barPath = useMemo(() => {
49
- return getBarPath(x, y, width, height, borderRadiusPixels, roundTop, roundBottom, layout);
50
- }, [x, y, width, height, borderRadiusPixels, roundTop, roundBottom, layout]);
51
- const effectiveOrigin = originProp != null ? originProp : layout === 'horizontal' ? x : y + height;
52
- if (!barPath) {
53
- return null;
54
- }
55
-
56
- // Always use the BarComponent for rendering
46
+ return getBarPath(x, y, width, height, borderRadius, roundTop, roundBottom, layout);
47
+ }, [x, y, width, height, borderRadius, roundTop, roundBottom, layout]);
48
+ const origin = useMemo(() => originProp != null ? originProp : layout === 'horizontal' ? x : y + height, [originProp, layout, x, y, height]);
49
+ if (!barPath) return;
57
50
  return /*#__PURE__*/_jsx(BarComponent, {
58
51
  borderRadius: borderRadius,
59
52
  d: barPath,
60
53
  dataX: dataX,
61
54
  dataY: dataY,
62
- fill: effectiveFill,
55
+ fill: fill != null ? fill : theme.color.fgPrimary,
63
56
  fillOpacity: fillOpacity,
64
57
  height: height,
65
- origin: effectiveOrigin,
58
+ minSize: minSize,
59
+ origin: origin,
66
60
  roundBottom: roundBottom,
67
61
  roundTop: roundTop,
68
62
  seriesId: seriesId,
@@ -44,9 +44,9 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
44
44
  });
45
45
  }, [seriesProp, stacked]);
46
46
  const seriesIds = useMemo(() => series == null ? void 0 : series.map(s => s.id), [series]);
47
- const isHorizontal = chartProps.layout === 'horizontal';
48
- const defaultXScaleType = isHorizontal ? 'linear' : 'band';
49
- const defaultYScaleType = isHorizontal ? 'band' : 'linear';
47
+ const isHorizontalLayout = chartProps.layout === 'horizontal';
48
+ const defaultXScaleType = isHorizontalLayout ? 'linear' : 'band';
49
+ const defaultYScaleType = isHorizontalLayout ? 'band' : 'linear';
50
50
 
51
51
  // Split axis props into config props for Chart and visual props for axis components
52
52
  const _ref2 = xAxis || {},
@@ -82,24 +82,24 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
82
82
  scaleType: xScaleType != null ? xScaleType : defaultXScaleType,
83
83
  data: xData,
84
84
  categoryPadding: xCategoryPadding,
85
- domain: isHorizontal && !hasNegativeValues ? _extends({
85
+ domain: isHorizontalLayout && !hasNegativeValues ? _extends({
86
86
  min: 0
87
87
  }, xDomain) : xDomain,
88
88
  domainLimit: xDomainLimit,
89
89
  range: xRange
90
- }), [xScaleType, defaultXScaleType, xData, xCategoryPadding, isHorizontal, hasNegativeValues, xDomain, xDomainLimit, xRange]);
90
+ }), [xScaleType, defaultXScaleType, xData, xCategoryPadding, isHorizontalLayout, hasNegativeValues, xDomain, xDomainLimit, xRange]);
91
91
 
92
92
  // Set default min domain to 0 for bar chart, but only if there are no negative values.
93
93
  const yAxisConfig = useMemo(() => ({
94
94
  scaleType: yScaleType != null ? yScaleType : defaultYScaleType,
95
95
  data: yData,
96
96
  categoryPadding: yCategoryPadding,
97
- domain: !isHorizontal && !hasNegativeValues ? _extends({
97
+ domain: !isHorizontalLayout && !hasNegativeValues ? _extends({
98
98
  min: 0
99
99
  }, yDomain) : yDomain,
100
100
  domainLimit: yDomainLimit,
101
101
  range: yRange
102
- }), [yScaleType, defaultYScaleType, yData, yCategoryPadding, isHorizontal, hasNegativeValues, yDomain, yDomainLimit, yRange]);
102
+ }), [yScaleType, defaultYScaleType, yData, yCategoryPadding, isHorizontalLayout, hasNegativeValues, yDomain, yDomainLimit, yRange]);
103
103
  return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
104
104
  ref: ref,
105
105
  inset: inset,
@@ -1,9 +1,17 @@
1
- import { memo, useMemo } from 'react';
2
- import { Group, Skia } from '@shopify/react-native-skia';
1
+ import { memo, useEffect, useMemo, useState } from 'react';
2
+ import { useSharedValue } from 'react-native-reanimated';
3
+ import { Group, Skia, usePathInterpolation } from '@shopify/react-native-skia';
3
4
  import { useCartesianChartContext } from '../ChartProvider';
4
- import { defaultAxisId } from '../utils';
5
+ import { getStackGroups } from '../utils';
6
+ import { buildTransition, instantTransition } from '../utils/transition';
5
7
  import { BarStackGroup } from './BarStackGroup';
6
8
  import { jsx as _jsx } from "react/jsx-runtime";
9
+ const makeClipPath = area => {
10
+ const path = Skia.Path.Make();
11
+ path.addRect(area);
12
+ return path;
13
+ };
14
+
7
15
  /**
8
16
  * BarPlot component that handles multiple series with proper stacking coordination.
9
17
  * Groups series by stack ID + y-axis ID combination and renders BarStackGroup for each group.
@@ -28,6 +36,7 @@ export const BarPlot = /*#__PURE__*/memo(_ref => {
28
36
  transition
29
37
  } = _ref;
30
38
  const {
39
+ animate,
31
40
  series: allSeries,
32
41
  drawingArea
33
42
  } = useCartesianChartContext();
@@ -38,50 +47,32 @@ export const BarPlot = /*#__PURE__*/memo(_ref => {
38
47
  }
39
48
  return allSeries;
40
49
  }, [allSeries, seriesIds]);
41
- const stackGroups = useMemo(() => {
42
- const groups = new Map();
43
-
44
- // Group series into stacks based on stackId + axis ID combination
45
- targetSeries.forEach(series => {
46
- var _series$xAxisId, _series$yAxisId;
47
- const xAxisId = (_series$xAxisId = series.xAxisId) != null ? _series$xAxisId : defaultAxisId;
48
- const yAxisId = (_series$yAxisId = series.yAxisId) != null ? _series$yAxisId : defaultAxisId;
49
- const stackId = series.stackId || "individual-" + series.id;
50
- const stackKey = stackId + ":" + xAxisId + ":" + yAxisId;
51
- if (!groups.has(stackKey)) {
52
- groups.set(stackKey, {
53
- stackId: stackKey,
54
- series: [],
55
- xAxisId: series.xAxisId,
56
- yAxisId: series.yAxisId
57
- });
58
- }
59
- const group = groups.get(stackKey);
60
- group.series.push(series);
61
- });
62
- return Array.from(groups.values());
63
- }, [targetSeries]);
64
-
65
- // Create clip path for the entire chart area (shared by all bars)
66
- const clipPath = useMemo(() => {
67
- if (!drawingArea) return null;
68
- const clip = Skia.Path.Make();
69
- clip.addRect({
70
- x: drawingArea.x,
71
- y: drawingArea.y,
72
- width: drawingArea.width,
73
- height: drawingArea.height
74
- });
75
- return clip;
76
- }, [drawingArea]);
77
- if (!clipPath) {
78
- return null;
79
- }
80
-
81
- // Note: Clipping is now handled here at the BarPlot level (one clip path for all bars!)
82
- // This is much more efficient than creating a clip path for each individual bar
50
+ const stackGroups = useMemo(() => getStackGroups(targetSeries), [targetSeries]);
51
+ const clipUpdateTransition = useMemo(() => (transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : instantTransition, [transitions == null ? void 0 : transitions.update]);
52
+ const emptyPath = useMemo(() => Skia.Path.Make(), []);
53
+ const initialPath = useMemo(() => drawingArea ? makeClipPath(drawingArea) : emptyPath,
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ []);
56
+ const [clipPaths, setClipPaths] = useState({
57
+ from: initialPath,
58
+ to: initialPath
59
+ });
60
+ const clipProgress = useSharedValue(0);
61
+ useEffect(() => {
62
+ if (!drawingArea) return;
63
+ const nextPath = makeClipPath(drawingArea);
64
+ setClipPaths(prev => ({
65
+ from: prev.to,
66
+ to: nextPath
67
+ }));
68
+ clipProgress.value = 0;
69
+ clipProgress.value = buildTransition(1, animate ? clipUpdateTransition : null);
70
+ // eslint-disable-next-line react-hooks/exhaustive-deps
71
+ }, [drawingArea, animate, clipUpdateTransition]);
72
+ const animatedClipPath = usePathInterpolation(clipProgress, [0, 1], [clipPaths.from, clipPaths.to]);
73
+ if (!drawingArea) return;
83
74
  return /*#__PURE__*/_jsx(Group, {
84
- clip: clipPath,
75
+ clip: animatedClipPath,
85
76
  children: stackGroups.map((group, stackIndex) => /*#__PURE__*/_jsx(BarStackGroup, {
86
77
  BarComponent: defaultBarComponent,
87
78
  BarStackComponent: BarStackComponent,