@coinbase/cds-mobile-visualization 3.4.0-beta.21 → 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.
- package/CHANGELOG.md +14 -0
- package/dts/chart/CartesianChart.d.ts +39 -7
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +18 -6
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +7 -0
- package/dts/chart/area/Area.d.ts.map +1 -1
- package/dts/chart/area/AreaChart.d.ts +33 -9
- package/dts/chart/area/AreaChart.d.ts.map +1 -1
- package/dts/chart/area/DottedArea.d.ts.map +1 -1
- package/dts/chart/area/GradientArea.d.ts.map +1 -1
- package/dts/chart/area/SolidArea.d.ts.map +1 -1
- package/dts/chart/axis/Axis.d.ts +3 -1
- package/dts/chart/axis/Axis.d.ts.map +1 -1
- package/dts/chart/axis/XAxis.d.ts +6 -0
- package/dts/chart/axis/XAxis.d.ts.map +1 -1
- package/dts/chart/axis/YAxis.d.ts +1 -0
- package/dts/chart/axis/YAxis.d.ts.map +1 -1
- package/dts/chart/bar/Bar.d.ts +4 -2
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +49 -9
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +30 -9
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
- package/dts/chart/gradient/Gradient.d.ts +5 -0
- package/dts/chart/gradient/Gradient.d.ts.map +1 -1
- package/dts/chart/line/DottedLine.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +7 -0
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +8 -5
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/ReferenceLine.d.ts +1 -0
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
- package/dts/chart/line/SolidLine.d.ts.map +1 -1
- package/dts/chart/point/Point.d.ts +7 -0
- package/dts/chart/point/Point.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +2 -1
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -1
- package/dts/chart/scrubber/Scrubber.d.ts +8 -0
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +20 -9
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +6 -5
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +13 -0
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/context.d.ts +21 -6
- package/dts/chart/utils/context.d.ts.map +1 -1
- package/dts/chart/utils/gradient.d.ts +3 -1
- package/dts/chart/utils/gradient.d.ts.map +1 -1
- package/dts/chart/utils/path.d.ts +20 -0
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +7 -0
- package/dts/chart/utils/point.d.ts.map +1 -1
- package/dts/chart/utils/transition.d.ts +7 -4
- package/dts/chart/utils/transition.d.ts.map +1 -1
- package/esm/chart/CartesianChart.js +107 -68
- package/esm/chart/Path.js +18 -14
- package/esm/chart/__stories__/ChartTransitions.stories.js +6 -10
- package/esm/chart/area/Area.js +19 -9
- package/esm/chart/area/AreaChart.js +18 -13
- package/esm/chart/area/DottedArea.js +23 -17
- package/esm/chart/area/GradientArea.js +11 -6
- package/esm/chart/area/SolidArea.js +3 -1
- package/esm/chart/area/__stories__/AreaChart.stories.js +30 -2
- package/esm/chart/axis/XAxis.js +14 -21
- package/esm/chart/axis/YAxis.js +4 -3
- package/esm/chart/bar/Bar.js +9 -5
- package/esm/chart/bar/BarChart.js +34 -31
- package/esm/chart/bar/BarPlot.js +7 -5
- package/esm/chart/bar/BarStack.js +176 -36
- package/esm/chart/bar/BarStackGroup.js +37 -27
- package/esm/chart/bar/DefaultBar.js +24 -8
- package/esm/chart/bar/DefaultBarStack.js +24 -10
- package/esm/chart/bar/__stories__/BarChart.stories.js +99 -3
- package/esm/chart/gradient/Gradient.js +2 -1
- package/esm/chart/line/DottedLine.js +3 -1
- package/esm/chart/line/Line.js +36 -21
- package/esm/chart/line/LineChart.js +13 -11
- package/esm/chart/line/SolidLine.js +3 -1
- package/esm/chart/line/__stories__/LineChart.stories.js +31 -0
- package/esm/chart/point/Point.js +2 -1
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +1 -1
- package/esm/chart/scrubber/DefaultScrubberLabel.js +26 -10
- package/esm/chart/scrubber/Scrubber.js +47 -21
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +24 -20
- package/esm/chart/scrubber/ScrubberProvider.js +29 -24
- package/esm/chart/scrubber/__stories__/Scrubber.stories.js +135 -1
- package/esm/chart/utils/axis.js +42 -14
- package/esm/chart/utils/bar.js +6 -4
- package/esm/chart/utils/chart.js +18 -5
- package/esm/chart/utils/context.js +7 -0
- package/esm/chart/utils/gradient.js +8 -4
- package/esm/chart/utils/path.js +90 -61
- package/esm/chart/utils/point.js +28 -18
- package/esm/chart/utils/transition.js +28 -10
- package/package.json +5 -5
package/esm/chart/utils/bar.js
CHANGED
|
@@ -6,7 +6,8 @@ import { defaultTransition } from './transition';
|
|
|
6
6
|
/**
|
|
7
7
|
* A bar-specific transition that extends Transition with stagger support.
|
|
8
8
|
* When `staggerDelay` is provided, bars will animate with increasing delays
|
|
9
|
-
* based on their
|
|
9
|
+
* based on their position along the category axis (vertical: left-to-right,
|
|
10
|
+
* horizontal: top-to-bottom).
|
|
10
11
|
*
|
|
11
12
|
* @example
|
|
12
13
|
* // Bars stagger in from left to right over 250ms, each animating for 750ms
|
|
@@ -17,18 +18,19 @@ import { defaultTransition } from './transition';
|
|
|
17
18
|
* Strips `staggerDelay` from a transition and computes a positional delay.
|
|
18
19
|
*
|
|
19
20
|
* @param transition - The transition config (may include staggerDelay)
|
|
20
|
-
* @param
|
|
21
|
+
* @param normalizedPosition - The bar's normalized position along the category axis (0–1)
|
|
21
22
|
* @returns A standard Transition with computed delay
|
|
22
23
|
*/
|
|
23
|
-
export const withStaggerDelayTransition = (transition,
|
|
24
|
+
export const withStaggerDelayTransition = (transition, normalizedPosition) => {
|
|
24
25
|
var _baseTransition$delay;
|
|
26
|
+
if (!transition) return null;
|
|
25
27
|
const {
|
|
26
28
|
staggerDelay
|
|
27
29
|
} = transition,
|
|
28
30
|
baseTransition = _objectWithoutPropertiesLoose(transition, _excluded);
|
|
29
31
|
if (!staggerDelay) return transition;
|
|
30
32
|
return _extends({}, baseTransition, {
|
|
31
|
-
delay: ((_baseTransition$delay = baseTransition == null ? void 0 : baseTransition.delay) != null ? _baseTransition$delay : 0) +
|
|
33
|
+
delay: ((_baseTransition$delay = baseTransition == null ? void 0 : baseTransition.delay) != null ? _baseTransition$delay : 0) + normalizedPosition * staggerDelay
|
|
32
34
|
});
|
|
33
35
|
};
|
|
34
36
|
|
package/esm/chart/utils/chart.js
CHANGED
|
@@ -46,15 +46,16 @@ export const getChartDomain = (series, min, max) => {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Creates a composite stack key that includes
|
|
50
|
-
* This ensures series with different
|
|
49
|
+
* Creates a composite stack key that includes stack ID and axis IDs.
|
|
50
|
+
* This ensures series with different scales don't get stacked together.
|
|
51
51
|
*/
|
|
52
52
|
const createStackKey = series => {
|
|
53
53
|
if (series.stackId === undefined) return undefined;
|
|
54
54
|
|
|
55
|
-
// Include
|
|
55
|
+
// Include axis IDs to prevent cross-scale stacking
|
|
56
|
+
const xAxisId = series.xAxisId || 'default';
|
|
56
57
|
const yAxisId = series.yAxisId || 'default';
|
|
57
|
-
return series.stackId + ":" + yAxisId;
|
|
58
|
+
return series.stackId + ":" + xAxisId + ":" + yAxisId;
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
/**
|
|
@@ -225,12 +226,24 @@ export const getChartRange = (series, min, max) => {
|
|
|
225
226
|
}
|
|
226
227
|
return range;
|
|
227
228
|
};
|
|
228
|
-
export const
|
|
229
|
+
export const defaultVerticalLayoutChartInset = {
|
|
229
230
|
top: 32,
|
|
230
231
|
left: 16,
|
|
231
232
|
bottom: 16,
|
|
232
233
|
right: 16
|
|
233
234
|
};
|
|
235
|
+
export const defaultHorizontalLayoutChartInset = {
|
|
236
|
+
top: 16,
|
|
237
|
+
left: 16,
|
|
238
|
+
bottom: 16,
|
|
239
|
+
right: 48
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @deprecated Use `defaultVerticalLayoutChartInset` for vertical layout charts or
|
|
244
|
+
* `defaultHorizontalLayoutChartInset` for horizontal layout charts.
|
|
245
|
+
*/
|
|
246
|
+
export const defaultChartInset = defaultVerticalLayoutChartInset;
|
|
234
247
|
|
|
235
248
|
/**
|
|
236
249
|
* Normalize padding to include all sides with a value.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Chart layout for Cartesian charts.
|
|
5
|
+
* Describes the direction bars/areas grow.
|
|
6
|
+
* - 'vertical': Bars grow vertically (up/down). X is category axis, Y is value axis.
|
|
7
|
+
* - 'horizontal': Bars grow horizontally (left/right). Y is category axis, X is value axis.
|
|
8
|
+
*/
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
11
|
* Context value for Cartesian (X/Y) coordinate charts.
|
|
5
12
|
* Contains axis-specific methods and properties for rectangular coordinate systems.
|
|
@@ -262,9 +262,13 @@ export const getBaseline = function (axisBounds, baseline) {
|
|
|
262
262
|
* @param fill - The color to use for the gradient
|
|
263
263
|
* @param peakOpacity - Opacity at the peak of the gradient
|
|
264
264
|
* @param baselineOpacity - Opacity at the baseline
|
|
265
|
-
* @
|
|
265
|
+
* @param axis - The axis the gradient maps to ('y' for vertical, 'x' for horizontal layout)
|
|
266
|
+
* @returns A gradient definition with stops in ascending order
|
|
266
267
|
*/
|
|
267
|
-
export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity)
|
|
268
|
+
export const createGradient = function (axisBounds, baselineValue, fill, peakOpacity, baselineOpacity, axis) {
|
|
269
|
+
if (axis === void 0) {
|
|
270
|
+
axis = 'y';
|
|
271
|
+
}
|
|
268
272
|
const {
|
|
269
273
|
min,
|
|
270
274
|
max
|
|
@@ -273,7 +277,7 @@ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, bas
|
|
|
273
277
|
const upperBound = Math.max(min, max);
|
|
274
278
|
if (lowerBound < baselineValue && baselineValue < upperBound) {
|
|
275
279
|
return {
|
|
276
|
-
axis
|
|
280
|
+
axis,
|
|
277
281
|
stops: [{
|
|
278
282
|
offset: lowerBound,
|
|
279
283
|
color: fill,
|
|
@@ -291,7 +295,7 @@ export const createGradient = (axisBounds, baselineValue, fill, peakOpacity, bas
|
|
|
291
295
|
}
|
|
292
296
|
const peakValue = Math.abs(min - baselineValue) > Math.abs(max - baselineValue) ? min : max;
|
|
293
297
|
return {
|
|
294
|
-
axis
|
|
298
|
+
axis,
|
|
295
299
|
stops: [{
|
|
296
300
|
offset: peakValue,
|
|
297
301
|
color: fill,
|
package/esm/chart/utils/path.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { area as d3Area, curveBumpX, curveCatmullRom, curveLinear, curveLinearClosed, curveMonotoneX, curveNatural, curveStep, curveStepAfter, curveStepBefore, line as d3Line } from 'd3-shape';
|
|
2
|
-
import {
|
|
1
|
+
import { area as d3Area, curveBumpX, curveBumpY, curveCatmullRom, curveLinear, curveLinearClosed, curveMonotoneX, curveMonotoneY, curveNatural, curveStep, curveStepAfter, curveStepBefore, line as d3Line } from 'd3-shape';
|
|
2
|
+
import { getPointOnScale, projectPoints } from './point';
|
|
3
3
|
import { isCategoricalScale } from './scale';
|
|
4
4
|
/**
|
|
5
5
|
* Default enter transition for path-based components (Line, Area).
|
|
@@ -13,18 +13,23 @@ export const defaultPathEnterTransition = {
|
|
|
13
13
|
* Get the d3 curve function for a path.
|
|
14
14
|
* See https://d3js.org/d3-shape/curve
|
|
15
15
|
* @param curve - The curve type. Defaults to 'linear'.
|
|
16
|
+
* @param layout - The chart layout. Defaults to 'vertical'.
|
|
16
17
|
* @returns The d3 curve function.
|
|
17
18
|
*/
|
|
18
|
-
export const getPathCurveFunction = function (curve) {
|
|
19
|
+
export const getPathCurveFunction = function (curve, layout) {
|
|
19
20
|
if (curve === void 0) {
|
|
20
21
|
curve = 'linear';
|
|
21
22
|
}
|
|
23
|
+
if (layout === void 0) {
|
|
24
|
+
layout = 'vertical';
|
|
25
|
+
}
|
|
22
26
|
switch (curve) {
|
|
23
27
|
case 'catmullRom':
|
|
24
28
|
return curveCatmullRom;
|
|
25
29
|
case 'monotone':
|
|
26
|
-
//
|
|
27
|
-
|
|
30
|
+
// For vertical layout, X is the independent axis (category/index), so use MonotoneX.
|
|
31
|
+
// For horizontal layout, Y is the independent axis (category/index), so use MonotoneY.
|
|
32
|
+
return layout !== 'horizontal' ? curveMonotoneX : curveMonotoneY;
|
|
28
33
|
case 'natural':
|
|
29
34
|
return curveNatural;
|
|
30
35
|
case 'step':
|
|
@@ -34,8 +39,9 @@ export const getPathCurveFunction = function (curve) {
|
|
|
34
39
|
case 'stepAfter':
|
|
35
40
|
return curveStepAfter;
|
|
36
41
|
case 'bump':
|
|
37
|
-
//
|
|
38
|
-
|
|
42
|
+
// For vertical layout, X is the independent axis (category/index), so use BumpX.
|
|
43
|
+
// For horizontal layout, Y is the independent axis (category/index), so use BumpY.
|
|
44
|
+
return layout !== 'horizontal' ? curveBumpX : curveBumpY;
|
|
39
45
|
case 'linearClosed':
|
|
40
46
|
return curveLinearClosed;
|
|
41
47
|
case 'linear':
|
|
@@ -61,17 +67,21 @@ export const getLinePath = _ref => {
|
|
|
61
67
|
xScale,
|
|
62
68
|
yScale,
|
|
63
69
|
xData,
|
|
64
|
-
|
|
70
|
+
yData,
|
|
71
|
+
connectNulls = false,
|
|
72
|
+
layout = 'vertical'
|
|
65
73
|
} = _ref;
|
|
66
74
|
if (data.length === 0) {
|
|
67
75
|
return '';
|
|
68
76
|
}
|
|
69
|
-
const curveFunction = getPathCurveFunction(curve);
|
|
77
|
+
const curveFunction = getPathCurveFunction(curve, layout);
|
|
70
78
|
const dataPoints = projectPoints({
|
|
71
79
|
data,
|
|
72
80
|
xScale,
|
|
73
81
|
yScale,
|
|
74
|
-
xData
|
|
82
|
+
xData,
|
|
83
|
+
yData,
|
|
84
|
+
layout
|
|
75
85
|
});
|
|
76
86
|
|
|
77
87
|
// When connectNulls is true, filter out null values before rendering
|
|
@@ -110,14 +120,20 @@ export const getAreaPath = _ref2 => {
|
|
|
110
120
|
xScale,
|
|
111
121
|
yScale,
|
|
112
122
|
xData,
|
|
113
|
-
|
|
123
|
+
yData,
|
|
124
|
+
connectNulls = false,
|
|
125
|
+
layout = 'vertical'
|
|
114
126
|
} = _ref2;
|
|
115
127
|
if (data.length === 0) {
|
|
116
128
|
return '';
|
|
117
129
|
}
|
|
118
|
-
const curveFunction = getPathCurveFunction(curve);
|
|
119
|
-
const
|
|
120
|
-
|
|
130
|
+
const curveFunction = getPathCurveFunction(curve, layout);
|
|
131
|
+
const categoryAxisIsX = layout !== 'horizontal';
|
|
132
|
+
|
|
133
|
+
// Determine baseline from the value scale.
|
|
134
|
+
const valueScale = categoryAxisIsX ? yScale : xScale;
|
|
135
|
+
const domain = valueScale.domain();
|
|
136
|
+
const min = Math.min(...domain);
|
|
121
137
|
const normalizedData = data.map((item, index) => {
|
|
122
138
|
if (item === null) {
|
|
123
139
|
return null;
|
|
@@ -129,7 +145,7 @@ export const getAreaPath = _ref2 => {
|
|
|
129
145
|
return null;
|
|
130
146
|
}
|
|
131
147
|
if (typeof item === 'number') {
|
|
132
|
-
return [
|
|
148
|
+
return [min, item];
|
|
133
149
|
}
|
|
134
150
|
return null;
|
|
135
151
|
});
|
|
@@ -137,37 +153,28 @@ export const getAreaPath = _ref2 => {
|
|
|
137
153
|
if (range === null) {
|
|
138
154
|
return {
|
|
139
155
|
x: 0,
|
|
156
|
+
y: 0,
|
|
140
157
|
low: null,
|
|
141
158
|
high: null,
|
|
142
159
|
isValid: false
|
|
143
160
|
};
|
|
144
161
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
|
|
163
|
+
// Determine the position along the independent (index/category) axis.
|
|
164
|
+
let indexValue = index;
|
|
165
|
+
const indexScale = categoryAxisIsX ? xScale : yScale;
|
|
166
|
+
const indexData = categoryAxisIsX ? xData : yData;
|
|
167
|
+
if (!isCategoricalScale(indexScale) && indexData && indexData[index] !== undefined) {
|
|
168
|
+
indexValue = indexData[index];
|
|
148
169
|
}
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
xScale,
|
|
153
|
-
yScale
|
|
154
|
-
});
|
|
155
|
-
const lowPoint = projectPoint({
|
|
156
|
-
x: xValue,
|
|
157
|
-
y: range[0],
|
|
158
|
-
xScale,
|
|
159
|
-
yScale
|
|
160
|
-
});
|
|
161
|
-
const highPoint = projectPoint({
|
|
162
|
-
x: xValue,
|
|
163
|
-
y: range[1],
|
|
164
|
-
xScale,
|
|
165
|
-
yScale
|
|
166
|
-
});
|
|
170
|
+
const position = getPointOnScale(indexValue, indexScale);
|
|
171
|
+
const low = getPointOnScale(range[0], valueScale);
|
|
172
|
+
const high = getPointOnScale(range[1], valueScale);
|
|
167
173
|
return {
|
|
168
|
-
x:
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
x: categoryAxisIsX ? position : 0,
|
|
175
|
+
y: !categoryAxisIsX ? position : 0,
|
|
176
|
+
low,
|
|
177
|
+
high,
|
|
171
178
|
isValid: true
|
|
172
179
|
};
|
|
173
180
|
});
|
|
@@ -175,16 +182,25 @@ export const getAreaPath = _ref2 => {
|
|
|
175
182
|
// When connectNulls is true, filter out invalid points before rendering
|
|
176
183
|
// When false, use defined() to create gaps in the area
|
|
177
184
|
const filteredPoints = connectNulls ? dataPoints.filter(d => d.isValid) : dataPoints;
|
|
178
|
-
const areaGenerator = d3Area()
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
const areaGenerator = d3Area();
|
|
186
|
+
if (categoryAxisIsX) {
|
|
187
|
+
areaGenerator.x(d => d.x).y0(d => {
|
|
188
|
+
var _d$low;
|
|
189
|
+
return (_d$low = d.low) != null ? _d$low : 0;
|
|
190
|
+
}).y1(d => {
|
|
191
|
+
var _d$high;
|
|
192
|
+
return (_d$high = d.high) != null ? _d$high : 0;
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
areaGenerator.y(d => d.y).x0(d => {
|
|
196
|
+
var _d$low2;
|
|
197
|
+
return (_d$low2 = d.low) != null ? _d$low2 : 0;
|
|
198
|
+
}).x1(d => {
|
|
199
|
+
var _d$high2;
|
|
200
|
+
return (_d$high2 = d.high) != null ? _d$high2 : 0;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
areaGenerator.curve(curveFunction).defined(d => connectNulls || d.isValid && d.low != null && d.high != null);
|
|
188
204
|
const result = areaGenerator(filteredPoints);
|
|
189
205
|
return result != null ? result : '';
|
|
190
206
|
};
|
|
@@ -216,22 +232,35 @@ export const lineToPath = (x1, y1, x2, y2) => {
|
|
|
216
232
|
* const roundedPath = getBarPath(10, 20, 50, 100, 8, true, false);
|
|
217
233
|
* ```
|
|
218
234
|
*/
|
|
219
|
-
export const getBarPath = (x, y, width, height, radius, roundTop, roundBottom)
|
|
235
|
+
export const getBarPath = function (x, y, width, height, radius, roundTop, roundBottom, layout) {
|
|
236
|
+
if (layout === void 0) {
|
|
237
|
+
layout = 'vertical';
|
|
238
|
+
}
|
|
239
|
+
const barsGrowVertically = layout !== 'horizontal';
|
|
220
240
|
const roundBothSides = roundTop && roundBottom;
|
|
221
241
|
const r = Math.min(radius, width / 2, roundBothSides ? height / 2 : height);
|
|
222
|
-
|
|
223
|
-
|
|
242
|
+
|
|
243
|
+
// In vertical layout (bars grow up/down):
|
|
244
|
+
// - roundTop rounds the top face (min Y)
|
|
245
|
+
// - roundBottom rounds the bottom face (max Y)
|
|
246
|
+
// In horizontal layout (bars grow left/right):
|
|
247
|
+
// - roundTop rounds the right face (max X)
|
|
248
|
+
// - roundBottom rounds the left face (min X)
|
|
249
|
+
const rTL = barsGrowVertically ? roundTop ? r : 0 : roundBottom ? r : 0;
|
|
250
|
+
const rTR = barsGrowVertically ? roundTop ? r : 0 : roundTop ? r : 0;
|
|
251
|
+
const rBR = barsGrowVertically ? roundBottom ? r : 0 : roundTop ? r : 0;
|
|
252
|
+
const rBL = barsGrowVertically ? roundBottom ? r : 0 : roundBottom ? r : 0;
|
|
224
253
|
|
|
225
254
|
// Build path with selective rounding
|
|
226
|
-
let path = "M " + (x +
|
|
227
|
-
path += " L " + (x + width -
|
|
228
|
-
path += " A " +
|
|
229
|
-
path += " L " + (x + width) + " " + (y + height -
|
|
230
|
-
path += " A " +
|
|
231
|
-
path += " L " + (x +
|
|
232
|
-
path += " A " +
|
|
233
|
-
path += " L " + x + " " + (y +
|
|
234
|
-
path += " A " +
|
|
255
|
+
let path = "M " + (x + rTL) + " " + y;
|
|
256
|
+
path += " L " + (x + width - rTR) + " " + y;
|
|
257
|
+
path += " A " + rTR + " " + rTR + " 0 0 1 " + (x + width) + " " + (y + rTR);
|
|
258
|
+
path += " L " + (x + width) + " " + (y + height - rBR);
|
|
259
|
+
path += " A " + rBR + " " + rBR + " 0 0 1 " + (x + width - rBR) + " " + (y + height);
|
|
260
|
+
path += " L " + (x + rBL) + " " + (y + height);
|
|
261
|
+
path += " A " + rBL + " " + rBL + " 0 0 1 " + x + " " + (y + height - rBL);
|
|
262
|
+
path += " L " + x + " " + (y + rTL);
|
|
263
|
+
path += " A " + rTL + " " + rTL + " 0 0 1 " + (x + rTL) + " " + y;
|
|
235
264
|
path += ' Z';
|
|
236
265
|
return path;
|
|
237
266
|
};
|
package/esm/chart/utils/point.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyBandScale, applySerializableScale, isCategoricalScale, isLogScale
|
|
1
|
+
import { applyBandScale, applySerializableScale, isCategoricalScale, isLogScale } from './scale';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Position a label should be placed relative to the point
|
|
@@ -164,7 +164,8 @@ export const projectPoints = _ref3 => {
|
|
|
164
164
|
xScale,
|
|
165
165
|
yScale,
|
|
166
166
|
xData,
|
|
167
|
-
yData
|
|
167
|
+
yData,
|
|
168
|
+
layout = 'vertical'
|
|
168
169
|
} = _ref3;
|
|
169
170
|
if (data.length === 0) {
|
|
170
171
|
return [];
|
|
@@ -182,28 +183,37 @@ export const projectPoints = _ref3 => {
|
|
|
182
183
|
});
|
|
183
184
|
}
|
|
184
185
|
|
|
185
|
-
//
|
|
186
|
-
|
|
186
|
+
// Determine values/scales based on role (index vs value) and layout.
|
|
187
|
+
const categoryAxisIsX = layout !== 'horizontal';
|
|
188
|
+
const indexScale = categoryAxisIsX ? xScale : yScale;
|
|
189
|
+
const indexData = categoryAxisIsX ? xData : yData;
|
|
187
190
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const numericXData = xData;
|
|
196
|
-
xValue = (_numericXData$index = numericXData[index]) != null ? _numericXData$index : index;
|
|
191
|
+
// 1. Calculate position along the index axis (categorical or numeric domain).
|
|
192
|
+
let indexValue = index;
|
|
193
|
+
if (!isCategoricalScale(indexScale)) {
|
|
194
|
+
if (indexData && Array.isArray(indexData) && indexData.length > 0) {
|
|
195
|
+
if (typeof indexData[0] === 'number') {
|
|
196
|
+
var _indexData$index;
|
|
197
|
+
indexValue = (_indexData$index = indexData[index]) != null ? _indexData$index : index;
|
|
197
198
|
}
|
|
198
199
|
}
|
|
199
200
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
|
|
202
|
+
// 2. Calculate position along the value axis (measured magnitude).
|
|
203
|
+
const valueAsNumber = value;
|
|
204
|
+
|
|
205
|
+
// 3. Project final coordinates based on layout.
|
|
206
|
+
if (categoryAxisIsX) {
|
|
207
|
+
return projectPoint({
|
|
208
|
+
x: indexValue,
|
|
209
|
+
y: valueAsNumber,
|
|
210
|
+
xScale,
|
|
211
|
+
yScale
|
|
212
|
+
});
|
|
203
213
|
}
|
|
204
214
|
return projectPoint({
|
|
205
|
-
x:
|
|
206
|
-
y:
|
|
215
|
+
x: valueAsNumber,
|
|
216
|
+
y: indexValue,
|
|
207
217
|
xScale,
|
|
208
218
|
yScale
|
|
209
219
|
});
|
|
@@ -56,13 +56,18 @@ export const defaultAccessoryEnterTransition = {
|
|
|
56
56
|
delay: accessoryFadeTransitionDelay
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
// Avoid exact endpoint samples, which can intermittently produce non-interpolatable
|
|
60
|
+
// path pairs for SkPath.interpolate on complex morphs.
|
|
61
|
+
// See https://github.com/wcandillon/can-it-be-done-in-react-native/blob/db8d6ee7024e37e8f8d2cb237c0b953b5fc766fe/season5/src/Headspace/Play.tsx
|
|
62
|
+
const pathInterpolationEpsilon = 1e-3;
|
|
63
|
+
|
|
59
64
|
/**
|
|
60
65
|
* Resolves a transition value based on the animation state and a default.
|
|
61
66
|
* @note Passing in null will disable an animation.
|
|
62
67
|
* @note Passing in undefined will use the provided default.
|
|
63
68
|
*/
|
|
64
69
|
export const getTransition = (value, animate, defaultValue) => {
|
|
65
|
-
if (!animate || value === null) return
|
|
70
|
+
if (!animate || value === null) return null;
|
|
66
71
|
return value != null ? value : defaultValue;
|
|
67
72
|
};
|
|
68
73
|
|
|
@@ -106,6 +111,7 @@ export const useInterpolator = (factory, value, interpolator, input, output, opt
|
|
|
106
111
|
export const buildTransition = (targetValue, transition) => {
|
|
107
112
|
'worklet';
|
|
108
113
|
|
|
114
|
+
if (transition === null) return targetValue;
|
|
109
115
|
const delayMs = transition.delay;
|
|
110
116
|
let animation;
|
|
111
117
|
switch (transition.type) {
|
|
@@ -160,14 +166,14 @@ export const buildTransition = (targetValue, transition) => {
|
|
|
160
166
|
* });
|
|
161
167
|
*/
|
|
162
168
|
export const usePathTransition = _ref => {
|
|
163
|
-
var
|
|
169
|
+
var _Skia$Path$MakeFromSV;
|
|
164
170
|
let {
|
|
165
171
|
currentPath,
|
|
166
172
|
initialPath,
|
|
167
173
|
transitions,
|
|
168
174
|
transition = defaultTransition
|
|
169
175
|
} = _ref;
|
|
170
|
-
const updateTransition = (
|
|
176
|
+
const updateTransition = (transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition;
|
|
171
177
|
const enterTransition = transitions == null ? void 0 : transitions.enter;
|
|
172
178
|
const targetPathRef = useRef(initialPath != null ? initialPath : currentPath);
|
|
173
179
|
const isFirstAnimation = useRef(!!initialPath);
|
|
@@ -180,24 +186,36 @@ export const usePathTransition = _ref => {
|
|
|
180
186
|
const result = useSharedValue(initialSkiaPath);
|
|
181
187
|
useEffect(() => {
|
|
182
188
|
if (targetPathRef.current !== currentPath) {
|
|
183
|
-
var _Skia$Path$
|
|
189
|
+
var _Skia$Path$MakeFromSV3, _Skia$Path$MakeFromSV4, _Skia$Path$MakeFromSV5;
|
|
184
190
|
let fromPath = targetPathRef.current;
|
|
185
191
|
if (interpolatorRef.current) {
|
|
186
192
|
const p = Math.min(Math.max(progress.value, 0), 1);
|
|
187
193
|
fromPath = interpolatorRef.current(p);
|
|
188
194
|
}
|
|
189
195
|
targetPathRef.current = currentPath;
|
|
190
|
-
const pathInterpolator = interpolatePath(fromPath, currentPath);
|
|
191
|
-
interpolatorRef.current = pathInterpolator;
|
|
192
|
-
normalizedStartShared.value = (_Skia$Path$MakeFromSV2 = Skia.Path.MakeFromSVGString(pathInterpolator(0))) != null ? _Skia$Path$MakeFromSV2 : Skia.Path.Make();
|
|
193
|
-
normalizedEndShared.value = (_Skia$Path$MakeFromSV3 = Skia.Path.MakeFromSVGString(pathInterpolator(1))) != null ? _Skia$Path$MakeFromSV3 : Skia.Path.Make();
|
|
194
|
-
fallbackPathShared.value = (_Skia$Path$MakeFromSV4 = Skia.Path.MakeFromSVGString(currentPath)) != null ? _Skia$Path$MakeFromSV4 : Skia.Path.Make();
|
|
195
196
|
const activeTransition = isFirstAnimation.current && enterTransition !== undefined ? enterTransition : updateTransition;
|
|
196
197
|
isFirstAnimation.current = false;
|
|
198
|
+
if (activeTransition === null) {
|
|
199
|
+
var _Skia$Path$MakeFromSV2;
|
|
200
|
+
const targetPath = (_Skia$Path$MakeFromSV2 = Skia.Path.MakeFromSVGString(currentPath)) != null ? _Skia$Path$MakeFromSV2 : Skia.Path.Make();
|
|
201
|
+
interpolatorRef.current = null;
|
|
202
|
+
normalizedStartShared.value = targetPath;
|
|
203
|
+
normalizedEndShared.value = targetPath;
|
|
204
|
+
fallbackPathShared.value = targetPath;
|
|
205
|
+
progress.value = 1;
|
|
206
|
+
result.value = targetPath;
|
|
207
|
+
notifyChange(result);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const pathInterpolator = interpolatePath(fromPath, currentPath);
|
|
211
|
+
interpolatorRef.current = pathInterpolator;
|
|
212
|
+
normalizedStartShared.value = (_Skia$Path$MakeFromSV3 = Skia.Path.MakeFromSVGString(pathInterpolator(pathInterpolationEpsilon))) != null ? _Skia$Path$MakeFromSV3 : Skia.Path.Make();
|
|
213
|
+
normalizedEndShared.value = (_Skia$Path$MakeFromSV4 = Skia.Path.MakeFromSVGString(pathInterpolator(1 - pathInterpolationEpsilon))) != null ? _Skia$Path$MakeFromSV4 : Skia.Path.Make();
|
|
214
|
+
fallbackPathShared.value = (_Skia$Path$MakeFromSV5 = Skia.Path.MakeFromSVGString(currentPath)) != null ? _Skia$Path$MakeFromSV5 : Skia.Path.Make();
|
|
197
215
|
progress.value = 0;
|
|
198
216
|
progress.value = buildTransition(1, activeTransition);
|
|
199
217
|
}
|
|
200
|
-
}, [currentPath, updateTransition, enterTransition, progress, normalizedStartShared, normalizedEndShared, fallbackPathShared]);
|
|
218
|
+
}, [currentPath, updateTransition, enterTransition, progress, normalizedStartShared, normalizedEndShared, fallbackPathShared, result]);
|
|
201
219
|
useAnimatedReaction(() => ({
|
|
202
220
|
p: progress.value,
|
|
203
221
|
to: fallbackPathShared.value
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinbase/cds-mobile-visualization",
|
|
3
|
-
"version": "3.4.0-beta.
|
|
3
|
+
"version": "3.4.0-beta.23",
|
|
4
4
|
"description": "Coinbase Design System - Mobile Visualization Native",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"CHANGELOG"
|
|
37
37
|
],
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@coinbase/cds-common": "^8.
|
|
39
|
+
"@coinbase/cds-common": "^8.52.0",
|
|
40
40
|
"@coinbase/cds-lottie-files": "^3.3.4",
|
|
41
|
-
"@coinbase/cds-mobile": "^8.
|
|
41
|
+
"@coinbase/cds-mobile": "^8.52.0",
|
|
42
42
|
"@coinbase/cds-utils": "^2.3.5",
|
|
43
43
|
"@shopify/react-native-skia": "^1.12.4 || ^2.0.0",
|
|
44
44
|
"react": "^18.3.1",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"@babel/preset-env": "^7.28.0",
|
|
58
58
|
"@babel/preset-react": "^7.27.1",
|
|
59
59
|
"@babel/preset-typescript": "^7.27.1",
|
|
60
|
-
"@coinbase/cds-common": "^8.
|
|
60
|
+
"@coinbase/cds-common": "^8.52.0",
|
|
61
61
|
"@coinbase/cds-lottie-files": "^3.3.4",
|
|
62
|
-
"@coinbase/cds-mobile": "^8.
|
|
62
|
+
"@coinbase/cds-mobile": "^8.52.0",
|
|
63
63
|
"@coinbase/cds-utils": "^2.3.5",
|
|
64
64
|
"@shopify/react-native-skia": "1.12.4",
|
|
65
65
|
"@types/react": "^18.3.12",
|