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

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 (100) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dts/chart/CartesianChart.d.ts +39 -7
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/Path.d.ts.map +1 -1
  5. package/dts/chart/area/Area.d.ts +7 -0
  6. package/dts/chart/area/Area.d.ts.map +1 -1
  7. package/dts/chart/area/AreaChart.d.ts +5 -5
  8. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  9. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  10. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  11. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  12. package/dts/chart/axis/Axis.d.ts +3 -1
  13. package/dts/chart/axis/Axis.d.ts.map +1 -1
  14. package/dts/chart/axis/XAxis.d.ts +6 -0
  15. package/dts/chart/axis/XAxis.d.ts.map +1 -1
  16. package/dts/chart/axis/YAxis.d.ts +1 -0
  17. package/dts/chart/axis/YAxis.d.ts.map +1 -1
  18. package/dts/chart/bar/Bar.d.ts +4 -2
  19. package/dts/chart/bar/Bar.d.ts.map +1 -1
  20. package/dts/chart/bar/BarChart.d.ts +49 -9
  21. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  22. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  23. package/dts/chart/bar/BarStack.d.ts +30 -9
  24. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  25. package/dts/chart/bar/BarStackGroup.d.ts +1 -1
  26. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  27. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  28. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  29. package/dts/chart/gradient/Gradient.d.ts +5 -0
  30. package/dts/chart/gradient/Gradient.d.ts.map +1 -1
  31. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  32. package/dts/chart/line/Line.d.ts +7 -0
  33. package/dts/chart/line/Line.d.ts.map +1 -1
  34. package/dts/chart/line/LineChart.d.ts +5 -5
  35. package/dts/chart/line/LineChart.d.ts.map +1 -1
  36. package/dts/chart/line/ReferenceLine.d.ts +1 -0
  37. package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
  38. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  39. package/dts/chart/point/Point.d.ts +7 -0
  40. package/dts/chart/point/Point.d.ts.map +1 -1
  41. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
  42. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +2 -1
  43. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -1
  44. package/dts/chart/scrubber/Scrubber.d.ts +8 -0
  45. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  46. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -1
  47. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
  48. package/dts/chart/utils/axis.d.ts +20 -9
  49. package/dts/chart/utils/axis.d.ts.map +1 -1
  50. package/dts/chart/utils/bar.d.ts +4 -3
  51. package/dts/chart/utils/bar.d.ts.map +1 -1
  52. package/dts/chart/utils/chart.d.ts +13 -0
  53. package/dts/chart/utils/chart.d.ts.map +1 -1
  54. package/dts/chart/utils/context.d.ts +21 -6
  55. package/dts/chart/utils/context.d.ts.map +1 -1
  56. package/dts/chart/utils/gradient.d.ts +3 -1
  57. package/dts/chart/utils/gradient.d.ts.map +1 -1
  58. package/dts/chart/utils/path.d.ts +20 -0
  59. package/dts/chart/utils/path.d.ts.map +1 -1
  60. package/dts/chart/utils/point.d.ts +7 -0
  61. package/dts/chart/utils/point.d.ts.map +1 -1
  62. package/esm/chart/CartesianChart.js +107 -68
  63. package/esm/chart/Path.js +10 -7
  64. package/esm/chart/area/Area.js +19 -9
  65. package/esm/chart/area/AreaChart.js +11 -9
  66. package/esm/chart/area/DottedArea.js +11 -6
  67. package/esm/chart/area/GradientArea.js +11 -6
  68. package/esm/chart/area/SolidArea.js +3 -1
  69. package/esm/chart/area/__stories__/AreaChart.stories.js +30 -2
  70. package/esm/chart/axis/XAxis.js +14 -21
  71. package/esm/chart/axis/YAxis.js +4 -3
  72. package/esm/chart/bar/Bar.js +9 -5
  73. package/esm/chart/bar/BarChart.js +34 -31
  74. package/esm/chart/bar/BarPlot.js +7 -5
  75. package/esm/chart/bar/BarStack.js +176 -36
  76. package/esm/chart/bar/BarStackGroup.js +37 -27
  77. package/esm/chart/bar/DefaultBar.js +24 -8
  78. package/esm/chart/bar/DefaultBarStack.js +24 -10
  79. package/esm/chart/bar/__stories__/BarChart.stories.js +99 -3
  80. package/esm/chart/gradient/Gradient.js +2 -1
  81. package/esm/chart/line/DottedLine.js +3 -1
  82. package/esm/chart/line/Line.js +32 -19
  83. package/esm/chart/line/LineChart.js +9 -8
  84. package/esm/chart/line/SolidLine.js +3 -1
  85. package/esm/chart/line/__stories__/LineChart.stories.js +31 -0
  86. package/esm/chart/point/Point.js +2 -1
  87. package/esm/chart/scrubber/DefaultScrubberBeacon.js +1 -1
  88. package/esm/chart/scrubber/DefaultScrubberLabel.js +26 -10
  89. package/esm/chart/scrubber/Scrubber.js +47 -21
  90. package/esm/chart/scrubber/ScrubberBeaconGroup.js +24 -20
  91. package/esm/chart/scrubber/ScrubberProvider.js +29 -24
  92. package/esm/chart/scrubber/__stories__/Scrubber.stories.js +135 -1
  93. package/esm/chart/utils/axis.js +42 -14
  94. package/esm/chart/utils/bar.js +5 -4
  95. package/esm/chart/utils/chart.js +18 -5
  96. package/esm/chart/utils/context.js +7 -0
  97. package/esm/chart/utils/gradient.js +8 -4
  98. package/esm/chart/utils/path.js +90 -61
  99. package/esm/chart/utils/point.js +28 -18
  100. package/package.json +5 -5
