@coinbase/cds-mobile-visualization 3.4.0-beta.9 → 3.4.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 +132 -0
- package/dts/chart/CartesianChart.d.ts +92 -7
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/ChartContextBridge.d.ts.map +1 -1
- package/dts/chart/ChartProvider.d.ts +3 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -1
- package/dts/chart/Path.d.ts +36 -13
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +20 -5
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +14 -11
- 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 +22 -42
- 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 +51 -51
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +56 -11
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts +2 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +45 -20
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +2 -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/index.d.ts +1 -0
- package/dts/chart/index.d.ts.map +1 -1
- package/dts/chart/legend/DefaultLegendEntry.d.ts +5 -0
- package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts +5 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
- package/dts/chart/legend/Legend.d.ts +168 -0
- package/dts/chart/legend/Legend.d.ts.map +1 -0
- package/dts/chart/legend/index.d.ts +4 -0
- package/dts/chart/legend/index.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +23 -19
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +26 -9
- 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 +26 -2
- package/dts/chart/point/Point.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +32 -2
- 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 +86 -17
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts +12 -0
- package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +10 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +16 -1
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +45 -10
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +190 -0
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +32 -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 +26 -0
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +24 -12
- package/dts/chart/utils/point.d.ts.map +1 -1
- package/dts/chart/utils/scale.d.ts +11 -0
- package/dts/chart/utils/scale.d.ts.map +1 -1
- package/dts/chart/utils/scrubber.d.ts +2 -1
- package/dts/chart/utils/scrubber.d.ts.map +1 -1
- package/dts/chart/utils/transition.d.ts +63 -22
- package/dts/chart/utils/transition.d.ts.map +1 -1
- package/dts/sparkline/Sparkline.d.ts +2 -1
- package/dts/sparkline/Sparkline.d.ts.map +1 -1
- package/dts/sparkline/SparklineArea.d.ts +2 -1
- package/dts/sparkline/SparklineArea.d.ts.map +1 -1
- package/dts/sparkline/SparklineGradient.d.ts +2 -1
- package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +2 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
- package/esm/chart/CartesianChart.js +176 -82
- package/esm/chart/ChartContextBridge.js +14 -3
- package/esm/chart/ChartProvider.js +2 -2
- package/esm/chart/Path.js +34 -29
- package/esm/chart/PeriodSelector.js +5 -1
- package/esm/chart/__stories__/CartesianChart.stories.js +16 -80
- package/esm/chart/__stories__/ChartAccessibility.stories.js +721 -0
- package/esm/chart/__stories__/ChartTransitions.stories.js +625 -0
- package/esm/chart/__stories__/PeriodSelector.stories.js +99 -1
- package/esm/chart/area/Area.js +21 -9
- package/esm/chart/area/AreaChart.js +18 -13
- package/esm/chart/area/DottedArea.js +28 -18
- package/esm/chart/area/GradientArea.js +14 -7
- package/esm/chart/area/SolidArea.js +6 -2
- package/esm/chart/area/__stories__/AreaChart.stories.js +47 -5
- package/esm/chart/axis/Axis.js +5 -41
- package/esm/chart/axis/XAxis.js +116 -47
- package/esm/chart/axis/YAxis.js +105 -26
- package/esm/chart/axis/__stories__/Axis.stories.js +324 -48
- package/esm/chart/bar/Bar.js +17 -15
- package/esm/chart/bar/BarChart.js +38 -33
- package/esm/chart/bar/BarPlot.js +40 -45
- package/esm/chart/bar/BarStack.js +92 -475
- package/esm/chart/bar/BarStackGroup.js +37 -27
- package/esm/chart/bar/DefaultBar.js +27 -18
- package/esm/chart/bar/DefaultBarStack.js +25 -9
- package/esm/chart/bar/__stories__/BarChart.stories.js +728 -54
- package/esm/chart/gradient/Gradient.js +2 -1
- package/esm/chart/index.js +1 -0
- package/esm/chart/legend/DefaultLegendEntry.js +42 -0
- package/esm/chart/legend/DefaultLegendShape.js +64 -0
- package/esm/chart/legend/Legend.js +59 -0
- package/esm/chart/legend/__stories__/Legend.stories.js +574 -0
- package/esm/chart/legend/index.js +3 -0
- package/esm/chart/line/DottedLine.js +6 -2
- package/esm/chart/line/Line.js +42 -38
- package/esm/chart/line/LineChart.js +36 -12
- package/esm/chart/line/SolidLine.js +6 -2
- package/esm/chart/line/__stories__/LineChart.stories.js +236 -590
- package/esm/chart/line/__stories__/ReferenceLine.stories.js +95 -1
- package/esm/chart/point/Point.js +35 -36
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +41 -38
- package/esm/chart/scrubber/DefaultScrubberLabel.js +26 -10
- package/esm/chart/scrubber/Scrubber.js +67 -35
- package/esm/chart/scrubber/ScrubberAccessibilityView.js +177 -0
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +30 -22
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +35 -8
- package/esm/chart/scrubber/ScrubberProvider.js +29 -24
- package/esm/chart/scrubber/__stories__/Scrubber.stories.js +946 -0
- package/esm/chart/utils/axis.js +88 -44
- package/esm/chart/utils/bar.js +820 -0
- package/esm/chart/utils/chart.js +34 -7
- package/esm/chart/utils/context.js +7 -0
- package/esm/chart/utils/gradient.js +8 -4
- package/esm/chart/utils/path.js +91 -61
- package/esm/chart/utils/point.js +92 -39
- package/esm/chart/utils/scale.js +13 -2
- package/esm/chart/utils/scrubber.js +12 -5
- package/esm/chart/utils/transition.js +108 -60
- package/esm/sparkline/Sparkline.js +2 -1
- package/esm/sparkline/SparklineArea.js +2 -1
- package/esm/sparkline/SparklineGradient.js +2 -1
- package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +2 -1
- package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +2 -0
- package/package.json +5 -6
- package/esm/chart/__stories__/Chart.stories.js +0 -77
package/esm/chart/axis/XAxis.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
const _excluded = ["position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "TickLabelComponent", "GridLineComponent", "LineComponent", "TickMarkLineComponent", "tickMarkLabelGap", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "tickMinStep", "tickMaxStep", "label", "labelGap", "height"];
|
|
1
|
+
const _excluded = ["axisId", "position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "TickLabelComponent", "GridLineComponent", "LineComponent", "TickMarkLineComponent", "tickMarkLabelGap", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "tickMinStep", "tickMaxStep", "label", "labelGap", "height", "bandGridLinePlacement", "bandTickMarkPlacement"];
|
|
2
2
|
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; }
|
|
3
3
|
import { memo, useCallback, useEffect, useId, useMemo } from 'react';
|
|
4
4
|
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
5
5
|
import { Group } from '@shopify/react-native-skia';
|
|
6
6
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
7
7
|
import { DottedLine } from '../line/DottedLine';
|
|
8
|
-
import { ReferenceLine } from '../line/ReferenceLine';
|
|
9
8
|
import { SolidLine } from '../line/SolidLine';
|
|
10
9
|
import { ChartText } from '../text/ChartText';
|
|
11
10
|
import { ChartTextGroup } from '../text/ChartTextGroup';
|
|
12
|
-
import { getAxisTicksData, isCategoricalScale, lineToPath } from '../utils';
|
|
11
|
+
import { getAxisTicksData, getPointOnScale, isCategoricalScale, lineToPath, toPointAnchor } from '../utils';
|
|
13
12
|
import { DefaultAxisTickLabel } from './DefaultAxisTickLabel';
|
|
14
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
14
|
const AXIS_HEIGHT = 32;
|
|
16
15
|
const LABEL_SIZE = 20;
|
|
17
16
|
export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
18
17
|
let {
|
|
18
|
+
axisId,
|
|
19
19
|
position = 'bottom',
|
|
20
20
|
showGrid,
|
|
21
21
|
requestedTickCount,
|
|
@@ -35,26 +35,26 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
|
35
35
|
tickMaxStep,
|
|
36
36
|
label,
|
|
37
37
|
labelGap = 4,
|
|
38
|
-
height = label ? AXIS_HEIGHT + LABEL_SIZE : AXIS_HEIGHT
|
|
38
|
+
height = label ? AXIS_HEIGHT + LABEL_SIZE : AXIS_HEIGHT,
|
|
39
|
+
bandGridLinePlacement = 'edges',
|
|
40
|
+
bandTickMarkPlacement = 'middle'
|
|
39
41
|
} = _ref,
|
|
40
42
|
props = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
41
43
|
const theme = useTheme();
|
|
42
44
|
const registrationId = useId();
|
|
43
45
|
const {
|
|
44
46
|
animate,
|
|
47
|
+
drawingArea,
|
|
48
|
+
layout,
|
|
45
49
|
getXScale,
|
|
46
50
|
getXAxis,
|
|
47
51
|
registerAxis,
|
|
48
52
|
unregisterAxis,
|
|
49
53
|
getAxisBounds
|
|
50
54
|
} = useCartesianChartContext();
|
|
51
|
-
const xScale = getXScale();
|
|
52
|
-
const xAxis = getXAxis();
|
|
55
|
+
const xScale = getXScale(axisId);
|
|
56
|
+
const xAxis = getXAxis(axisId);
|
|
53
57
|
const axisBounds = getAxisBounds(registrationId);
|
|
54
|
-
|
|
55
|
-
// Note: gridOpacity not currently used in Skia version
|
|
56
|
-
// const gridOpacity = useSharedValue(1);
|
|
57
|
-
|
|
58
58
|
useEffect(() => {
|
|
59
59
|
registerAxis(registrationId, position, height);
|
|
60
60
|
return () => unregisterAxis(registrationId);
|
|
@@ -64,15 +64,12 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
|
64
64
|
// If we have string labels and no custom formatter, use the labels
|
|
65
65
|
const axisData = xAxis == null ? void 0 : xAxis.data;
|
|
66
66
|
const hasStringLabels = axisData && Array.isArray(axisData) && typeof axisData[0] === 'string';
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// For band scales with string data, value is an index
|
|
70
|
-
if (hasStringLabels && typeof value === 'number' && axisData[value] !== undefined) {
|
|
71
|
-
finalValue = axisData[value];
|
|
67
|
+
if (hasStringLabels && !tickLabelFormatter && axisData[value] !== undefined) {
|
|
68
|
+
return axisData[value];
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
//
|
|
75
|
-
return (_tickLabelFormatter = tickLabelFormatter == null ? void 0 : tickLabelFormatter(
|
|
71
|
+
// Otherwise passes raw index to formatter
|
|
72
|
+
return (_tickLabelFormatter = tickLabelFormatter == null ? void 0 : tickLabelFormatter(value)) != null ? _tickLabelFormatter : value;
|
|
76
73
|
}, [xAxis == null ? void 0 : xAxis.data, tickLabelFormatter]);
|
|
77
74
|
const ticksData = useMemo(() => {
|
|
78
75
|
if (!xScale) return [];
|
|
@@ -91,27 +88,87 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
|
91
88
|
const domain = xScale.domain();
|
|
92
89
|
categories = domain.map(String);
|
|
93
90
|
}
|
|
94
|
-
let possibleTickValues;
|
|
95
|
-
|
|
96
|
-
// If we have discrete data, we can use the indices as possible tick values
|
|
97
|
-
if (axisData && Array.isArray(axisData) && (typeof axisData[0] === 'string' || typeof axisData[0] === 'number' && isCategoricalScale(xScale))) {
|
|
98
|
-
possibleTickValues = Array.from({
|
|
99
|
-
length: axisData.length
|
|
100
|
-
}, (_, i) => i);
|
|
101
|
-
}
|
|
102
91
|
return getAxisTicksData({
|
|
103
92
|
scaleFunction: xScale,
|
|
104
93
|
ticks,
|
|
105
|
-
requestedTickCount,
|
|
94
|
+
requestedTickCount: requestedTickCount != null ? requestedTickCount : layout === 'horizontal' ? 5 : undefined,
|
|
106
95
|
categories,
|
|
107
|
-
possibleTickValues
|
|
96
|
+
possibleTickValues: axisData && Array.isArray(axisData) && typeof axisData[0] === 'string' ? Array.from({
|
|
97
|
+
length: axisData.length
|
|
98
|
+
}, (_, i) => i) : undefined,
|
|
108
99
|
tickInterval: tickInterval,
|
|
109
100
|
options: {
|
|
110
101
|
minStep: tickMinStep,
|
|
111
102
|
maxStep: tickMaxStep
|
|
112
103
|
}
|
|
113
104
|
});
|
|
114
|
-
}, [ticks, xScale, requestedTickCount, tickInterval, tickMinStep, tickMaxStep, xAxis == null ? void 0 : xAxis.data]);
|
|
105
|
+
}, [ticks, xScale, requestedTickCount, tickInterval, tickMinStep, tickMaxStep, xAxis == null ? void 0 : xAxis.data, layout]);
|
|
106
|
+
const isBandScale = useMemo(() => {
|
|
107
|
+
if (!xScale) return false;
|
|
108
|
+
return isCategoricalScale(xScale);
|
|
109
|
+
}, [xScale]);
|
|
110
|
+
|
|
111
|
+
// Compute grid line positions (including bounds closing line for band scales)
|
|
112
|
+
const gridLinePositions = useMemo(() => {
|
|
113
|
+
if (!xScale) return [];
|
|
114
|
+
return ticksData.flatMap((tick, index) => {
|
|
115
|
+
if (!isBandScale) {
|
|
116
|
+
return [{
|
|
117
|
+
x: tick.position,
|
|
118
|
+
key: "grid-" + tick.tick + "-" + index
|
|
119
|
+
}];
|
|
120
|
+
}
|
|
121
|
+
const bandScale = xScale;
|
|
122
|
+
const isLastTick = index === ticksData.length - 1;
|
|
123
|
+
const isEdges = bandGridLinePlacement === 'edges';
|
|
124
|
+
const startX = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandGridLinePlacement));
|
|
125
|
+
const positions = [{
|
|
126
|
+
x: startX,
|
|
127
|
+
key: "grid-" + tick.tick + "-" + index
|
|
128
|
+
}];
|
|
129
|
+
|
|
130
|
+
// For edges on last tick, add the closing line at stepEnd
|
|
131
|
+
if (isLastTick && isEdges) {
|
|
132
|
+
const endX = getPointOnScale(tick.tick, bandScale, 'stepEnd');
|
|
133
|
+
positions.push({
|
|
134
|
+
x: endX,
|
|
135
|
+
key: "grid-" + tick.tick + "-" + index + "-end"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return positions;
|
|
139
|
+
});
|
|
140
|
+
}, [ticksData, xScale, isBandScale, bandGridLinePlacement]);
|
|
141
|
+
|
|
142
|
+
// Compute tick mark positions (including bounds closing tick for band scales)
|
|
143
|
+
const tickMarkPositions = useMemo(() => {
|
|
144
|
+
if (!xScale) return [];
|
|
145
|
+
return ticksData.flatMap((tick, index) => {
|
|
146
|
+
if (!isBandScale) {
|
|
147
|
+
return [{
|
|
148
|
+
x: tick.position,
|
|
149
|
+
key: "tick-mark-" + tick.tick + "-" + index
|
|
150
|
+
}];
|
|
151
|
+
}
|
|
152
|
+
const bandScale = xScale;
|
|
153
|
+
const isLastTick = index === ticksData.length - 1;
|
|
154
|
+
const isEdges = bandTickMarkPlacement === 'edges';
|
|
155
|
+
const startX = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandTickMarkPlacement));
|
|
156
|
+
const positions = [{
|
|
157
|
+
x: startX,
|
|
158
|
+
key: "tick-mark-" + tick.tick + "-" + index
|
|
159
|
+
}];
|
|
160
|
+
|
|
161
|
+
// For edges on last tick, add the closing tick mark at stepEnd
|
|
162
|
+
if (isLastTick && isEdges) {
|
|
163
|
+
const endX = getPointOnScale(tick.tick, bandScale, 'stepEnd');
|
|
164
|
+
positions.push({
|
|
165
|
+
x: endX,
|
|
166
|
+
key: "tick-mark-" + tick.tick + "-" + index + "-end"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return positions;
|
|
170
|
+
});
|
|
171
|
+
}, [ticksData, xScale, isBandScale, bandTickMarkPlacement]);
|
|
115
172
|
const chartTextData = useMemo(() => {
|
|
116
173
|
if (!axisBounds) return null;
|
|
117
174
|
return ticksData.map(tick => {
|
|
@@ -121,11 +178,7 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
|
121
178
|
// This ensures tick labels are centered in the axis area, not including label space
|
|
122
179
|
const availableSpace = AXIS_HEIGHT - tickOffset;
|
|
123
180
|
const labelOffset = availableSpace / 2;
|
|
124
|
-
|
|
125
|
-
// For bottom position: start at axisBounds.y
|
|
126
|
-
// For top position with label: start at axisBounds.y + LABEL_SIZE
|
|
127
|
-
const baseY = position === 'top' && label ? axisBounds.y + LABEL_SIZE : axisBounds.y;
|
|
128
|
-
const labelY = position === 'top' ? baseY + labelOffset - tickOffset : baseY + labelOffset + tickOffset;
|
|
181
|
+
const labelY = position === 'top' ? axisBounds.y + axisBounds.height - tickOffset - labelOffset : axisBounds.y + labelOffset + tickOffset;
|
|
129
182
|
return {
|
|
130
183
|
x: tick.position,
|
|
131
184
|
y: labelY,
|
|
@@ -137,20 +190,33 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
|
137
190
|
}
|
|
138
191
|
};
|
|
139
192
|
});
|
|
140
|
-
}, [axisBounds, ticksData, theme.color.fgMuted, tickMarkLabelGap, showTickMarks, tickMarkSize, position, formatTick
|
|
193
|
+
}, [axisBounds, ticksData, theme.color.fgMuted, tickMarkLabelGap, showTickMarks, tickMarkSize, position, formatTick]);
|
|
141
194
|
if (!xScale || !axisBounds) return;
|
|
142
195
|
const labelX = axisBounds.x + axisBounds.width / 2;
|
|
143
196
|
const labelY = position === 'bottom' ? axisBounds.y + axisBounds.height - LABEL_SIZE / 2 : axisBounds.y + LABEL_SIZE / 2;
|
|
197
|
+
|
|
198
|
+
// Pre-compute tick mark Y coordinates
|
|
199
|
+
const tickYTop = axisBounds.y;
|
|
200
|
+
const tickYBottom = axisBounds.y + axisBounds.height;
|
|
201
|
+
const tickYStart = position === 'bottom' ? tickYTop : tickYBottom;
|
|
202
|
+
const tickYEnd = position === 'bottom' ? tickYTop + tickMarkSize : tickYBottom - tickMarkSize;
|
|
203
|
+
|
|
204
|
+
// Note: Unlike web, mobile renders grid lines and tick marks immediately without fade animation.
|
|
205
|
+
// This is because Skia can measure text dimensions synchronously, so there's no need to hide
|
|
206
|
+
// elements while waiting for measurements (web uses async ResizeObserver).
|
|
144
207
|
return /*#__PURE__*/_jsxs(Group, {
|
|
145
208
|
children: [showGrid && /*#__PURE__*/_jsx(Group, {
|
|
146
|
-
children:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
return /*#__PURE__*/_jsx(
|
|
152
|
-
|
|
153
|
-
|
|
209
|
+
children: gridLinePositions.map(_ref2 => {
|
|
210
|
+
let {
|
|
211
|
+
x,
|
|
212
|
+
key
|
|
213
|
+
} = _ref2;
|
|
214
|
+
return /*#__PURE__*/_jsx(GridLineComponent, {
|
|
215
|
+
animate: false,
|
|
216
|
+
clipPath: null,
|
|
217
|
+
d: lineToPath(x, drawingArea.y, x, drawingArea.y + drawingArea.height),
|
|
218
|
+
stroke: theme.color.bgLine
|
|
219
|
+
}, key);
|
|
154
220
|
})
|
|
155
221
|
}), chartTextData && /*#__PURE__*/_jsx(ChartTextGroup, {
|
|
156
222
|
prioritizeEndLabels: true,
|
|
@@ -158,20 +224,23 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
|
|
|
158
224
|
labels: chartTextData,
|
|
159
225
|
minGap: minTickLabelGap
|
|
160
226
|
}), axisBounds && showTickMarks && /*#__PURE__*/_jsx(Group, {
|
|
161
|
-
children:
|
|
162
|
-
|
|
163
|
-
|
|
227
|
+
children: tickMarkPositions.map(_ref3 => {
|
|
228
|
+
let {
|
|
229
|
+
x,
|
|
230
|
+
key
|
|
231
|
+
} = _ref3;
|
|
164
232
|
return /*#__PURE__*/_jsx(TickMarkLineComponent, {
|
|
165
233
|
animate: false,
|
|
166
234
|
clipPath: null,
|
|
167
|
-
d: lineToPath(
|
|
235
|
+
d: lineToPath(x, tickYStart, x, tickYEnd),
|
|
168
236
|
stroke: theme.color.fg,
|
|
169
237
|
strokeCap: "square",
|
|
170
238
|
strokeWidth: 1
|
|
171
|
-
},
|
|
239
|
+
}, key);
|
|
172
240
|
})
|
|
173
241
|
}), showLine && /*#__PURE__*/_jsx(LineComponent, {
|
|
174
242
|
animate: false,
|
|
243
|
+
clipPath: null,
|
|
175
244
|
d: lineToPath(axisBounds.x, position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height, axisBounds.x + axisBounds.width, position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height),
|
|
176
245
|
stroke: theme.color.fg,
|
|
177
246
|
strokeCap: "square",
|
package/esm/chart/axis/YAxis.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
const _excluded = ["axisId", "position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "TickLabelComponent", "GridLineComponent", "LineComponent", "TickMarkLineComponent", "tickMarkLabelGap", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "label", "labelGap", "width"];
|
|
1
|
+
const _excluded = ["axisId", "position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "TickLabelComponent", "GridLineComponent", "LineComponent", "TickMarkLineComponent", "tickMarkLabelGap", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "label", "labelGap", "width", "bandGridLinePlacement", "bandTickMarkPlacement"];
|
|
2
2
|
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; }
|
|
3
3
|
import { memo, useCallback, useEffect, useId, useMemo } from 'react';
|
|
4
4
|
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
5
5
|
import { Group, vec } from '@shopify/react-native-skia';
|
|
6
6
|
import { useCartesianChartContext } from '../ChartProvider';
|
|
7
7
|
import { DottedLine } from '../line/DottedLine';
|
|
8
|
-
import { ReferenceLine } from '../line/ReferenceLine';
|
|
9
8
|
import { SolidLine } from '../line/SolidLine';
|
|
10
9
|
import { ChartText } from '../text/ChartText';
|
|
11
10
|
import { ChartTextGroup } from '../text/ChartTextGroup';
|
|
12
|
-
import { getAxisTicksData, isCategoricalScale, lineToPath } from '../utils';
|
|
11
|
+
import { getAxisTicksData, getPointOnScale, isCategoricalScale, lineToPath, toPointAnchor } from '../utils';
|
|
13
12
|
import { DefaultAxisTickLabel } from './DefaultAxisTickLabel';
|
|
14
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
14
|
const AXIS_WIDTH = 44;
|
|
@@ -19,7 +18,7 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
|
|
|
19
18
|
axisId,
|
|
20
19
|
position = 'right',
|
|
21
20
|
showGrid,
|
|
22
|
-
requestedTickCount
|
|
21
|
+
requestedTickCount,
|
|
23
22
|
ticks,
|
|
24
23
|
tickLabelFormatter,
|
|
25
24
|
TickLabelComponent = DefaultAxisTickLabel,
|
|
@@ -34,13 +33,17 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
|
|
|
34
33
|
tickInterval,
|
|
35
34
|
label,
|
|
36
35
|
labelGap = 4,
|
|
37
|
-
width = label ? AXIS_WIDTH + LABEL_SIZE : AXIS_WIDTH
|
|
36
|
+
width = label ? AXIS_WIDTH + LABEL_SIZE : AXIS_WIDTH,
|
|
37
|
+
bandGridLinePlacement = 'edges',
|
|
38
|
+
bandTickMarkPlacement = 'middle'
|
|
38
39
|
} = _ref,
|
|
39
40
|
props = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
40
41
|
const theme = useTheme();
|
|
41
42
|
const registrationId = useId();
|
|
42
43
|
const {
|
|
43
44
|
animate,
|
|
45
|
+
drawingArea,
|
|
46
|
+
layout,
|
|
44
47
|
getYScale,
|
|
45
48
|
getYAxis,
|
|
46
49
|
registerAxis,
|
|
@@ -50,10 +53,6 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
|
|
|
50
53
|
const yScale = getYScale(axisId);
|
|
51
54
|
const yAxis = getYAxis(axisId);
|
|
52
55
|
const axisBounds = getAxisBounds(registrationId);
|
|
53
|
-
|
|
54
|
-
// Note: gridOpacity not currently used in Skia version
|
|
55
|
-
// const gridOpacity = useSharedValue(1);
|
|
56
|
-
|
|
57
56
|
useEffect(() => {
|
|
58
57
|
registerAxis(registrationId, position, width);
|
|
59
58
|
return () => unregisterAxis(registrationId);
|
|
@@ -96,12 +95,78 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
|
|
|
96
95
|
return getAxisTicksData({
|
|
97
96
|
scaleFunction: yScale,
|
|
98
97
|
ticks,
|
|
99
|
-
requestedTickCount: tickInterval !== undefined ? undefined : requestedTickCount != null ? requestedTickCount : 5,
|
|
98
|
+
requestedTickCount: tickInterval !== undefined ? undefined : requestedTickCount != null ? requestedTickCount : layout === 'horizontal' ? undefined : 5,
|
|
100
99
|
categories,
|
|
101
100
|
possibleTickValues: axisData && Array.isArray(axisData) && typeof axisData[0] === 'number' ? axisData : undefined,
|
|
102
101
|
tickInterval: tickInterval
|
|
103
102
|
});
|
|
104
|
-
}, [ticks, yScale, requestedTickCount, tickInterval, yAxis == null ? void 0 : yAxis.data]);
|
|
103
|
+
}, [ticks, yScale, requestedTickCount, tickInterval, yAxis == null ? void 0 : yAxis.data, layout]);
|
|
104
|
+
const isBandScale = useMemo(() => {
|
|
105
|
+
if (!yScale) return false;
|
|
106
|
+
return isCategoricalScale(yScale);
|
|
107
|
+
}, [yScale]);
|
|
108
|
+
|
|
109
|
+
// Compute grid line positions (including bounds closing line for band scales)
|
|
110
|
+
const gridLinePositions = useMemo(() => {
|
|
111
|
+
if (!yScale) return [];
|
|
112
|
+
return ticksData.flatMap((tick, index) => {
|
|
113
|
+
if (!isBandScale) {
|
|
114
|
+
return [{
|
|
115
|
+
y: tick.position,
|
|
116
|
+
key: "grid-" + tick.tick + "-" + index
|
|
117
|
+
}];
|
|
118
|
+
}
|
|
119
|
+
const bandScale = yScale;
|
|
120
|
+
const isLastTick = index === ticksData.length - 1;
|
|
121
|
+
const isEdges = bandGridLinePlacement === 'edges';
|
|
122
|
+
const startY = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandGridLinePlacement));
|
|
123
|
+
const positions = [{
|
|
124
|
+
y: startY,
|
|
125
|
+
key: "grid-" + tick.tick + "-" + index
|
|
126
|
+
}];
|
|
127
|
+
|
|
128
|
+
// For edges on last tick, add the closing line at stepEnd
|
|
129
|
+
if (isLastTick && isEdges) {
|
|
130
|
+
const endY = getPointOnScale(tick.tick, bandScale, 'stepEnd');
|
|
131
|
+
positions.push({
|
|
132
|
+
y: endY,
|
|
133
|
+
key: "grid-" + tick.tick + "-" + index + "-end"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return positions;
|
|
137
|
+
});
|
|
138
|
+
}, [ticksData, yScale, isBandScale, bandGridLinePlacement]);
|
|
139
|
+
|
|
140
|
+
// Compute tick mark positions (including bounds closing tick for band scales)
|
|
141
|
+
const tickMarkPositions = useMemo(() => {
|
|
142
|
+
if (!yScale) return [];
|
|
143
|
+
return ticksData.flatMap((tick, index) => {
|
|
144
|
+
if (!isBandScale) {
|
|
145
|
+
return [{
|
|
146
|
+
y: tick.position,
|
|
147
|
+
key: "tick-mark-" + tick.tick + "-" + index
|
|
148
|
+
}];
|
|
149
|
+
}
|
|
150
|
+
const bandScale = yScale;
|
|
151
|
+
const isLastTick = index === ticksData.length - 1;
|
|
152
|
+
const isEdges = bandTickMarkPlacement === 'edges';
|
|
153
|
+
const startY = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandTickMarkPlacement));
|
|
154
|
+
const positions = [{
|
|
155
|
+
y: startY,
|
|
156
|
+
key: "tick-mark-" + tick.tick + "-" + index
|
|
157
|
+
}];
|
|
158
|
+
|
|
159
|
+
// For edges on last tick, add the closing tick mark at stepEnd
|
|
160
|
+
if (isLastTick && isEdges) {
|
|
161
|
+
const endY = getPointOnScale(tick.tick, bandScale, 'stepEnd');
|
|
162
|
+
positions.push({
|
|
163
|
+
y: endY,
|
|
164
|
+
key: "tick-mark-" + tick.tick + "-" + index + "-end"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return positions;
|
|
168
|
+
});
|
|
169
|
+
}, [ticksData, yScale, isBandScale, bandTickMarkPlacement]);
|
|
105
170
|
const chartTextData = useMemo(() => {
|
|
106
171
|
if (!axisBounds) return null;
|
|
107
172
|
return ticksData.map(tick => {
|
|
@@ -122,17 +187,29 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
|
|
|
122
187
|
if (!yScale || !axisBounds) return;
|
|
123
188
|
const labelX = position === 'left' ? axisBounds.x + LABEL_SIZE / 2 : axisBounds.x + axisBounds.width - LABEL_SIZE / 2;
|
|
124
189
|
const labelY = axisBounds.y + axisBounds.height / 2;
|
|
190
|
+
|
|
191
|
+
// Pre-compute tick mark X coordinates
|
|
192
|
+
const tickXLeft = axisBounds.x;
|
|
193
|
+
const tickXRight = axisBounds.x + axisBounds.width;
|
|
194
|
+
const tickXStart = position === 'left' ? tickXRight : tickXLeft;
|
|
195
|
+
const tickXEnd = position === 'left' ? tickXRight - tickMarkSize : tickXLeft + tickMarkSize;
|
|
196
|
+
|
|
197
|
+
// Note: Unlike web, mobile renders grid lines and tick marks immediately without fade animation.
|
|
198
|
+
// This is because Skia can measure text dimensions synchronously, so there's no need to hide
|
|
199
|
+
// elements while waiting for measurements (web uses async ResizeObserver).
|
|
125
200
|
return /*#__PURE__*/_jsxs(Group, {
|
|
126
201
|
children: [showGrid && /*#__PURE__*/_jsx(Group, {
|
|
127
|
-
children:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
202
|
+
children: gridLinePositions.map(_ref2 => {
|
|
203
|
+
let {
|
|
204
|
+
y,
|
|
205
|
+
key
|
|
206
|
+
} = _ref2;
|
|
207
|
+
return /*#__PURE__*/_jsx(GridLineComponent, {
|
|
208
|
+
animate: false,
|
|
209
|
+
clipPath: null,
|
|
210
|
+
d: lineToPath(drawingArea.x, y, drawingArea.x + drawingArea.width, y),
|
|
211
|
+
stroke: theme.color.bgLine
|
|
212
|
+
}, key);
|
|
136
213
|
})
|
|
137
214
|
}), chartTextData && /*#__PURE__*/_jsx(ChartTextGroup, {
|
|
138
215
|
prioritizeEndLabels: true,
|
|
@@ -140,21 +217,23 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
|
|
|
140
217
|
labels: chartTextData,
|
|
141
218
|
minGap: minTickLabelGap
|
|
142
219
|
}), axisBounds && showTickMarks && /*#__PURE__*/_jsx(Group, {
|
|
143
|
-
children:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
220
|
+
children: tickMarkPositions.map(_ref3 => {
|
|
221
|
+
let {
|
|
222
|
+
y,
|
|
223
|
+
key
|
|
224
|
+
} = _ref3;
|
|
147
225
|
return /*#__PURE__*/_jsx(TickMarkLineComponent, {
|
|
148
226
|
animate: false,
|
|
149
227
|
clipPath: null,
|
|
150
|
-
d: lineToPath(
|
|
228
|
+
d: lineToPath(tickXStart, y, tickXEnd, y),
|
|
151
229
|
stroke: theme.color.fg,
|
|
152
230
|
strokeCap: "square",
|
|
153
231
|
strokeWidth: 1
|
|
154
|
-
},
|
|
232
|
+
}, key);
|
|
155
233
|
})
|
|
156
234
|
}), showLine && /*#__PURE__*/_jsx(LineComponent, {
|
|
157
235
|
animate: false,
|
|
236
|
+
clipPath: null,
|
|
158
237
|
d: lineToPath(position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x, axisBounds.y, position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x, axisBounds.y + axisBounds.height),
|
|
159
238
|
stroke: theme.color.fg,
|
|
160
239
|
strokeCap: "square",
|