@coinbase/cds-mobile-visualization 3.6.2 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dts/chart/CartesianChart.d.ts +4 -8
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +3 -0
- package/dts/chart/area/Area.d.ts.map +1 -1
- 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/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/gradient/Gradient.d.ts +14 -3
- 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 +3 -0
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/SolidLine.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +18 -8
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +17 -7
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +9 -0
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/context.d.ts +3 -3
- package/dts/chart/utils/context.d.ts.map +1 -1
- package/dts/chart/utils/gradient.d.ts +14 -4
- package/dts/chart/utils/gradient.d.ts.map +1 -1
- package/esm/chart/CartesianChart.js +6 -4
- package/esm/chart/__stories__/ChartTransitions.stories.js +68 -0
- package/esm/chart/area/Area.js +0 -2
- package/esm/chart/area/AreaChart.js +15 -19
- package/esm/chart/area/DottedArea.js +6 -4
- package/esm/chart/area/GradientArea.js +6 -4
- package/esm/chart/area/SolidArea.js +3 -0
- package/esm/chart/area/__stories__/AreaChart.stories.js +189 -3
- package/esm/chart/bar/BarChart.js +14 -22
- package/esm/chart/bar/BarStack.js +15 -10
- package/esm/chart/bar/__stories__/BarChart.stories.js +84 -2
- package/esm/chart/gradient/Gradient.js +119 -26
- package/esm/chart/line/DottedLine.js +3 -0
- package/esm/chart/line/Line.js +1 -3
- package/esm/chart/line/LineChart.js +8 -4
- package/esm/chart/line/SolidLine.js +3 -0
- package/esm/chart/utils/axis.js +32 -4
- package/esm/chart/utils/bar.js +129 -76
- package/esm/chart/utils/chart.js +53 -21
- package/esm/chart/utils/gradient.js +15 -5
- package/package.json +1 -1
package/esm/chart/area/Area.js
CHANGED
|
@@ -13,7 +13,6 @@ export const Area = /*#__PURE__*/memo(_ref => {
|
|
|
13
13
|
AreaComponent: AreaComponentProp,
|
|
14
14
|
fill: fillProp,
|
|
15
15
|
fillOpacity = 1,
|
|
16
|
-
baseline,
|
|
17
16
|
connectNulls,
|
|
18
17
|
gradient: gradientProp,
|
|
19
18
|
transitions,
|
|
@@ -74,7 +73,6 @@ export const Area = /*#__PURE__*/memo(_ref => {
|
|
|
74
73
|
if (!xScale || !yScale || !sourceData || !area) return;
|
|
75
74
|
return /*#__PURE__*/_jsx(AreaComponent, {
|
|
76
75
|
animate: animate,
|
|
77
|
-
baseline: baseline,
|
|
78
76
|
d: area,
|
|
79
77
|
fill: fill,
|
|
80
78
|
fillOpacity: fillOpacity,
|
|
@@ -1,6 +1,6 @@
|
|
|
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", "id"],
|
|
3
|
-
_excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
|
|
2
|
+
_excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "baseline", "id"],
|
|
3
|
+
_excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "baseline", "id"],
|
|
4
4
|
_excluded4 = ["id", "data", "label", "color", "xAxisId", "yAxisId", "opacity", "LineComponent", "stackId"],
|
|
5
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); }
|
|
@@ -9,7 +9,7 @@ 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 { defaultStackId } from '../utils';
|
|
12
|
+
import { defaultStackId, withBaselineDomain } 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) => {
|
|
@@ -45,7 +45,8 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
|
|
|
45
45
|
gradient: s.gradient,
|
|
46
46
|
xAxisId: s.xAxisId,
|
|
47
47
|
yAxisId: s.yAxisId,
|
|
48
|
-
stackId: s.stackId
|
|
48
|
+
stackId: s.stackId,
|
|
49
|
+
legendShape: s.legendShape
|
|
49
50
|
}));
|
|
50
51
|
}, [series]);
|
|
51
52
|
const transformedSeries = useMemo(() => {
|
|
@@ -68,6 +69,7 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
|
|
|
68
69
|
domain: xDomain,
|
|
69
70
|
domainLimit: xDomainLimit,
|
|
70
71
|
range: xRange,
|
|
72
|
+
baseline: xBaseline,
|
|
71
73
|
id: xAxisId
|
|
72
74
|
} = _ref2,
|
|
73
75
|
xAxisVisualProps = _objectWithoutPropertiesLoose(_ref2, _excluded2);
|
|
@@ -79,35 +81,29 @@ export const AreaChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
|
|
|
79
81
|
domain: yDomain,
|
|
80
82
|
domainLimit: yDomainLimit,
|
|
81
83
|
range: yRange,
|
|
84
|
+
baseline: yBaseline,
|
|
82
85
|
id: yAxisId
|
|
83
86
|
} = _ref3,
|
|
84
87
|
yAxisVisualProps = _objectWithoutPropertiesLoose(_ref3, _excluded3);
|
|
88
|
+
const isHorizontalLayout = chartProps.layout === 'horizontal';
|
|
89
|
+
const valueAxisBaseline = isHorizontalLayout ? xBaseline : yBaseline;
|
|
85
90
|
const xAxisConfig = {
|
|
86
91
|
scaleType: xScaleType,
|
|
87
92
|
data: xData,
|
|
88
93
|
categoryPadding: xCategoryPadding,
|
|
89
|
-
domain: xDomain,
|
|
94
|
+
domain: isHorizontalLayout ? withBaselineDomain(xDomain, valueAxisBaseline) : xDomain,
|
|
90
95
|
domainLimit: xDomainLimit,
|
|
91
|
-
range: xRange
|
|
96
|
+
range: xRange,
|
|
97
|
+
baseline: xBaseline
|
|
92
98
|
};
|
|
93
|
-
const hasNegativeValues = useMemo(() => {
|
|
94
|
-
if (!series) return false;
|
|
95
|
-
return series.some(s => {
|
|
96
|
-
var _s$data;
|
|
97
|
-
return (_s$data = s.data) == null ? void 0 : _s$data.some(value => typeof value === 'number' && value < 0 || Array.isArray(value) && value.some(v => typeof v === 'number' && v < 0));
|
|
98
|
-
});
|
|
99
|
-
}, [series]);
|
|
100
|
-
|
|
101
|
-
// Set default min domain to 0 for area chart, but only if there are no negative values
|
|
102
99
|
const yAxisConfig = {
|
|
103
100
|
scaleType: yScaleType,
|
|
104
101
|
data: yData,
|
|
105
102
|
categoryPadding: yCategoryPadding,
|
|
106
|
-
domain:
|
|
107
|
-
min: 0
|
|
108
|
-
}, yDomain),
|
|
103
|
+
domain: !isHorizontalLayout ? withBaselineDomain(yDomain, valueAxisBaseline) : yDomain,
|
|
109
104
|
domainLimit: yDomainLimit,
|
|
110
|
-
range: yRange
|
|
105
|
+
range: yRange,
|
|
106
|
+
baseline: yBaseline
|
|
111
107
|
};
|
|
112
108
|
return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
|
|
113
109
|
ref: ref,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const _excluded = ["d", "fill", "patternSize", "dotSize", "peakOpacity", "baselineOpacity", "
|
|
1
|
+
const _excluded = ["d", "fill", "patternSize", "dotSize", "peakOpacity", "baselineOpacity", "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';
|
|
@@ -17,6 +17,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
17
17
|
* on the fill color and peak/baseline opacities.
|
|
18
18
|
*/
|
|
19
19
|
export const DottedArea = /*#__PURE__*/memo(_ref => {
|
|
20
|
+
var _transitions$update;
|
|
20
21
|
let {
|
|
21
22
|
d,
|
|
22
23
|
fill: fillProp,
|
|
@@ -24,7 +25,6 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
|
|
|
24
25
|
dotSize = 1,
|
|
25
26
|
peakOpacity = 1,
|
|
26
27
|
baselineOpacity = 0,
|
|
27
|
-
baseline,
|
|
28
28
|
xAxisId,
|
|
29
29
|
yAxisId,
|
|
30
30
|
gradient: gradientProp,
|
|
@@ -66,9 +66,9 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
|
|
|
66
66
|
const gradient = useMemo(() => {
|
|
67
67
|
if (gradientProp) return gradientProp;
|
|
68
68
|
if (!valueAxisConfig) return;
|
|
69
|
-
const baselineValue = getBaseline(valueAxisConfig.domain, baseline);
|
|
69
|
+
const baselineValue = getBaseline(valueAxisConfig.domain, valueAxisConfig.baseline);
|
|
70
70
|
return createGradient(valueAxisConfig.domain, baselineValue, fill, peakOpacity, baselineOpacity, gradientAxis);
|
|
71
|
-
}, [gradientProp, valueAxisConfig, fill,
|
|
71
|
+
}, [gradientProp, valueAxisConfig, fill, peakOpacity, baselineOpacity, gradientAxis]);
|
|
72
72
|
|
|
73
73
|
// Update transition is used for clip path, we skip update animation on Path itself
|
|
74
74
|
return /*#__PURE__*/_jsx(Group, {
|
|
@@ -81,7 +81,9 @@ export const DottedArea = /*#__PURE__*/memo(_ref => {
|
|
|
81
81
|
transitions: transitions
|
|
82
82
|
}, pathProps, {
|
|
83
83
|
children: gradient && /*#__PURE__*/_jsx(Gradient, {
|
|
84
|
+
animate: shouldAnimate,
|
|
84
85
|
gradient: gradient,
|
|
86
|
+
transition: (_transitions$update = transitions == null ? void 0 : transitions.update) != null ? _transitions$update : transition,
|
|
85
87
|
xAxisId: xAxisId,
|
|
86
88
|
yAxisId: yAxisId
|
|
87
89
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const _excluded = ["d", "fill", "fillOpacity", "gradient", "peakOpacity", "baselineOpacity", "
|
|
1
|
+
const _excluded = ["d", "fill", "fillOpacity", "gradient", "peakOpacity", "baselineOpacity", "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';
|
|
@@ -14,6 +14,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
14
14
|
* on the fill color and peak/baseline opacities.
|
|
15
15
|
*/
|
|
16
16
|
export const GradientArea = /*#__PURE__*/memo(_ref => {
|
|
17
|
+
var _transitions$update;
|
|
17
18
|
let {
|
|
18
19
|
d,
|
|
19
20
|
fill: fillProp,
|
|
@@ -21,7 +22,6 @@ export const GradientArea = /*#__PURE__*/memo(_ref => {
|
|
|
21
22
|
gradient: gradientProp,
|
|
22
23
|
peakOpacity = 0.3,
|
|
23
24
|
baselineOpacity = 0,
|
|
24
|
-
baseline,
|
|
25
25
|
xAxisId,
|
|
26
26
|
yAxisId,
|
|
27
27
|
animate,
|
|
@@ -41,9 +41,9 @@ export const GradientArea = /*#__PURE__*/memo(_ref => {
|
|
|
41
41
|
const gradient = useMemo(() => {
|
|
42
42
|
if (gradientProp) return gradientProp;
|
|
43
43
|
if (!valueAxisConfig) return;
|
|
44
|
-
const baselineValue = getBaseline(valueAxisConfig.domain, baseline);
|
|
44
|
+
const baselineValue = getBaseline(valueAxisConfig.domain, valueAxisConfig.baseline);
|
|
45
45
|
return createGradient(valueAxisConfig.domain, baselineValue, fill, peakOpacity, baselineOpacity, gradientAxis);
|
|
46
|
-
}, [gradientProp, valueAxisConfig, fill,
|
|
46
|
+
}, [gradientProp, valueAxisConfig, fill, peakOpacity, baselineOpacity, gradientAxis]);
|
|
47
47
|
return /*#__PURE__*/_jsx(Path, _extends({
|
|
48
48
|
animate: animate,
|
|
49
49
|
d: d,
|
|
@@ -53,7 +53,9 @@ export const GradientArea = /*#__PURE__*/memo(_ref => {
|
|
|
53
53
|
transitions: transitions
|
|
54
54
|
}, pathProps, {
|
|
55
55
|
children: gradient && /*#__PURE__*/_jsx(Gradient, {
|
|
56
|
+
animate: animate,
|
|
56
57
|
gradient: gradient,
|
|
58
|
+
transition: (_transitions$update = transitions == null ? void 0 : transitions.update) != null ? _transitions$update : transition,
|
|
57
59
|
xAxisId: xAxisId,
|
|
58
60
|
yAxisId: yAxisId
|
|
59
61
|
})
|
|
@@ -12,6 +12,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
12
12
|
* Otherwise, renders with solid fill.
|
|
13
13
|
*/
|
|
14
14
|
export const SolidArea = /*#__PURE__*/memo(_ref => {
|
|
15
|
+
var _transitions$update;
|
|
15
16
|
let {
|
|
16
17
|
d,
|
|
17
18
|
fill,
|
|
@@ -34,7 +35,9 @@ export const SolidArea = /*#__PURE__*/memo(_ref => {
|
|
|
34
35
|
transitions: transitions
|
|
35
36
|
}, pathProps, {
|
|
36
37
|
children: gradient && /*#__PURE__*/_jsx(Gradient, {
|
|
38
|
+
animate: animate,
|
|
37
39
|
gradient: gradient,
|
|
40
|
+
transition: (_transitions$update = transitions == null ? void 0 : transitions.update) != null ? _transitions$update : transition,
|
|
38
41
|
xAxisId: xAxisId,
|
|
39
42
|
yAxisId: yAxisId
|
|
40
43
|
})
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
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); }
|
|
2
|
+
import { memo, useCallback } from 'react';
|
|
3
|
+
import { candles as btcCandles } from '@coinbase/cds-common/internal/data/candles';
|
|
2
4
|
import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
|
|
3
5
|
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
4
|
-
import {
|
|
6
|
+
import { VStack } from '@coinbase/cds-mobile/layout';
|
|
7
|
+
import { DefaultReferenceLineLabel, DottedLine, ReferenceLine } from '../../line';
|
|
5
8
|
import { Scrubber } from '../../scrubber/Scrubber';
|
|
6
9
|
import { AreaChart } from '..';
|
|
7
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
11
|
const basicData = [24, 13, 98, 39, 48, 38, 43];
|
|
12
|
+
const baselineThresholdData = [40, 28, 21, 5, 48, 5, 28, 2, 29, 48, 18, 30, 29, 8].map(value => value + 50);
|
|
9
13
|
const BasicExample = () => {
|
|
10
14
|
const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + basicData[index], []);
|
|
11
15
|
return /*#__PURE__*/_jsx(AreaChart, {
|
|
@@ -49,12 +53,164 @@ const StackedExample = () => {
|
|
|
49
53
|
data: potentialRewardsData,
|
|
50
54
|
color: theme.color.fgPositive,
|
|
51
55
|
type: 'dotted',
|
|
52
|
-
LineComponent: DottedLine
|
|
56
|
+
LineComponent: props => /*#__PURE__*/_jsx(DottedLine, _extends({}, props, {
|
|
57
|
+
dashIntervals: [6, 6]
|
|
58
|
+
}))
|
|
53
59
|
}],
|
|
54
60
|
type: "dotted",
|
|
55
61
|
children: /*#__PURE__*/_jsx(Scrubber, {})
|
|
56
62
|
});
|
|
57
63
|
};
|
|
64
|
+
const CustomBaselineExample = () => {
|
|
65
|
+
const theme = useTheme();
|
|
66
|
+
const candles = [...btcCandles].reverse().slice(0, 180);
|
|
67
|
+
const prices = candles.map(candle => parseFloat(candle.close));
|
|
68
|
+
const dates = candles.map(candle => new Date(parseInt(candle.start, 10) * 1000));
|
|
69
|
+
const startingPrice = prices[0];
|
|
70
|
+
const formatPrice = useCallback(price => {
|
|
71
|
+
return "$" + price.toLocaleString('en-US', {
|
|
72
|
+
minimumFractionDigits: 2,
|
|
73
|
+
maximumFractionDigits: 2
|
|
74
|
+
});
|
|
75
|
+
}, []);
|
|
76
|
+
const formatPriceInThousands = useCallback(price => {
|
|
77
|
+
return "$" + (price / 1000).toLocaleString('en-US', {
|
|
78
|
+
minimumFractionDigits: 0,
|
|
79
|
+
maximumFractionDigits: 0
|
|
80
|
+
}) + "k";
|
|
81
|
+
}, []);
|
|
82
|
+
const formatDate = useCallback(date => {
|
|
83
|
+
return date.toLocaleDateString('en-US', {
|
|
84
|
+
month: 'short',
|
|
85
|
+
day: 'numeric',
|
|
86
|
+
year: 'numeric'
|
|
87
|
+
});
|
|
88
|
+
}, []);
|
|
89
|
+
const formatLabel = useCallback(dataIndex => formatPrice(prices[dataIndex]) + " " + formatDate(dates[dataIndex]), [dates, formatDate, formatPrice, prices]);
|
|
90
|
+
const PriceLabel = /*#__PURE__*/memo(props => /*#__PURE__*/_jsx(DefaultReferenceLineLabel, _extends({}, props, {
|
|
91
|
+
background: theme.color.bgSecondary,
|
|
92
|
+
borderRadius: 12.5,
|
|
93
|
+
color: theme.color.fg,
|
|
94
|
+
dx: 12,
|
|
95
|
+
font: "label1",
|
|
96
|
+
horizontalAlignment: "left",
|
|
97
|
+
inset: {
|
|
98
|
+
top: 4,
|
|
99
|
+
bottom: 4,
|
|
100
|
+
left: 8,
|
|
101
|
+
right: 8
|
|
102
|
+
}
|
|
103
|
+
})));
|
|
104
|
+
const chartAccessibilityLabel = "Bitcoin area chart with custom baseline. Current price: " + formatPrice(prices[prices.length - 1]) + ". Swipe to navigate.";
|
|
105
|
+
const getScrubberAccessibilityLabel = useCallback(index => formatPrice(prices[index]) + " " + formatDate(dates[index]), [dates, formatDate, formatPrice, prices]);
|
|
106
|
+
return /*#__PURE__*/_jsxs(AreaChart, {
|
|
107
|
+
enableScrubbing: true,
|
|
108
|
+
showLines: true,
|
|
109
|
+
showYAxis: true,
|
|
110
|
+
accessibilityLabel: chartAccessibilityLabel,
|
|
111
|
+
fillOpacity: 0.5,
|
|
112
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
113
|
+
height: 300,
|
|
114
|
+
series: [{
|
|
115
|
+
id: 'prices',
|
|
116
|
+
data: prices,
|
|
117
|
+
gradient: {
|
|
118
|
+
stops: [{
|
|
119
|
+
offset: startingPrice,
|
|
120
|
+
color: theme.color.fgNegative
|
|
121
|
+
}, {
|
|
122
|
+
offset: startingPrice,
|
|
123
|
+
color: theme.color.fgPositive
|
|
124
|
+
}]
|
|
125
|
+
}
|
|
126
|
+
}],
|
|
127
|
+
yAxis: {
|
|
128
|
+
baseline: startingPrice,
|
|
129
|
+
showGrid: true,
|
|
130
|
+
tickLabelFormatter: formatPriceInThousands,
|
|
131
|
+
domain: {
|
|
132
|
+
min: 70000,
|
|
133
|
+
max: 120000
|
|
134
|
+
},
|
|
135
|
+
ticks: [80000, 100000, 120000]
|
|
136
|
+
},
|
|
137
|
+
children: [/*#__PURE__*/_jsx(Scrubber, {
|
|
138
|
+
labelElevated: true,
|
|
139
|
+
label: formatLabel
|
|
140
|
+
}), /*#__PURE__*/_jsx(ReferenceLine, {
|
|
141
|
+
LabelComponent: PriceLabel,
|
|
142
|
+
LineComponent: props => /*#__PURE__*/_jsx(DottedLine, _extends({}, props, {
|
|
143
|
+
dashIntervals: [0, 16],
|
|
144
|
+
strokeWidth: 3
|
|
145
|
+
})),
|
|
146
|
+
dataY: startingPrice,
|
|
147
|
+
label: formatPrice(startingPrice),
|
|
148
|
+
stroke: theme.color.fg
|
|
149
|
+
})]
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
const AxisBaselineThresholdExample = () => {
|
|
153
|
+
const theme = useTheme();
|
|
154
|
+
return /*#__PURE__*/_jsxs(VStack, {
|
|
155
|
+
gap: 2,
|
|
156
|
+
children: [/*#__PURE__*/_jsx(AreaChart, {
|
|
157
|
+
enableScrubbing: true,
|
|
158
|
+
showLines: true,
|
|
159
|
+
showYAxis: true,
|
|
160
|
+
accessibilityLabel: "Area chart with threshold baseline at 30.",
|
|
161
|
+
getScrubberAccessibilityLabel: index => "Point " + (index + 1) + ": " + baselineThresholdData[index],
|
|
162
|
+
height: 220,
|
|
163
|
+
inset: 0,
|
|
164
|
+
series: [{
|
|
165
|
+
id: 'axis-baseline-threshold-vertical',
|
|
166
|
+
data: baselineThresholdData,
|
|
167
|
+
gradient: {
|
|
168
|
+
stops: [{
|
|
169
|
+
offset: 30,
|
|
170
|
+
color: theme.color.fgNegative
|
|
171
|
+
}, {
|
|
172
|
+
offset: 30,
|
|
173
|
+
color: theme.color.fgPositive
|
|
174
|
+
}]
|
|
175
|
+
}
|
|
176
|
+
}],
|
|
177
|
+
type: "dotted",
|
|
178
|
+
yAxis: {
|
|
179
|
+
showGrid: true,
|
|
180
|
+
baseline: 30
|
|
181
|
+
},
|
|
182
|
+
children: /*#__PURE__*/_jsx(Scrubber, {})
|
|
183
|
+
}), /*#__PURE__*/_jsx(AreaChart, {
|
|
184
|
+
enableScrubbing: true,
|
|
185
|
+
showLines: true,
|
|
186
|
+
showXAxis: true,
|
|
187
|
+
accessibilityLabel: "Horizontal area chart with threshold baseline at 30.",
|
|
188
|
+
getScrubberAccessibilityLabel: index => "Point " + (index + 1) + ": " + baselineThresholdData[index],
|
|
189
|
+
height: 220,
|
|
190
|
+
inset: 0,
|
|
191
|
+
layout: "horizontal",
|
|
192
|
+
series: [{
|
|
193
|
+
id: 'axis-baseline-threshold-horizontal',
|
|
194
|
+
data: baselineThresholdData,
|
|
195
|
+
gradient: {
|
|
196
|
+
stops: [{
|
|
197
|
+
offset: 30,
|
|
198
|
+
color: theme.color.fgNegative
|
|
199
|
+
}, {
|
|
200
|
+
offset: 30,
|
|
201
|
+
color: theme.color.fgPositive
|
|
202
|
+
}]
|
|
203
|
+
}
|
|
204
|
+
}],
|
|
205
|
+
type: "dotted",
|
|
206
|
+
xAxis: {
|
|
207
|
+
showGrid: true,
|
|
208
|
+
baseline: 30
|
|
209
|
+
},
|
|
210
|
+
children: /*#__PURE__*/_jsx(Scrubber, {})
|
|
211
|
+
})]
|
|
212
|
+
});
|
|
213
|
+
};
|
|
58
214
|
const AreaChartStories = () => {
|
|
59
215
|
return /*#__PURE__*/_jsxs(ExampleScreen, {
|
|
60
216
|
children: [/*#__PURE__*/_jsx(Example, {
|
|
@@ -82,6 +238,36 @@ const AreaChartStories = () => {
|
|
|
82
238
|
},
|
|
83
239
|
children: /*#__PURE__*/_jsx(Scrubber, {})
|
|
84
240
|
})
|
|
241
|
+
}), /*#__PURE__*/_jsx(Example, {
|
|
242
|
+
title: "Axis Baseline",
|
|
243
|
+
children: /*#__PURE__*/_jsx(AreaChart, {
|
|
244
|
+
enableScrubbing: true,
|
|
245
|
+
showLines: true,
|
|
246
|
+
showYAxis: true,
|
|
247
|
+
accessibilityLabel: "Area chart with custom axis baseline at 100.",
|
|
248
|
+
getScrubberAccessibilityLabel: index => "Point " + (index + 1) + ": " + [112, 97, 121, 103, 129, 118, 94][index],
|
|
249
|
+
height: 220,
|
|
250
|
+
series: [{
|
|
251
|
+
id: 'netFlow',
|
|
252
|
+
data: [112, 97, 121, 103, 129, 118, 94]
|
|
253
|
+
}],
|
|
254
|
+
yAxis: {
|
|
255
|
+
baseline: 100,
|
|
256
|
+
domain: {
|
|
257
|
+
min: 80,
|
|
258
|
+
max: 140
|
|
259
|
+
},
|
|
260
|
+
showGrid: true,
|
|
261
|
+
tickLabelFormatter: value => "" + value
|
|
262
|
+
},
|
|
263
|
+
children: /*#__PURE__*/_jsx(Scrubber, {})
|
|
264
|
+
})
|
|
265
|
+
}), /*#__PURE__*/_jsx(Example, {
|
|
266
|
+
title: "Axis Baseline Threshold",
|
|
267
|
+
children: /*#__PURE__*/_jsx(AxisBaselineThresholdExample, {})
|
|
268
|
+
}), /*#__PURE__*/_jsx(Example, {
|
|
269
|
+
title: "Custom Baseline",
|
|
270
|
+
children: /*#__PURE__*/_jsx(CustomBaselineExample, {})
|
|
85
271
|
}), /*#__PURE__*/_jsx(Example, {
|
|
86
272
|
title: "Styles",
|
|
87
273
|
children: /*#__PURE__*/_jsx(AreaChart, {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const _excluded = ["series", "stacked", "showXAxis", "showYAxis", "xAxis", "yAxis", "inset", "children", "barPadding", "BarComponent", "fillOpacity", "stroke", "strokeWidth", "borderRadius", "roundBaseline", "BarStackComponent", "stackGap", "barMinSize", "stackMinSize", "transitions", "transition"],
|
|
2
|
-
_excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
|
|
3
|
-
_excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"];
|
|
2
|
+
_excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "baseline", "id"],
|
|
3
|
+
_excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "baseline", "id"];
|
|
4
4
|
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); }
|
|
5
5
|
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; }
|
|
6
6
|
import { forwardRef, memo, useMemo } from 'react';
|
|
7
7
|
import { XAxis, YAxis } from '../axis';
|
|
8
8
|
import { CartesianChart } from '../CartesianChart';
|
|
9
|
-
import { defaultStackId } from '../utils';
|
|
9
|
+
import { defaultStackId, withBaselineDomain } from '../utils';
|
|
10
10
|
import { BarPlot } from './BarPlot';
|
|
11
11
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
12
|
export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
|
|
@@ -57,6 +57,7 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
|
|
|
57
57
|
domain: xDomain,
|
|
58
58
|
domainLimit: xDomainLimit,
|
|
59
59
|
range: xRange,
|
|
60
|
+
baseline: xBaseline,
|
|
60
61
|
id: xAxisId
|
|
61
62
|
} = _ref2,
|
|
62
63
|
xAxisVisualProps = _objectWithoutPropertiesLoose(_ref2, _excluded2);
|
|
@@ -68,38 +69,29 @@ export const BarChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
|
|
|
68
69
|
domain: yDomain,
|
|
69
70
|
domainLimit: yDomainLimit,
|
|
70
71
|
range: yRange,
|
|
72
|
+
baseline: yBaseline,
|
|
71
73
|
id: yAxisId
|
|
72
74
|
} = _ref3,
|
|
73
75
|
yAxisVisualProps = _objectWithoutPropertiesLoose(_ref3, _excluded3);
|
|
74
|
-
const
|
|
75
|
-
if (!series) return false;
|
|
76
|
-
return series.some(s => {
|
|
77
|
-
var _s$data;
|
|
78
|
-
return (_s$data = s.data) == null ? void 0 : _s$data.some(value => typeof value === 'number' && value < 0 || Array.isArray(value) && value.some(v => typeof v === 'number' && v < 0));
|
|
79
|
-
});
|
|
80
|
-
}, [series]);
|
|
76
|
+
const valueAxisBaseline = isHorizontalLayout ? xBaseline : yBaseline;
|
|
81
77
|
const xAxisConfig = useMemo(() => ({
|
|
82
78
|
scaleType: xScaleType != null ? xScaleType : defaultXScaleType,
|
|
83
79
|
data: xData,
|
|
84
80
|
categoryPadding: xCategoryPadding,
|
|
85
|
-
domain: isHorizontalLayout
|
|
86
|
-
min: 0
|
|
87
|
-
}, xDomain) : xDomain,
|
|
81
|
+
domain: isHorizontalLayout ? withBaselineDomain(xDomain, valueAxisBaseline) : xDomain,
|
|
88
82
|
domainLimit: xDomainLimit,
|
|
89
|
-
range: xRange
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// Set default min domain to 0 for bar chart, but only if there are no negative values.
|
|
83
|
+
range: xRange,
|
|
84
|
+
baseline: xBaseline
|
|
85
|
+
}), [xScaleType, defaultXScaleType, xData, xCategoryPadding, isHorizontalLayout, xDomain, xDomainLimit, xRange, xBaseline, valueAxisBaseline]);
|
|
93
86
|
const yAxisConfig = useMemo(() => ({
|
|
94
87
|
scaleType: yScaleType != null ? yScaleType : defaultYScaleType,
|
|
95
88
|
data: yData,
|
|
96
89
|
categoryPadding: yCategoryPadding,
|
|
97
|
-
domain: !isHorizontalLayout
|
|
98
|
-
min: 0
|
|
99
|
-
}, yDomain) : yDomain,
|
|
90
|
+
domain: !isHorizontalLayout ? withBaselineDomain(yDomain, valueAxisBaseline) : yDomain,
|
|
100
91
|
domainLimit: yDomainLimit,
|
|
101
|
-
range: yRange
|
|
102
|
-
|
|
92
|
+
range: yRange,
|
|
93
|
+
baseline: yBaseline
|
|
94
|
+
}), [yScaleType, defaultYScaleType, yData, yCategoryPadding, isHorizontalLayout, yDomain, yDomainLimit, yRange, yBaseline, valueAxisBaseline]);
|
|
103
95
|
return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
|
|
104
96
|
ref: ref,
|
|
105
97
|
inset: inset,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { memo, useMemo } from 'react';
|
|
2
2
|
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
3
3
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
4
|
-
import { EPSILON, getBars,
|
|
4
|
+
import { EPSILON, getBars, getBaselinePx, getStackOrigin } from '../utils/bar';
|
|
5
5
|
import { getGradientStops } from '../utils/gradient';
|
|
6
6
|
import { convertToSerializableScale } from '../utils/scale';
|
|
7
7
|
import { Bar } from './Bar';
|
|
@@ -48,7 +48,11 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
48
48
|
} = useCartesianChartContext();
|
|
49
49
|
const xAxis = getXAxis(xAxisId);
|
|
50
50
|
const yAxis = getYAxis(yAxisId);
|
|
51
|
-
const baseline = useMemo(() =>
|
|
51
|
+
const baseline = useMemo(() => {
|
|
52
|
+
var _ref2;
|
|
53
|
+
return (_ref2 = layout === 'vertical' ? yAxis : xAxis) == null ? void 0 : _ref2.baseline;
|
|
54
|
+
}, [layout, yAxis, xAxis]);
|
|
55
|
+
const baselinePx = useMemo(() => getBaselinePx(valueScale, rect, layout, baseline), [rect, valueScale, layout, baseline]);
|
|
52
56
|
const seriesGradients = useMemo(() => {
|
|
53
57
|
return series.map(s => {
|
|
54
58
|
if (!s.gradient) return;
|
|
@@ -87,6 +91,7 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
87
91
|
roundBaseline,
|
|
88
92
|
layout,
|
|
89
93
|
baseline,
|
|
94
|
+
baselinePx,
|
|
90
95
|
stackGap,
|
|
91
96
|
barMinSize,
|
|
92
97
|
stackMinSize,
|
|
@@ -96,12 +101,12 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
96
101
|
defaultStroke,
|
|
97
102
|
defaultStrokeWidth,
|
|
98
103
|
defaultBarComponent
|
|
99
|
-
}), [series, seriesData, indexPos, thickness,
|
|
104
|
+
}), [series, seriesData, categoryIndex, categoryValue, indexPos, thickness, valueScale, seriesGradients, roundBaseline, layout, baseline, baselinePx, stackGap, barMinSize, stackMinSize, theme.color.fgPrimary, borderRadius, defaultFillOpacity, defaultStroke, defaultStrokeWidth, defaultBarComponent]);
|
|
100
105
|
const stackRect = useMemo(() => {
|
|
101
106
|
if (bars.length === 0) {
|
|
102
107
|
return {
|
|
103
|
-
x: layout === 'vertical' ? indexPos :
|
|
104
|
-
y: layout === 'vertical' ?
|
|
108
|
+
x: layout === 'vertical' ? indexPos : baselinePx,
|
|
109
|
+
y: layout === 'vertical' ? baselinePx : indexPos,
|
|
105
110
|
width: layout === 'vertical' ? thickness : 0,
|
|
106
111
|
height: layout === 'vertical' ? 0 : thickness
|
|
107
112
|
};
|
|
@@ -116,14 +121,14 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
116
121
|
width: maxX - minX,
|
|
117
122
|
height: maxY - minY
|
|
118
123
|
};
|
|
119
|
-
}, [bars,
|
|
124
|
+
}, [bars, baselinePx, indexPos, layout, thickness]);
|
|
120
125
|
const stackOrigin = useMemo(() => {
|
|
121
126
|
var _getStackOrigin;
|
|
122
127
|
return (_getStackOrigin = getStackOrigin(bars.map(b => b.origin), bars.map(b => {
|
|
123
128
|
var _b$minSize;
|
|
124
129
|
return (_b$minSize = b.minSize) != null ? _b$minSize : 0;
|
|
125
|
-
}))) != null ? _getStackOrigin :
|
|
126
|
-
}, [bars,
|
|
130
|
+
}))) != null ? _getStackOrigin : baselinePx;
|
|
131
|
+
}, [bars, baselinePx]);
|
|
127
132
|
const barElements = bars.map((bar, index) => /*#__PURE__*/_jsx(Bar, {
|
|
128
133
|
BarComponent: bar.BarComponent,
|
|
129
134
|
borderRadius: bar.borderRadius,
|
|
@@ -147,8 +152,8 @@ export const BarStack = /*#__PURE__*/memo(_ref => {
|
|
|
147
152
|
}, bar.seriesId + "-" + categoryIndex + "-" + index));
|
|
148
153
|
const edge = layout === 'vertical' ? stackRect.y : stackRect.x;
|
|
149
154
|
const size = layout === 'vertical' ? stackRect.height : stackRect.width;
|
|
150
|
-
const stackRoundLower = roundBaseline || Math.abs(edge -
|
|
151
|
-
const stackRoundHigher = roundBaseline || Math.abs(edge + size -
|
|
155
|
+
const stackRoundLower = roundBaseline || Math.abs(edge - baselinePx) >= EPSILON;
|
|
156
|
+
const stackRoundHigher = roundBaseline || Math.abs(edge + size - baselinePx) >= EPSILON;
|
|
152
157
|
const stackRoundTop = layout === 'vertical' ? stackRoundLower : stackRoundHigher;
|
|
153
158
|
const stackRoundBottom = layout === 'vertical' ? stackRoundHigher : stackRoundLower;
|
|
154
159
|
return /*#__PURE__*/_jsx(BarStackComponent, {
|