@@ -1,4 +1,4 @@
1
- const _excluded = ["series", "children", "animate", "enableScrubbing", "xAxis", "yAxis", "inset", "onScrubberPositionChange", "legend", "legendPosition", "legendAccessibilityLabel", "width", "height", "style", "styles", "allowOverflowGestures", "fontFamilies", "fontProvider", "collapsable"];
1
+ const _excluded = ["series", "children", "layout", "animate", "enableScrubbing", "xAxis", "yAxis", "inset", "onScrubberPositionChange", "legend", "legendPosition", "legendAccessibilityLabel", "width", "height", "style", "styles", "allowOverflowGestures", "fontFamilies", "fontProvider", "collapsable"];
2
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
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
4
  import React, { forwardRef, memo, useCallback, useMemo } from 'react';
@@ -10,7 +10,7 @@ import { convertToSerializableScale } from './utils/scale';
10
10
  import { useChartContextBridge } from './ChartContextBridge';
11
11
  import { CartesianChartProvider } from './ChartProvider';
12
12
  import { Legend } from './legend';
13
- import { defaultAxisId, defaultChartInset, getAxisConfig, getAxisDomain, getAxisRange, getAxisScale, getChartInset, getStackedSeriesData as calculateStackedSeriesData, useTotalAxisPadding } from './utils';
13
+ import { defaultAxisId, defaultHorizontalLayoutChartInset, defaultVerticalLayoutChartInset, getAxisConfig, getAxisRange, getCartesianAxisDomain, getCartesianAxisScale, getChartInset, getStackedSeriesData as calculateStackedSeriesData, useTotalAxisPadding } from './utils';
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  const ChartCanvas = /*#__PURE__*/memo(_ref => {
16
16
  let {
@@ -32,6 +32,7 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
32
32
  let {
33
33
  series,
34
34
  children,
35
+ layout = 'vertical',
35
36
  animate = true,
36
37
  enableScrubbing,
37
38
  xAxis: xAxisConfigProp,
@@ -57,11 +58,18 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
57
58
  const [containerLayout, onContainerLayout] = useLayout();
58
59
  const chartWidth = containerLayout.width;
59
60
  const chartHeight = containerLayout.height;
60
- const calculatedInset = useMemo(() => getChartInset(inset, defaultChartInset), [inset]);
61
-
62
- // there can only be one x axis but the helper function always returns an array
63
- const xAxisConfig = useMemo(() => getAxisConfig('x', xAxisConfigProp)[0], [xAxisConfigProp]);
61
+ const calculatedInset = useMemo(() => getChartInset(inset, layout === 'horizontal' ? defaultHorizontalLayoutChartInset : defaultVerticalLayoutChartInset), [inset, layout]);
62
+ const xAxisConfig = useMemo(() => getAxisConfig('x', xAxisConfigProp), [xAxisConfigProp]);
64
63
  const yAxisConfig = useMemo(() => getAxisConfig('y', yAxisConfigProp), [yAxisConfigProp]);
64
+
65
+ // Horizontal layout supports multiple value axes on x, but only a single category axis on y.
66
+ // Vertical layout keeps a single x-axis to preserve existing behavior.
67
+ if (layout === 'horizontal' && yAxisConfig.length > 1) {
68
+ throw new Error('When layout="horizontal", only one y-axis is supported. See https://cds.coinbase.com/components/charts/CartesianChart.');
69
+ }
70
+ if (layout !== 'horizontal' && xAxisConfig.length > 1) {
71
+ throw new Error('Multiple x-axes are only supported when layout="horizontal". See https://cds.coinbase.com/components/charts/CartesianChart.');
72
+ }
65
73
  const {
66
74
  renderedAxes,
67
75
  registerAxis,
@@ -91,54 +99,76 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
91
99
  };
92
100
  }, [chartHeight, chartWidth, totalInset]);
93
101
  const {
94
- xAxis,
95
- xScale
102
+ xAxes,
103
+ xScales
96
104
  } = useMemo(() => {
105
+ const axes = new Map();
106
+ const scales = new Map();
97
107
  if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return {
98
- xAxis: undefined,
99
- xScale: undefined
100
- };
101
- const domain = getAxisDomain(xAxisConfig, series != null ? series : [], 'x');
102
- const range = getAxisRange(xAxisConfig, chartRect, 'x');
103
- const axisConfig = {
104
- scaleType: xAxisConfig.scaleType,
105
- domain,
106
- range,
107
- data: xAxisConfig.data,
108
- categoryPadding: xAxisConfig.categoryPadding,
109
- domainLimit: xAxisConfig.domainLimit
108
+ xAxes: axes,
109
+ xScales: scales
110
110
  };
111
+ xAxisConfig.forEach(axisParam => {
112
+ var _axisParam$id, _series$filter, _axisParam$domainLimi;
113
+ const axisId = (_axisParam$id = axisParam.id) != null ? _axisParam$id : defaultAxisId;
111
114
 
112
- // Create the scale
113
- const scale = getAxisScale({
114
- config: axisConfig,
115
- type: 'x',
116
- range: axisConfig.range,
117
- dataDomain: axisConfig.domain
118
- });
119
- if (!scale) return {
120
- xAxis: undefined,
121
- xScale: undefined
122
- };
115
+ // Get relevant series data.
116
+ const relevantSeries = xAxisConfig.length > 1 ? (_series$filter = series == null ? void 0 : series.filter(s => {
117
+ var _s$xAxisId;
118
+ return ((_s$xAxisId = s.xAxisId) != null ? _s$xAxisId : defaultAxisId) === axisId;
119
+ })) != null ? _series$filter : [] : series != null ? series : [];
120
+
121
+ // Calculate domain and range.
122
+ const dataDomain = getCartesianAxisDomain(axisParam, relevantSeries, 'x', layout);
123
+ const range = getAxisRange(axisParam, chartRect, 'x');
124
+ const axisConfig = {
125
+ scaleType: axisParam.scaleType,
126
+ domain: dataDomain,
127
+ range,
128
+ data: axisParam.data,
129
+ categoryPadding: axisParam.categoryPadding,
130
+ domainLimit: (_axisParam$domainLimi = axisParam.domainLimit) != null ? _axisParam$domainLimi : layout === 'horizontal' ? 'nice' : 'strict'
131
+ };
132
+
133
+ // Create the scale.
134
+ const scale = getCartesianAxisScale({
135
+ config: axisConfig,
136
+ type: 'x',
137
+ range: axisConfig.range,
138
+ dataDomain: axisConfig.domain,
139
+ layout
140
+ });
141
+ if (scale) {
142
+ scales.set(axisId, scale);
123
143
 
124
- // Update axis config with actual scale domain (after .nice() or other adjustments)
125
- const scaleDomain = scale.domain();
126
- const actualDomain = Array.isArray(scaleDomain) && scaleDomain.length === 2 ? {
127
- min: scaleDomain[0],
128
- max: scaleDomain[1]
129
- } : axisConfig.domain;
130
- const finalAxisConfig = _extends({}, axisConfig, {
131
- domain: actualDomain
144
+ // Update axis config with actual scale domain (after .nice() or other adjustments).
145
+ const scaleDomain = scale.domain();
146
+ const actualDomain = Array.isArray(scaleDomain) && scaleDomain.length === 2 ? {
147
+ min: scaleDomain[0],
148
+ max: scaleDomain[1]
149
+ } : axisConfig.domain;
150
+ axes.set(axisId, _extends({}, axisConfig, {
151
+ domain: actualDomain
152
+ }));
153
+ }
132
154
  });
133
155
  return {
134
- xAxis: finalAxisConfig,
135
- xScale: scale
156
+ xAxes: axes,
157
+ xScales: scales
136
158
  };
137
- }, [xAxisConfig, series, chartRect]);
138
- const xSerializableScale = useMemo(() => {
139
- if (!xScale) return;
140
- return convertToSerializableScale(xScale);
141
- }, [xScale]);
159
+ }, [xAxisConfig, series, chartRect, layout]);
160
+
161
+ // We need a set of serialized scales usable in UI thread.
162
+ const xSerializableScales = useMemo(() => {
163
+ const serializableScales = new Map();
164
+ xScales.forEach((scale, id) => {
165
+ const serializableScale = convertToSerializableScale(scale);
166
+ if (serializableScale) {
167
+ serializableScales.set(id, serializableScale);
168
+ }
169
+ });
170
+ return serializableScales;
171
+ }, [xScales]);
142
172
  const {
143
173
  yAxes,
144
174
  yScales
@@ -150,17 +180,17 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
150
180
  yScales: scales
151
181
  };
152
182
  yAxisConfig.forEach(axisParam => {
153
- var _axisParam$id, _series$filter, _axisParam$domainLimi;
154
- const axisId = (_axisParam$id = axisParam.id) != null ? _axisParam$id : defaultAxisId;
183
+ var _axisParam$id2, _series$filter2, _axisParam$domainLimi2;
184
+ const axisId = (_axisParam$id2 = axisParam.id) != null ? _axisParam$id2 : defaultAxisId;
155
185
 
156
- // Get relevant series data
157
- const relevantSeries = (_series$filter = series == null ? void 0 : series.filter(s => {
186
+ // Get relevant series data.
187
+ const relevantSeries = yAxisConfig.length > 1 ? (_series$filter2 = series == null ? void 0 : series.filter(s => {
158
188
  var _s$yAxisId;
159
189
  return ((_s$yAxisId = s.yAxisId) != null ? _s$yAxisId : defaultAxisId) === axisId;
160
- })) != null ? _series$filter : [];
190
+ })) != null ? _series$filter2 : [] : series != null ? series : [];
161
191
 
162
- // Calculate domain and range
163
- const dataDomain = getAxisDomain(axisParam, relevantSeries, 'y');
192
+ // Calculate domain and range.
193
+ const dataDomain = getCartesianAxisDomain(axisParam, relevantSeries, 'y', layout);
164
194
  const range = getAxisRange(axisParam, chartRect, 'y');
165
195
  const axisConfig = {
166
196
  scaleType: axisParam.scaleType,
@@ -168,20 +198,21 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
168
198
  range,
169
199
  data: axisParam.data,
170
200
  categoryPadding: axisParam.categoryPadding,
171
- domainLimit: (_axisParam$domainLimi = axisParam.domainLimit) != null ? _axisParam$domainLimi : 'nice'
201
+ domainLimit: (_axisParam$domainLimi2 = axisParam.domainLimit) != null ? _axisParam$domainLimi2 : layout === 'horizontal' ? 'strict' : 'nice'
172
202
  };
173
203
 
174
- // Create the scale
175
- const scale = getAxisScale({
204
+ // Create the scale.
205
+ const scale = getCartesianAxisScale({
176
206
  config: axisConfig,
177
207
  type: 'y',
178
208
  range: axisConfig.range,
179
- dataDomain: axisConfig.domain
209
+ dataDomain: axisConfig.domain,
210
+ layout
180
211
  });
181
212
  if (scale) {
182
213
  scales.set(axisId, scale);
183
214
 
184
- // Update axis config with actual scale domain (after .nice() or other adjustments)
215
+ // Update axis config with actual scale domain (after .nice() or other adjustments).
185
216
  const scaleDomain = scale.domain();
186
217
  const actualDomain = Array.isArray(scaleDomain) && scaleDomain.length === 2 ? {
187
218
  min: scaleDomain[0],
@@ -196,7 +227,7 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
196
227
  yAxes: axes,
197
228
  yScales: scales
198
229
  };
199
- }, [yAxisConfig, series, chartRect]);
230
+ }, [yAxisConfig, series, chartRect, layout]);
200
231
 
201
232
  // We need a set of serialized scales usable in UI thread
202
233
  const ySerializableScales = useMemo(() => {
@@ -209,11 +240,11 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
209
240
  });
210
241
  return serializableScales;
211
242
  }, [yScales]);
212
- const getXAxis = useCallback(() => xAxis, [xAxis]);
243
+ const getXAxis = useCallback(id => xAxes.get(id != null ? id : defaultAxisId), [xAxes]);
213
244
  const getYAxis = useCallback(id => yAxes.get(id != null ? id : defaultAxisId), [yAxes]);
214
- const getXScale = useCallback(() => xScale, [xScale]);
245
+ const getXScale = useCallback(id => xScales.get(id != null ? id : defaultAxisId), [xScales]);
215
246
  const getYScale = useCallback(id => yScales.get(id != null ? id : defaultAxisId), [yScales]);
216
- const getXSerializableScale = useCallback(() => xSerializableScale, [xSerializableScale]);
247
+ const getXSerializableScale = useCallback(id => xSerializableScales.get(id != null ? id : defaultAxisId), [xSerializableScales]);
217
248
  const getYSerializableScale = useCallback(id => ySerializableScales.get(id != null ? id : defaultAxisId), [ySerializableScales]);
218
249
  const getSeries = useCallback(seriesId => series == null ? void 0 : series.find(s => s.id === seriesId), [series]);
219
250
  const stackedDataMap = useMemo(() => {
@@ -224,20 +255,27 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
224
255
  if (!seriesId) return undefined;
225
256
  return stackedDataMap.get(seriesId);
226
257
  }, [stackedDataMap]);
258
+ const categoryAxisIsX = useMemo(() => {
259
+ return layout !== 'horizontal';
260
+ }, [layout]);
261
+ const categoryAxisConfig = useMemo(() => {
262
+ var _xAxisConfig$, _yAxisConfig$;
263
+ return categoryAxisIsX ? (_xAxisConfig$ = xAxisConfig[0]) != null ? _xAxisConfig$ : yAxisConfig[0] : (_yAxisConfig$ = yAxisConfig[0]) != null ? _yAxisConfig$ : xAxisConfig[0];
264
+ }, [categoryAxisIsX, xAxisConfig, yAxisConfig]);
227
265
  const dataLength = useMemo(() => {
228
- // If xAxis has categorical data, use that length
229
- if (xAxisConfig.data && xAxisConfig.data.length > 0) {
230
- return xAxisConfig.data.length;
266
+ // If category axis has categorical data, use that length.
267
+ if (categoryAxisConfig.data && categoryAxisConfig.data.length > 0) {
268
+ return categoryAxisConfig.data.length;
231
269
  }
232
270
 
233
- // Otherwise, find the longest series
271
+ // Otherwise, find the longest series.
234
272
  if (!series || series.length === 0) return 0;
235
273
  return series.reduce((max, s) => {
236
274
  var _seriesData$length;
237
275
  const seriesData = getStackedSeriesData(s.id);
238
276
  return Math.max(max, (_seriesData$length = seriesData == null ? void 0 : seriesData.length) != null ? _seriesData$length : 0);
239
277
  }, 0);
240
- }, [xAxisConfig.data, series, getStackedSeriesData]);
278
+ }, [categoryAxisConfig, series, getStackedSeriesData]);
241
279
  const getAxisBounds = useCallback(axisId => {
242
280
  const axis = renderedAxes.get(axisId);
243
281
  if (!axis || !chartRect) return;
@@ -290,6 +328,7 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
290
328
  return Skia.TypefaceFontProvider.Make();
291
329
  }, [fontProviderProp]);
292
330
  const contextValue = useMemo(() => ({
331
+ layout,
293
332
  series: series != null ? series : [],
294
333
  getSeries,
295
334
  getSeriesData: getStackedSeriesData,
@@ -309,7 +348,7 @@ export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2,
309
348
  registerAxis,
310
349
  unregisterAxis,
311
350
  getAxisBounds
312
- }), [series, getSeries, getStackedSeriesData, animate, chartWidth, chartHeight, fontFamilies, fontProvider, getXAxis, getYAxis, getXScale, getYScale, getXSerializableScale, getYSerializableScale, chartRect, dataLength, registerAxis, unregisterAxis, getAxisBounds]);
351
+ }), [layout, series, getSeries, getStackedSeriesData, animate, chartWidth, chartHeight, fontFamilies, fontProvider, getXAxis, getYAxis, getXScale, getYScale, getXSerializableScale, getYSerializableScale, chartRect, dataLength, registerAxis, unregisterAxis, getAxisBounds]);
313
352
  const rootStyles = useMemo(() => {
314
353
  return [style, styles == null ? void 0 : styles.root];
315
354
  }, [style, styles == null ? void 0 : styles.root]);
package/esm/chart/Path.js CHANGED
@@ -115,29 +115,32 @@ export const Path = /*#__PURE__*/memo(props => {
115
115
  initialClipPath: null,
116
116
  targetClipPath: null
117
117
  };
118
+ const categoryAxisIsX = context.layout !== 'horizontal';
119
+ const fullWidth = rect.width + totalOffset;
120
+ const fullHeight = rect.height + totalOffset;
118
121
 
119
- // Initial clip path (width = 0)
122
+ // Initial clip path starts collapsed on the category axis.
120
123
  const initial = Skia.Path.Make();
121
124
  initial.addRect({
122
125
  x: rect.x - clipOffset,
123
126
  y: rect.y - clipOffset,
124
- width: 0,
125
- height: rect.height + totalOffset
127
+ width: categoryAxisIsX ? 0 : fullWidth,
128
+ height: categoryAxisIsX ? fullHeight : 0
126
129
  });
127
130
 
128
- // Target clip path (full width)
131
+ // Target clip path is fully expanded.
129
132
  const target = Skia.Path.Make();
130
133
  target.addRect({
131
134
  x: rect.x - clipOffset,
132
135
  y: rect.y - clipOffset,
133
- width: rect.width + totalOffset,
134
- height: rect.height + totalOffset
136
+ width: fullWidth,
137
+ height: fullHeight
135
138
  });
136
139
  return {
137
140
  initialClipPath: initial,
138
141
  targetClipPath: target
139
142
  };
140
- }, [rect, clipOffset, totalOffset]);
143
+ }, [rect, clipOffset, totalOffset, context.layout]);
141
144
 
142
145
  // Use usePathInterpolation for animated clip path
143
146
  const animatedClipPath = usePathInterpolation(clipProgress, [0, 1], shouldAnimateClip && initialClipPath && targetClipPath ? [initialClipPath, targetClipPath] : targetClipPath ? [targetClipPath, targetClipPath] : [Skia.Path.Make(), Skia.Path.Make()]);
@@ -21,33 +21,42 @@ export const Area = /*#__PURE__*/memo(_ref => {
21
21
  animate
22
22
  } = _ref;
23
23
  const {
24
+ layout,
24
25
  getSeries,
25
26
  getSeriesData,
26
27
  getXScale,
27
28
  getYScale,
28
- getXAxis
29
+ getXAxis,
30
+ getYAxis
29
31
  } = useCartesianChartContext();
30
32
  const matchedSeries = useMemo(() => getSeries(seriesId), [seriesId, getSeries]);
31
33
  const gradient = useMemo(() => gradientProp != null ? gradientProp : matchedSeries == null ? void 0 : matchedSeries.gradient, [gradientProp, matchedSeries == null ? void 0 : matchedSeries.gradient]);
32
34
  const fill = useMemo(() => fillProp != null ? fillProp : matchedSeries == null ? void 0 : matchedSeries.color, [fillProp, matchedSeries == null ? void 0 : matchedSeries.color]);
33
35
  const sourceData = useMemo(() => getSeriesData(seriesId), [seriesId, getSeriesData]);
34
- const xAxis = getXAxis();
35
- const xScale = getXScale();
36
+ const xAxis = getXAxis(matchedSeries == null ? void 0 : matchedSeries.xAxisId);
37
+ const xScale = getXScale(matchedSeries == null ? void 0 : matchedSeries.xAxisId);
36
38
  const yScale = getYScale(matchedSeries == null ? void 0 : matchedSeries.yAxisId);
39
+ const yAxis = getYAxis(matchedSeries == null ? void 0 : matchedSeries.yAxisId);
40
+ const categoryAxisIsX = useMemo(() => {
41
+ return layout !== 'horizontal';
42
+ }, [layout]);
43
+ const categoryAxis = useMemo(() => {
44
+ return categoryAxisIsX ? xAxis : yAxis;
45
+ }, [categoryAxisIsX, xAxis, yAxis]);
37
46
  const area = useMemo(() => {
38
47
  if (!sourceData || sourceData.length === 0 || !xScale || !yScale) return '';
39
-
40
- // Get numeric x-axis data if available
41
- const xData = xAxis != null && xAxis.data && Array.isArray(xAxis.data) && typeof xAxis.data[0] === 'number' ? xAxis.data : undefined;
48
+ const indexData = categoryAxis != null && categoryAxis.data && Array.isArray(categoryAxis.data) && typeof categoryAxis.data[0] === 'number' ? categoryAxis.data : undefined;
42
49
  return getAreaPath({
43
50
  data: sourceData,
44
51
  xScale,
45
52
  yScale,
46
53
  curve,
47
- xData,
48
- connectNulls
54
+ xData: categoryAxisIsX ? indexData : undefined,
55
+ yData: !categoryAxisIsX ? indexData : undefined,
56
+ connectNulls,
57
+ layout
49
58
  });
50
- }, [sourceData, xScale, yScale, curve, xAxis == null ? void 0 : xAxis.data, connectNulls]);
59
+ }, [sourceData, xScale, yScale, curve, categoryAxis, categoryAxisIsX, connectNulls, layout]);
51
60
  const AreaComponent = useMemo(() => {
52
61
  if (AreaComponentProp) {
53
62
  return AreaComponentProp;
@@ -72,6 +81,7 @@ export const Area = /*#__PURE__*/memo(_ref => {
72
81
  gradient: gradient,
73
82
  transition: transition,
74
83
  transitions: transitions,
84
+ xAxisId: matchedSeries == null ? void 0 : matchedSeries.xAxisId,
75
85
  yAxisId: matchedSeries == null ? void 0 : matchedSeries.yAxisId
76
86
  });
77
87
  });
@@ -1,15 +1,15 @@
1
1
  const _excluded = ["series", "stacked", "AreaComponent", "curve", "fillOpacity", "type", "connectNulls", "transition", "transitions", "LineComponent", "strokeWidth", "showXAxis", "showYAxis", "showLines", "lineType", "xAxis", "yAxis", "inset", "children"],
2
- _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range"],
2
+ _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
3
3
  _excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
4
- _excluded4 = ["id", "data", "label", "color", "yAxisId", "opacity", "LineComponent", "stackId"],
5
- _excluded5 = ["id", "data", "label", "color", "yAxisId", "fill", "fillOpacity", "stackId", "type"];
4
+ _excluded4 = ["id", "data", "label", "color", "xAxisId", "yAxisId", "opacity", "LineComponent", "stackId"],
5
+ _excluded5 = ["id", "data", "label", "color", "xAxisId", "yAxisId", "fill", "fillOpacity", "stackId", "type"];
6
6
  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); }
7
7
  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; }
8
8
  import { forwardRef, memo, useMemo } from 'react';
9
9
  import { XAxis, YAxis } from '../axis';
10
10
  import { CartesianChart } from '../CartesianChart';
11
11
  import { Line } from '../line/Line';
12
- import { defaultChartInset, defaultStackId, getChartInset } from '../utils';
12
+ import { defaultStackId } from '../utils';
13
13
  import { Area } from './Area';
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
@@ -35,8 +35,6 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
35
35
  children
36
36
  } = _ref,
37
37
  chartProps = _objectWithoutPropertiesLoose(_ref, _excluded);
38
- const calculatedInset = useMemo(() => getChartInset(inset, defaultChartInset), [inset]);
39
-
40
38
  // Convert AreaSeries to Series for Chart context
41
39
  const chartSeries = useMemo(() => {
42
40
  return series == null ? void 0 : series.map(s => ({
@@ -45,6 +43,7 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
45
43
  label: s.label,
46
44
  color: s.color,
47
45
  gradient: s.gradient,
46
+ xAxisId: s.xAxisId,
48
47
  yAxisId: s.yAxisId,
49
48
  stackId: s.stackId
50
49
  }));
@@ -68,7 +67,8 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
68
67
  categoryPadding: xCategoryPadding,
69
68
  domain: xDomain,
70
69
  domainLimit: xDomainLimit,
71
- range: xRange
70
+ range: xRange,
71
+ id: xAxisId
72
72
  } = _ref2,
73
73
  xAxisVisualProps = _objectWithoutPropertiesLoose(_ref2, _excluded2);
74
74
  const _ref3 = yAxis || {},
@@ -111,11 +111,13 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
111
111
  };
112
112
  return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
113
113
  ref: ref,
114
- inset: calculatedInset,
114
+ inset: inset,
115
115
  series: seriesToRender,
116
116
  xAxis: xAxisConfig,
117
117
  yAxis: yAxisConfig,
118
- children: [showXAxis && /*#__PURE__*/_jsx(XAxis, _extends({}, xAxisVisualProps)), showYAxis && /*#__PURE__*/_jsx(YAxis, _extends({
118
+ children: [showXAxis && /*#__PURE__*/_jsx(XAxis, _extends({
119
+ axisId: xAxisId
120
+ }, xAxisVisualProps)), showYAxis && /*#__PURE__*/_jsx(YAxis, _extends({
119
121
  axisId: yAxisId
120
122
  }, yAxisVisualProps)), series == null ? void 0 : series.map(_ref4 => {
121
123
  let {
@@ -1,4 +1,4 @@
1
- const _excluded = ["d", "fill", "patternSize", "dotSize", "peakOpacity", "baselineOpacity", "baseline", "yAxisId", "gradient", "animate", "transitions", "transition"];
1
+ const _excluded = ["d", "fill", "patternSize", "dotSize", "peakOpacity", "baselineOpacity", "baseline", "xAxisId", "yAxisId", "gradient", "animate", "transitions", "transition"];
2
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
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
4
  import { memo, useMemo } from 'react';
@@ -25,6 +25,7 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
25
25
  peakOpacity = 1,
26
26
  baselineOpacity = 0,
27
27
  baseline,
28
+ xAxisId,
28
29
  yAxisId,
29
30
  gradient: gradientProp,
30
31
  animate: animateProp,
@@ -36,10 +37,13 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
36
37
  const {
37
38
  drawingArea,
38
39
  animate,
40
+ layout,
41
+ getXAxis,
39
42
  getYAxis
40
43
  } = useCartesianChartContext();
41
44
  const shouldAnimate = animateProp != null ? animateProp : animate;
42
- const yAxisConfig = getYAxis(yAxisId);
45
+ const valueAxisConfig = layout !== 'horizontal' ? getYAxis(yAxisId) : getXAxis(xAxisId);
46
+ const gradientAxis = layout !== 'horizontal' ? 'y' : 'x';
43
47
  const fill = useMemo(() => fillProp != null ? fillProp : theme.color.fgPrimary, [fillProp, theme.color.fgPrimary]);
44
48
  const updateTransition = useMemo(() => {
45
49
  return (transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition !== undefined ? transition : defaultTransition;
@@ -61,10 +65,10 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
61
65
  });
62
66
  const gradient = useMemo(() => {
63
67
  if (gradientProp) return gradientProp;
64
- if (!yAxisConfig) return;
65
- const baselineValue = getBaseline(yAxisConfig.domain, baseline);
66
- return createGradient(yAxisConfig.domain, baselineValue, fill, peakOpacity, baselineOpacity);
67
- }, [gradientProp, yAxisConfig, fill, baseline, peakOpacity, baselineOpacity]);
68
+ if (!valueAxisConfig) return;
69
+ const baselineValue = getBaseline(valueAxisConfig.domain, baseline);
70
+ return createGradient(valueAxisConfig.domain, baselineValue, fill, peakOpacity, baselineOpacity, gradientAxis);
71
+ }, [gradientProp, valueAxisConfig, fill, baseline, peakOpacity, baselineOpacity, gradientAxis]);
68
72
 
69
73
  // Update transition is used for clip path, we skip update animation on Path itself
70
74
  return /*#__PURE__*/_jsx(Group, {
@@ -78,6 +82,7 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
78
82
  }, pathProps, {
79
83
  children: gradient && /*#__PURE__*/_jsx(Gradient, {
80
84
  gradient: gradient,
85
+ xAxisId: xAxisId,
81
86
  yAxisId: yAxisId
82
87
  })
83
88
  }))
@@ -1,4 +1,4 @@
1
- const _excluded = ["d", "fill", "fillOpacity", "gradient", "peakOpacity", "baselineOpacity", "baseline", "yAxisId", "animate", "transitions", "transition"];
1
+ const _excluded = ["d", "fill", "fillOpacity", "gradient", "peakOpacity", "baselineOpacity", "baseline", "xAxisId", "yAxisId", "animate", "transitions", "transition"];
2
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
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
4
  import { memo, useMemo } from 'react';
@@ -22,6 +22,7 @@ export const GradientArea = /*#__PURE__*/memo(_ref => {
22
22
  peakOpacity = 0.3,
23
23
  baselineOpacity = 0,
24
24
  baseline,
25
+ xAxisId,
25
26
  yAxisId,
26
27
  animate,
27
28
  transitions,
@@ -29,17 +30,20 @@ export const GradientArea = /*#__PURE__*/memo(_ref => {
29
30
  } = _ref,
30
31
  pathProps = _objectWithoutPropertiesLoose(_ref, _excluded);
31
32
  const {
33
+ layout,
34
+ getXAxis,
32
35
  getYAxis
33
36
  } = useCartesianChartContext();
34
37
  const theme = useTheme();
35
- const yAxisConfig = getYAxis(yAxisId);
38
+ const valueAxisConfig = layout !== 'horizontal' ? getYAxis(yAxisId) : getXAxis(xAxisId);
39
+ const gradientAxis = layout !== 'horizontal' ? 'y' : 'x';
36
40
  const fill = useMemo(() => fillProp != null ? fillProp : theme.color.fgPrimary, [fillProp, theme.color.fgPrimary]);
37
41
  const gradient = useMemo(() => {
38
42
  if (gradientProp) return gradientProp;
39
- if (!yAxisConfig) return;
40
- const baselineValue = getBaseline(yAxisConfig.domain, baseline);
41
- return createGradient(yAxisConfig.domain, baselineValue, fill, peakOpacity, baselineOpacity);
42
- }, [gradientProp, yAxisConfig, fill, baseline, peakOpacity, baselineOpacity]);
43
+ if (!valueAxisConfig) return;
44
+ const baselineValue = getBaseline(valueAxisConfig.domain, baseline);
45
+ return createGradient(valueAxisConfig.domain, baselineValue, fill, peakOpacity, baselineOpacity, gradientAxis);
46
+ }, [gradientProp, valueAxisConfig, fill, baseline, peakOpacity, baselineOpacity, gradientAxis]);
43
47
  return /*#__PURE__*/_jsx(Path, _extends({
44
48
  animate: animate,
45
49
  d: d,
@@ -50,6 +54,7 @@ export const GradientArea = /*#__PURE__*/memo(_ref => {
50
54
  }, pathProps, {
51
55
  children: gradient && /*#__PURE__*/_jsx(Gradient, {
52
56
  gradient: gradient,
57
+ xAxisId: xAxisId,
53
58
  yAxisId: yAxisId
54
59
  })
55
60
  }));
@@ -1,4 +1,4 @@
1
- const _excluded = ["d", "fill", "fillOpacity", "yAxisId", "animate", "transitions", "transition", "gradient"];
1
+ const _excluded = ["d", "fill", "fillOpacity", "xAxisId", "yAxisId", "animate", "transitions", "transition", "gradient"];
2
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
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
4
  import { memo } from 'react';
@@ -16,6 +16,7 @@ export const SolidArea = /*#__PURE__*/memo(_ref => {
16
16
  d,
17
17
  fill,
18
18
  fillOpacity = 1,
19
+ xAxisId,
19
20
  yAxisId,
20
21
  animate,
21
22
  transitions,
@@ -34,6 +35,7 @@ export const SolidArea = /*#__PURE__*/memo(_ref => {
34
35
  }, pathProps, {
35
36
  children: gradient && /*#__PURE__*/_jsx(Gradient, {
36
37
  gradient: gradient,
38
+ xAxisId: xAxisId,
37
39
  yAxisId: yAxisId
38
40
  })
39
41
  }));
@@ -59,12 +59,12 @@ const AreaChartStories = () => {
59
59
  enableScrubbing: true,
60
60
  showLines: true,
61
61
  showYAxis: true,
62
- height: 400,
62
+ height: 150,
63
63
  series: [{
64
64
  id: 'pageViews',
65
65
  data: [24, 13, -98, 39, 48, 38, 43]
66
66
  }],
67
- type: "solid",
67
+ type: "gradient",
68
68
  yAxis: {
69
69
  showGrid: true
70
70
  },
@@ -94,6 +94,34 @@ const AreaChartStories = () => {
94
94
  type: 'gradient'
95
95
  }]
96
96
  })
97
+ }), /*#__PURE__*/_jsx(Example, {
98
+ title: "Horizontal Layout",
99
+ children: /*#__PURE__*/_jsx(AreaChart, {
100
+ enableScrubbing: true,
101
+ showLines: true,
102
+ showXAxis: true,
103
+ showYAxis: true,
104
+ height: 280,
105
+ layout: "horizontal",
106
+ series: [{
107
+ id: 'volume',
108
+ data: [68, 54, 43, 29, 18],
109
+ label: 'Volume'
110
+ }],
111
+ type: "gradient",
112
+ xAxis: {
113
+ domain: {
114
+ min: 0,
115
+ max: 80
116
+ },
117
+ tickLabelFormatter: value => value + "%"
118
+ },
119
+ yAxis: {
120
+ data: ['BTC', 'ETH', 'SOL', 'DOGE', 'ADA'],
121
+ scaleType: 'band'
122
+ },
123
+ children: /*#__PURE__*/_jsx(Scrubber, {})
124
+ })
97
125
  })]
98
126
  });
99
127
  };