@ledgerhq/lumen-ui-rnative-visualization 0.1.16 → 0.1.18
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/dist/module/lib/Components/Axis/XAxis/XAxis.js +2 -2
- package/dist/module/lib/Components/Axis/XAxis/XAxis.js.map +1 -1
- package/dist/module/lib/Components/Axis/YAxis/YAxis.js +2 -2
- package/dist/module/lib/Components/Axis/YAxis/YAxis.js.map +1 -1
- package/dist/module/lib/Components/CartesianChart/CartesianChart.js +29 -22
- package/dist/module/lib/Components/CartesianChart/CartesianChart.js.map +1 -1
- package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.js +61 -0
- package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.js.map +1 -0
- package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/index.js +4 -0
- package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/index.js.map +1 -0
- package/dist/module/lib/Components/CartesianChart/RevealClip/RevealClipDefs.js +3 -4
- package/dist/module/lib/Components/CartesianChart/RevealClip/RevealClipDefs.js.map +1 -1
- package/dist/module/lib/Components/CartesianChart/hooks/useDataFingerprint.js +13 -0
- package/dist/module/lib/Components/CartesianChart/hooks/useDataFingerprint.js.map +1 -0
- package/dist/module/lib/Components/CartesianChart/{RevealClip/utils.js → hooks/useRevealClipAnimation.js} +1 -6
- package/dist/module/lib/Components/CartesianChart/hooks/useRevealClipAnimation.js.map +1 -0
- package/dist/module/lib/Components/CartesianChart/hooks/useShimmerAnimation.js +37 -0
- package/dist/module/lib/Components/CartesianChart/hooks/useShimmerAnimation.js.map +1 -0
- package/dist/module/lib/Components/Line/Line.js +13 -8
- package/dist/module/lib/Components/Line/Line.js.map +1 -1
- package/dist/module/lib/Components/Line/constants.js +5 -0
- package/dist/module/lib/Components/Line/constants.js.map +1 -0
- package/dist/module/lib/Components/Line/types.js +2 -0
- package/dist/module/lib/Components/Line/utils.js +24 -7
- package/dist/module/lib/Components/Line/utils.js.map +1 -1
- package/dist/module/lib/Components/Line/utils.test.js +27 -1
- package/dist/module/lib/Components/Line/utils.test.js.map +1 -1
- package/dist/module/lib/Components/LineChart/LineChart.js +116 -27
- package/dist/module/lib/Components/LineChart/LineChart.js.map +1 -1
- package/dist/module/lib/Components/LineChart/LineChart.test.js +78 -0
- package/dist/module/lib/Components/LineChart/LineChart.test.js.map +1 -1
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.js +72 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.js.map +1 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.js +47 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.js.map +1 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/index.js +4 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/index.js.map +1 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/types.js +4 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/types.js.map +1 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.js +22 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.js.map +1 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.test.js +21 -0
- package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.test.js.map +1 -0
- package/dist/module/lib/Components/LineChart/utils.js +83 -0
- package/dist/module/lib/Components/LineChart/utils.js.map +1 -0
- package/dist/module/lib/Components/LineChart/utils.test.js +174 -0
- package/dist/module/lib/Components/LineChart/utils.test.js.map +1 -0
- package/dist/module/lib/Components/ReferenceLine/ReferenceLine.js +4 -4
- package/dist/module/lib/Components/ReferenceLine/ReferenceLine.js.map +1 -1
- package/dist/module/lib/Components/ReferenceLine/constants.js +2 -2
- package/dist/module/lib/Components/ReferenceLine/constants.js.map +1 -1
- package/dist/module/lib/Components/ReferenceLine/utils.js +2 -1
- package/dist/module/lib/Components/ReferenceLine/utils.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js +2 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/Scrubber.js +2 -2
- package/dist/module/lib/Components/Scrubber/Scrubber.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/ScrubberProvider.js +2 -1
- package/dist/module/lib/Components/Scrubber/ScrubberProvider.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/utils.js +3 -2
- package/dist/module/lib/Components/Scrubber/utils.js.map +1 -1
- package/dist/module/lib/utils/numbers.js +16 -0
- package/dist/module/lib/utils/numbers.js.map +1 -0
- package/dist/module/lib/utils/ticks/ticks.js +0 -16
- package/dist/module/lib/utils/ticks/ticks.js.map +1 -1
- package/dist/typescript/src/lib/Components/Axis/XAxis/XAxis.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Axis/YAxis/YAxis.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/CartesianChart.d.ts +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/CartesianChart.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.d.ts +18 -0
- package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/index.d.ts +2 -0
- package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/RevealClipDefs.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/types.d.ts +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/hooks/useDataFingerprint.d.ts +9 -0
- package/dist/typescript/src/lib/Components/CartesianChart/hooks/useDataFingerprint.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/CartesianChart/{RevealClip/utils.d.ts → hooks/useRevealClipAnimation.d.ts} +2 -5
- package/dist/typescript/src/lib/Components/CartesianChart/hooks/useRevealClipAnimation.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.d.ts +13 -0
- package/dist/typescript/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts +12 -0
- package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Line/Line.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Line/Line.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Line/constants.d.ts +3 -0
- package/dist/typescript/src/lib/Components/Line/constants.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Line/index.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Line/index.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Line/types.d.ts +8 -0
- package/dist/typescript/src/lib/Components/Line/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Line/utils.d.ts +5 -4
- package/dist/typescript/src/lib/Components/Line/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/LineChart/LineChart.d.ts +1 -1
- package/dist/typescript/src/lib/Components/LineChart/LineChart.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.d.ts +9 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/types.d.ts +3 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/utils.d.ts +14 -0
- package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/utils.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/LineChart/types.d.ts +29 -1
- package/dist/typescript/src/lib/Components/LineChart/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/LineChart/utils.d.ts +43 -0
- package/dist/typescript/src/lib/Components/LineChart/utils.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/ReferenceLine/ReferenceLine.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/ReferenceLine/constants.d.ts +2 -2
- package/dist/typescript/src/lib/Components/ReferenceLine/constants.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/ReferenceLine/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/Scrubber.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/utils/index.d.ts +1 -1
- package/dist/typescript/src/lib/utils/index.d.ts.map +1 -1
- package/dist/typescript/src/lib/utils/numbers.d.ts +13 -0
- package/dist/typescript/src/lib/utils/numbers.d.ts.map +1 -0
- package/dist/typescript/src/lib/utils/ticks/ticks.d.ts +1 -11
- package/dist/typescript/src/lib/utils/ticks/ticks.d.ts.map +1 -1
- package/dist/typescript/src/lib/utils/types.d.ts +20 -2
- package/dist/typescript/src/lib/utils/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/lib/Components/Axis/XAxis/XAxis.tsx +13 -18
- package/src/lib/Components/Axis/YAxis/YAxis.tsx +13 -18
- package/src/lib/Components/CartesianChart/CartesianChart.tsx +29 -23
- package/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.tsx +68 -0
- package/src/lib/Components/CartesianChart/ChartEmptyLabel/index.ts +1 -0
- package/src/lib/Components/CartesianChart/RevealClip/RevealClipDefs.tsx +3 -2
- package/src/lib/Components/CartesianChart/RevealClip/types.ts +1 -1
- package/src/lib/Components/CartesianChart/hooks/useDataFingerprint.ts +16 -0
- package/src/lib/Components/CartesianChart/{RevealClip/utils.ts → hooks/useRevealClipAnimation.ts} +1 -9
- package/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.ts +52 -0
- package/src/lib/Components/CartesianChart/types.ts +12 -0
- package/src/lib/Components/Line/Line.tsx +13 -10
- package/src/lib/Components/Line/constants.ts +2 -0
- package/src/lib/Components/Line/index.ts +1 -1
- package/src/lib/Components/Line/types.ts +10 -0
- package/src/lib/Components/Line/utils.test.ts +41 -1
- package/src/lib/Components/Line/utils.ts +42 -6
- package/src/lib/Components/LineChart/LineChart.test.tsx +64 -0
- package/src/lib/Components/LineChart/LineChart.tsx +139 -38
- package/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.tsx +39 -0
- package/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.tsx +72 -0
- package/src/lib/Components/LineChart/LineChartEmptyState/index.ts +2 -0
- package/src/lib/Components/LineChart/LineChartEmptyState/types.ts +3 -0
- package/src/lib/Components/LineChart/LineChartEmptyState/utils.test.ts +22 -0
- package/src/lib/Components/LineChart/LineChartEmptyState/utils.ts +24 -0
- package/src/lib/Components/LineChart/types.ts +35 -1
- package/src/lib/Components/LineChart/utils.test.ts +196 -0
- package/src/lib/Components/LineChart/utils.ts +107 -0
- package/src/lib/Components/ReferenceLine/ReferenceLine.tsx +8 -4
- package/src/lib/Components/ReferenceLine/constants.ts +2 -2
- package/src/lib/Components/ReferenceLine/utils.ts +2 -1
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.ts +2 -1
- package/src/lib/Components/Scrubber/Scrubber.tsx +13 -2
- package/src/lib/Components/Scrubber/ScrubberProvider.tsx +2 -1
- package/src/lib/Components/Scrubber/utils.ts +3 -5
- package/src/lib/utils/index.ts +1 -0
- package/src/lib/utils/numbers.ts +15 -0
- package/src/lib/utils/ticks/ticks.ts +1 -23
- package/src/lib/utils/types.ts +28 -2
- package/dist/module/lib/Components/CartesianChart/RevealClip/utils.js.map +0 -1
- package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/utils.d.ts.map +0 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
|
|
3
|
+
import type { Series } from '../../utils/types';
|
|
4
|
+
import { DEFAULT_AXIS_HEIGHT } from '../Axis/XAxis';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
canRenderLine,
|
|
8
|
+
computeAxisPadding,
|
|
9
|
+
getChartDisplayState,
|
|
10
|
+
} from './utils';
|
|
11
|
+
|
|
12
|
+
const makeSeries = (data: (number | null)[]): Series => ({
|
|
13
|
+
id: 'a',
|
|
14
|
+
stroke: '#000',
|
|
15
|
+
data,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('canRenderLine', () => {
|
|
19
|
+
it('returns false for undefined or empty series', () => {
|
|
20
|
+
expect(canRenderLine(undefined)).toBe(false);
|
|
21
|
+
expect(canRenderLine([])).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('returns false when no series has at least two finite points', () => {
|
|
25
|
+
expect(canRenderLine([makeSeries([1])])).toBe(false);
|
|
26
|
+
expect(canRenderLine([makeSeries([1, null])])).toBe(false);
|
|
27
|
+
expect(canRenderLine([makeSeries([null, null])])).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns true once a series has two finite points', () => {
|
|
31
|
+
expect(canRenderLine([makeSeries([1, 2])])).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('ignores null gaps when counting drawable points', () => {
|
|
35
|
+
expect(canRenderLine([makeSeries([1, null, 3])])).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('does not count NaN, Infinity, or holes as drawable points', () => {
|
|
39
|
+
expect(canRenderLine([makeSeries([NaN, NaN])])).toBe(false);
|
|
40
|
+
expect(canRenderLine([makeSeries([Infinity, -Infinity])])).toBe(false);
|
|
41
|
+
expect(canRenderLine([makeSeries([NaN, 1])])).toBe(false);
|
|
42
|
+
expect(
|
|
43
|
+
canRenderLine([makeSeries([1, undefined as unknown as number, 2])]),
|
|
44
|
+
).toBe(true);
|
|
45
|
+
expect(
|
|
46
|
+
canRenderLine([makeSeries([1, undefined as unknown as number])]),
|
|
47
|
+
).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns true when any series is drawable', () => {
|
|
51
|
+
expect(canRenderLine([makeSeries([1]), makeSeries([1, 2, 3])])).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('treats a missing data array as no points', () => {
|
|
55
|
+
expect(canRenderLine([{ id: 'a', stroke: '#000' }])).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('caps counted points to the x-axis domain length (like toScaledPoints)', () => {
|
|
59
|
+
expect(canRenderLine([makeSeries([1, 2, 3])], ['Jan'])).toBe(false);
|
|
60
|
+
expect(canRenderLine([makeSeries([1, 2, 3])], ['Jan', 'Feb'])).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('does not reduce drawable points when xData is longer than the series', () => {
|
|
64
|
+
expect(canRenderLine([makeSeries([1, 2])], ['a', 'b', 'c', 'd'])).toBe(
|
|
65
|
+
true,
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('counts only finite points within the capped range', () => {
|
|
70
|
+
expect(canRenderLine([makeSeries([null, 2, 3])], ['Jan', 'Feb'])).toBe(
|
|
71
|
+
false,
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('computeAxisPadding', () => {
|
|
77
|
+
const base = {
|
|
78
|
+
xAxisPosition: 'bottom' as const,
|
|
79
|
+
yAxisPosition: 'start' as const,
|
|
80
|
+
yAxisWidth: 40,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
it('returns undefined when no axis is shown', () => {
|
|
84
|
+
expect(
|
|
85
|
+
computeAxisPadding({ ...base, showXAxis: false, showYAxis: false }),
|
|
86
|
+
).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('reserves height on the side where the x-axis sits', () => {
|
|
90
|
+
expect(
|
|
91
|
+
computeAxisPadding({
|
|
92
|
+
...base,
|
|
93
|
+
showXAxis: true,
|
|
94
|
+
showYAxis: false,
|
|
95
|
+
xAxisPosition: 'bottom',
|
|
96
|
+
}),
|
|
97
|
+
).toEqual({ top: 0, bottom: DEFAULT_AXIS_HEIGHT, left: 0, right: 0 });
|
|
98
|
+
|
|
99
|
+
expect(
|
|
100
|
+
computeAxisPadding({
|
|
101
|
+
...base,
|
|
102
|
+
showXAxis: true,
|
|
103
|
+
showYAxis: false,
|
|
104
|
+
xAxisPosition: 'top',
|
|
105
|
+
}),
|
|
106
|
+
).toEqual({ top: DEFAULT_AXIS_HEIGHT, bottom: 0, left: 0, right: 0 });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('reserves the y-axis width on the side where it sits', () => {
|
|
110
|
+
expect(
|
|
111
|
+
computeAxisPadding({
|
|
112
|
+
...base,
|
|
113
|
+
showXAxis: false,
|
|
114
|
+
showYAxis: true,
|
|
115
|
+
yAxisPosition: 'start',
|
|
116
|
+
yAxisWidth: 56,
|
|
117
|
+
}),
|
|
118
|
+
).toEqual({ top: 0, bottom: 0, left: 56, right: 0 });
|
|
119
|
+
|
|
120
|
+
expect(
|
|
121
|
+
computeAxisPadding({
|
|
122
|
+
...base,
|
|
123
|
+
showXAxis: false,
|
|
124
|
+
showYAxis: true,
|
|
125
|
+
yAxisPosition: 'end',
|
|
126
|
+
yAxisWidth: 56,
|
|
127
|
+
}),
|
|
128
|
+
).toEqual({ top: 0, bottom: 0, left: 0, right: 56 });
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('combines padding when both axes are shown', () => {
|
|
132
|
+
expect(
|
|
133
|
+
computeAxisPadding({
|
|
134
|
+
showXAxis: true,
|
|
135
|
+
showYAxis: true,
|
|
136
|
+
xAxisPosition: 'bottom',
|
|
137
|
+
yAxisPosition: 'start',
|
|
138
|
+
yAxisWidth: 40,
|
|
139
|
+
}),
|
|
140
|
+
).toEqual({ top: 0, bottom: DEFAULT_AXIS_HEIGHT, left: 40, right: 0 });
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('getChartDisplayState', () => {
|
|
145
|
+
it('is initial-loading when loading with no data', () => {
|
|
146
|
+
expect(
|
|
147
|
+
getChartDisplayState({
|
|
148
|
+
loading: true,
|
|
149
|
+
hasData: false,
|
|
150
|
+
emptyLabel: 'No data',
|
|
151
|
+
}),
|
|
152
|
+
).toEqual({
|
|
153
|
+
status: 'initial-loading',
|
|
154
|
+
ariaLabel: 'Loading chart',
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('is empty when not loading with no data', () => {
|
|
159
|
+
expect(
|
|
160
|
+
getChartDisplayState({
|
|
161
|
+
loading: false,
|
|
162
|
+
hasData: false,
|
|
163
|
+
emptyLabel: 'Nothing here',
|
|
164
|
+
}),
|
|
165
|
+
).toEqual({
|
|
166
|
+
status: 'empty',
|
|
167
|
+
ariaLabel: 'Nothing here',
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('is transition-loading when loading with data', () => {
|
|
172
|
+
expect(
|
|
173
|
+
getChartDisplayState({
|
|
174
|
+
loading: true,
|
|
175
|
+
hasData: true,
|
|
176
|
+
emptyLabel: 'No data',
|
|
177
|
+
}),
|
|
178
|
+
).toEqual({
|
|
179
|
+
status: 'transition-loading',
|
|
180
|
+
ariaLabel: 'Loading chart',
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('is ready with no aria label when data is present and not loading', () => {
|
|
185
|
+
expect(
|
|
186
|
+
getChartDisplayState({
|
|
187
|
+
loading: false,
|
|
188
|
+
hasData: true,
|
|
189
|
+
emptyLabel: 'No data',
|
|
190
|
+
}),
|
|
191
|
+
).toEqual({
|
|
192
|
+
status: 'ready',
|
|
193
|
+
ariaLabel: undefined,
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isFiniteNumber } from '../../utils/numbers';
|
|
2
|
+
import type { ChartInset, Series } from '../../utils/types';
|
|
3
|
+
import { DEFAULT_AXIS_HEIGHT } from '../Axis/XAxis';
|
|
4
|
+
import type { XAxisProps } from '../Axis/XAxis';
|
|
5
|
+
import { DEFAULT_AXIS_WIDTH } from '../Axis/YAxis';
|
|
6
|
+
import type { YAxisProps } from '../Axis/YAxis';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Minimum number of finite points a series needs to be drawable as a line.
|
|
10
|
+
*/
|
|
11
|
+
const MIN_DRAWABLE_POINTS = 2;
|
|
12
|
+
const LOADING_ARIA_LABEL = 'Loading chart';
|
|
13
|
+
|
|
14
|
+
type ComputeAxisPaddingParams = {
|
|
15
|
+
showXAxis: boolean;
|
|
16
|
+
showYAxis: boolean;
|
|
17
|
+
xAxisPosition: XAxisProps['position'];
|
|
18
|
+
yAxisPosition: YAxisProps['position'];
|
|
19
|
+
yAxisWidth: YAxisProps['width'];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type ChartDisplayStateParams = {
|
|
23
|
+
loading: boolean;
|
|
24
|
+
hasData: boolean;
|
|
25
|
+
emptyLabel: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type ChartStatus = 'initial-loading' | 'empty' | 'transition-loading' | 'ready';
|
|
29
|
+
|
|
30
|
+
type ChartDisplayState = {
|
|
31
|
+
status: ChartStatus;
|
|
32
|
+
ariaLabel: string | undefined;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Reserves space on the relevant sides of the drawing area for visible axes.
|
|
37
|
+
* Returns `undefined` when no axis is shown so the chart keeps its full area.
|
|
38
|
+
*/
|
|
39
|
+
export const computeAxisPadding = ({
|
|
40
|
+
showXAxis,
|
|
41
|
+
showYAxis,
|
|
42
|
+
xAxisPosition,
|
|
43
|
+
yAxisPosition,
|
|
44
|
+
yAxisWidth,
|
|
45
|
+
}: ComputeAxisPaddingParams): Partial<ChartInset> | undefined => {
|
|
46
|
+
if (!showXAxis && !showYAxis) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const resolvedYAxisWidth = yAxisWidth ?? DEFAULT_AXIS_WIDTH;
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
top: showXAxis && xAxisPosition === 'top' ? DEFAULT_AXIS_HEIGHT : 0,
|
|
54
|
+
bottom: showXAxis && xAxisPosition === 'bottom' ? DEFAULT_AXIS_HEIGHT : 0,
|
|
55
|
+
left: showYAxis && yAxisPosition === 'start' ? resolvedYAxisWidth : 0,
|
|
56
|
+
right: showYAxis && yAxisPosition === 'end' ? resolvedYAxisWidth : 0,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Derives the chart's {@link ChartStatus} from its loading flag and whether it
|
|
62
|
+
* has drawable data, along with the matching accessibility label.
|
|
63
|
+
*/
|
|
64
|
+
export const getChartDisplayState = ({
|
|
65
|
+
loading,
|
|
66
|
+
hasData,
|
|
67
|
+
emptyLabel,
|
|
68
|
+
}: ChartDisplayStateParams): ChartDisplayState => {
|
|
69
|
+
if (loading) {
|
|
70
|
+
return {
|
|
71
|
+
status: hasData ? 'transition-loading' : 'initial-loading',
|
|
72
|
+
ariaLabel: LOADING_ARIA_LABEL,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!hasData) {
|
|
77
|
+
return { status: 'empty', ariaLabel: emptyLabel };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { status: 'ready', ariaLabel: undefined };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Whether any series has at least {@link MIN_DRAWABLE_POINTS} finite points,
|
|
85
|
+
* i.e. enough to actually draw a line. Drives the empty / loading / data states
|
|
86
|
+
* of the chart.
|
|
87
|
+
*
|
|
88
|
+
* When `xData` (the x-axis domain) is provided, only the first `xData.length`
|
|
89
|
+
* points of each series are considered — mirroring the cap in `toScaledPoints`
|
|
90
|
+
* (Line/utils.ts) — so a series longer than the axis cannot report drawable
|
|
91
|
+
* points that would never be plotted.
|
|
92
|
+
*/
|
|
93
|
+
export const canRenderLine = (
|
|
94
|
+
series: Series[] | undefined,
|
|
95
|
+
xData?: readonly (string | number)[],
|
|
96
|
+
): boolean => {
|
|
97
|
+
return (series ?? []).some((s) => {
|
|
98
|
+
const data = s.data ?? [];
|
|
99
|
+
const limit = xData ? Math.min(data.length, xData.length) : data.length;
|
|
100
|
+
let drawablePoints = 0;
|
|
101
|
+
for (let i = 0; i < limit; i++) {
|
|
102
|
+
if (isFiniteNumber(data[i])) drawablePoints++;
|
|
103
|
+
if (drawablePoints >= MIN_DRAWABLE_POINTS) return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
});
|
|
107
|
+
};
|
|
@@ -3,7 +3,10 @@ import { G, Line as SvgLine, Text as SvgText } from 'react-native-svg';
|
|
|
3
3
|
|
|
4
4
|
import { useCartesianChartContext } from '../CartesianChart/context';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
REFERENCE_LINE_DASH_ARRAY,
|
|
8
|
+
REFERENCE_LINE_STROKE_WIDTH,
|
|
9
|
+
} from './constants';
|
|
7
10
|
import type { ReferenceLineProps } from './types';
|
|
8
11
|
import {
|
|
9
12
|
computeHorizontalLabelCoordinates,
|
|
@@ -28,7 +31,8 @@ export function ReferenceLine({
|
|
|
28
31
|
const { theme } = useTheme();
|
|
29
32
|
|
|
30
33
|
const resolvedStroke = stroke ?? theme.colors.border.muted;
|
|
31
|
-
const dashArray =
|
|
34
|
+
const dashArray =
|
|
35
|
+
lineStyle === 'dashed' ? REFERENCE_LINE_DASH_ARRAY : undefined;
|
|
32
36
|
const fontSize = theme.typographies.body4.fontSize;
|
|
33
37
|
|
|
34
38
|
if (props.dataY !== undefined) {
|
|
@@ -65,7 +69,7 @@ export function ReferenceLine({
|
|
|
65
69
|
x2={drawingArea.x + drawingArea.width}
|
|
66
70
|
y2={yPixel}
|
|
67
71
|
stroke={resolvedStroke}
|
|
68
|
-
strokeWidth={
|
|
72
|
+
strokeWidth={REFERENCE_LINE_STROKE_WIDTH}
|
|
69
73
|
strokeDasharray={dashArray}
|
|
70
74
|
strokeLinecap='round'
|
|
71
75
|
/>
|
|
@@ -122,7 +126,7 @@ export function ReferenceLine({
|
|
|
122
126
|
x2={xPixel}
|
|
123
127
|
y2={drawingArea.y + drawingArea.height}
|
|
124
128
|
stroke={resolvedStroke}
|
|
125
|
-
strokeWidth={
|
|
129
|
+
strokeWidth={REFERENCE_LINE_STROKE_WIDTH}
|
|
126
130
|
strokeDasharray={dashArray}
|
|
127
131
|
strokeLinecap='round'
|
|
128
132
|
/>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
1
|
+
export const REFERENCE_LINE_STROKE_WIDTH = 2;
|
|
2
|
+
export const REFERENCE_LINE_DASH_ARRAY = '0.1 6';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isFiniteNumber } from '../../utils/numbers';
|
|
1
2
|
import { getPointOnScale, isCategoricalScale } from '../../utils/scales/scales';
|
|
2
3
|
import type { ChartScaleFunction, DrawingArea } from '../../utils/types';
|
|
3
4
|
import type { BaseAxisProps } from '../Axis';
|
|
@@ -127,7 +128,7 @@ export const resolvePixel = ({
|
|
|
127
128
|
|
|
128
129
|
const p = getPointOnScale(resolved, scale);
|
|
129
130
|
|
|
130
|
-
if (!
|
|
131
|
+
if (!isFiniteNumber(p) || !isPixelWithinDrawingArea(p, axis, drawingArea)) {
|
|
131
132
|
return undefined;
|
|
132
133
|
}
|
|
133
134
|
return p;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RefObject } from 'react';
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
|
+
import { clamp } from '../../../utils/numbers';
|
|
4
5
|
import type { DrawingArea } from '../../../utils/types';
|
|
5
6
|
import type { ChartTooltipItemData, SvgBBoxElement } from '../types';
|
|
6
7
|
import {
|
|
@@ -77,7 +78,7 @@ export const computeTooltipX = (
|
|
|
77
78
|
drawingArea.x,
|
|
78
79
|
drawingArea.x + drawingArea.width - tooltipWidth,
|
|
79
80
|
);
|
|
80
|
-
return
|
|
81
|
+
return clamp(preferredTooltipX, drawingArea.x, maxTooltipX);
|
|
81
82
|
};
|
|
82
83
|
|
|
83
84
|
/**
|
|
@@ -80,12 +80,23 @@ export function Scrubber({
|
|
|
80
80
|
const seriesData = seriesMap.get(s.id)?.data;
|
|
81
81
|
const pixelY = resolvePixelY(scrubberPosition, seriesData, getYScale);
|
|
82
82
|
if (pixelY === undefined) return null;
|
|
83
|
-
return {
|
|
83
|
+
return {
|
|
84
|
+
id: s.id,
|
|
85
|
+
stroke: s.stroke ?? theme.colors.border.muted,
|
|
86
|
+
pixelY,
|
|
87
|
+
};
|
|
84
88
|
})
|
|
85
89
|
.filter(
|
|
86
90
|
(b): b is { id: string; stroke: string; pixelY: number } => b !== null,
|
|
87
91
|
);
|
|
88
|
-
}, [
|
|
92
|
+
}, [
|
|
93
|
+
scrubberPosition,
|
|
94
|
+
showBeacons,
|
|
95
|
+
series,
|
|
96
|
+
seriesMap,
|
|
97
|
+
getYScale,
|
|
98
|
+
theme.colors.border.muted,
|
|
99
|
+
]);
|
|
89
100
|
|
|
90
101
|
const tooltipPayload = useMemo(() => {
|
|
91
102
|
if (scrubberPosition === undefined || !tooltip) {
|
|
@@ -4,6 +4,7 @@ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
|
4
4
|
import Animated, { useSharedValue } from 'react-native-reanimated';
|
|
5
5
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
6
6
|
|
|
7
|
+
import { clamp } from '../../utils/numbers';
|
|
7
8
|
import { useCartesianChartContext } from '../CartesianChart/context';
|
|
8
9
|
import { useMagneticPointsContext } from '../Point/pointContext';
|
|
9
10
|
import { ScrubberContextProvider } from './context';
|
|
@@ -83,7 +84,7 @@ export function ScrubberProvider({
|
|
|
83
84
|
const clamped =
|
|
84
85
|
index === undefined || ref.dataLength <= 0
|
|
85
86
|
? undefined
|
|
86
|
-
:
|
|
87
|
+
: clamp(index, 0, ref.dataLength - 1);
|
|
87
88
|
if (clamped === ref.lastIndex) return;
|
|
88
89
|
ref.lastIndex = clamped;
|
|
89
90
|
setScrubberPosition(clamped);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { clamp } from '../../utils/numbers';
|
|
1
2
|
import {
|
|
2
3
|
getPointOnScale,
|
|
3
4
|
isCategoricalScale,
|
|
@@ -71,7 +72,7 @@ export const getDataIndexFromPosition = (
|
|
|
71
72
|
const offset =
|
|
72
73
|
rangeStart + scale.paddingOuter() * step + scale.bandwidth() / 2;
|
|
73
74
|
const index = Math.round((pixelX - offset) / step);
|
|
74
|
-
return
|
|
75
|
+
return clamp(index, 0, dataLength - 1);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
if (isNumericScale(scale)) {
|
|
@@ -84,10 +85,7 @@ export const getDataIndexFromPosition = (
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
const inverted = scale.invert(pixelX);
|
|
87
|
-
return Math.
|
|
88
|
-
0,
|
|
89
|
-
Math.min(Math.round(inverted as number), dataLength - 1),
|
|
90
|
-
);
|
|
88
|
+
return clamp(Math.round(inverted as number), 0, dataLength - 1);
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
return 0;
|
package/src/lib/utils/index.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard for a finite number. Narrows out `null`, `undefined`, `NaN` and
|
|
3
|
+
* `Infinity`, i.e. any value that cannot be projected to a valid coordinate or
|
|
4
|
+
* counted as a drawable data point.
|
|
5
|
+
*/
|
|
6
|
+
export const isFiniteNumber = (value: unknown): value is number =>
|
|
7
|
+
Number.isFinite(value);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Constrains `value` to the inclusive `[min, max]` range. For a degenerate
|
|
11
|
+
* range where `min > max` (e.g. an index range `[0, length - 1]` for empty
|
|
12
|
+
* data), `min` takes precedence and is returned — matching `lodash.clamp`.
|
|
13
|
+
*/
|
|
14
|
+
export const clamp = (value: number, min: number, max: number): number =>
|
|
15
|
+
Math.max(Math.min(value, max), min);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BaseAxisProps } from '../../Components/Axis';
|
|
2
2
|
import { isCategoricalScale, isNumericScale } from '../scales/scales';
|
|
3
|
-
import type { ChartScaleFunction
|
|
3
|
+
import type { ChartScaleFunction } from '../types';
|
|
4
4
|
|
|
5
5
|
export const APPROXIMATE_TICK_COUNT = 5;
|
|
6
6
|
|
|
@@ -94,25 +94,3 @@ export const buildTicksData = (
|
|
|
94
94
|
label: getTickLabel(tick, axisData, formatter),
|
|
95
95
|
}));
|
|
96
96
|
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Excludes the X grid line at the Y-axis origin (left edge)
|
|
100
|
-
* to prevent overlap with the Y-axis solid line.
|
|
101
|
-
*/
|
|
102
|
-
export const isTickOnXAxisDomainEdge = (
|
|
103
|
-
tick: TickData,
|
|
104
|
-
drawingArea: DrawingArea,
|
|
105
|
-
): boolean => {
|
|
106
|
-
return tick.position !== drawingArea.x;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Excludes the Y grid line at the X-axis origin (bottom edge)
|
|
111
|
-
* to prevent overlap with the X-axis solid line.
|
|
112
|
-
*/
|
|
113
|
-
export const isTickOnYAxisDomainEdge = (
|
|
114
|
-
tick: TickData,
|
|
115
|
-
drawingArea: DrawingArea,
|
|
116
|
-
): boolean => {
|
|
117
|
-
return tick.position !== drawingArea.y + drawingArea.height;
|
|
118
|
-
};
|
package/src/lib/utils/types.ts
CHANGED
|
@@ -19,6 +19,26 @@ export type DrawingArea = {
|
|
|
19
19
|
height: number;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Interpolation used to draw a line (and its area) between data points.
|
|
24
|
+
* Each value maps to a [d3-shape](https://d3js.org/d3-shape/curve) curve:
|
|
25
|
+
* - `'bump'` — smooth cubic curve with horizontal tangents (`curveBumpX`).
|
|
26
|
+
* - `'natural'` — natural cubic spline through every point (`curveNatural`).
|
|
27
|
+
* - `'monotone'` — smooth curve that preserves monotonicity (`curveMonotoneX`).
|
|
28
|
+
* - `'linear'` — straight segments between points (`curveLinear`).
|
|
29
|
+
* - `'step'` — stepped, piecewise-constant line (`curveStep`).
|
|
30
|
+
* - `'stepAfter'` — stepped line where changes occur after the x-coordinate (`curveStepAfter`).
|
|
31
|
+
* - `'stepBefore'` — stepped line where changes occur before the x-coordinate (`curveStepBefore`).
|
|
32
|
+
*/
|
|
33
|
+
export type CurveType =
|
|
34
|
+
| 'bump'
|
|
35
|
+
| 'natural'
|
|
36
|
+
| 'monotone'
|
|
37
|
+
| 'linear'
|
|
38
|
+
| 'step'
|
|
39
|
+
| 'stepAfter'
|
|
40
|
+
| 'stepBefore';
|
|
41
|
+
|
|
22
42
|
export type Series = {
|
|
23
43
|
/**
|
|
24
44
|
* Unique identifier for the series.
|
|
@@ -33,9 +53,15 @@ export type Series = {
|
|
|
33
53
|
*/
|
|
34
54
|
label?: string;
|
|
35
55
|
/**
|
|
36
|
-
*
|
|
56
|
+
* Color applied to the series line/mark.
|
|
57
|
+
* @default border-muted
|
|
58
|
+
*/
|
|
59
|
+
stroke?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Interpolation used to draw the line between data points.
|
|
62
|
+
* @default 'bump'
|
|
37
63
|
*/
|
|
38
|
-
|
|
64
|
+
curve?: CurveType;
|
|
39
65
|
};
|
|
40
66
|
|
|
41
67
|
export type NumericScale =
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["useEffect","useId","useAnimatedProps","useSharedValue","withTiming","OVERFLOW_BUFFER","useRevealClipAnimation","durationMs","drawingArea","dataFingerprint","clipId","width","value","left","right","duration","animatedRectProps","useComputeDataFingerprint","series","map","s","data","join"],"sourceRoot":"../../../../../../src","sources":["lib/Components/CartesianChart/RevealClip/utils.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,KAAK,QAAQ,OAAO;AACxC,SACEC,gBAAgB,EAChBC,cAAc,EACdC,UAAU,QACL,yBAAyB;AAGhC,SAASC,eAAe,QAAQ,aAAU;AAa1C,OAAO,MAAMC,sBAAsB,GAAGA,CAAC;EACrCC,UAAU;EACVC,WAAW;EACXC;AACyB,CAAC,KAAgC;EAC1D,MAAMC,MAAM,GAAGT,KAAK,CAAC,CAAC;EACtB,MAAMU,KAAK,GAAGR,cAAc,CAAC,CAAC,CAAC;EAE/BH,SAAS,CAAC,MAAM;IACdW,KAAK,CAACC,KAAK,GAAG,CAAC;IACfD,KAAK,CAACC,KAAK,GAAGR,UAAU,CACtBI,WAAW,CAACG,KAAK,GAAGN,eAAe,CAACQ,IAAI,GAAGR,eAAe,CAACS,KAAK,EAChE;MAAEC,QAAQ,EAAER;IAAW,CACzB,CAAC;EACH,CAAC,EAAE,CAACC,WAAW,CAACG,KAAK,EAAEJ,UAAU,EAAEI,KAAK,EAAEF,eAAe,CAAC,CAAC;EAE3D,MAAMO,iBAAiB,GAAGd,gBAAgB,CAAC,OAAO;IAChDS,KAAK,EAAEA,KAAK,CAACC;EACf,CAAC,CAAC,CAAC;EAEH,OAAO;IAAEF,MAAM;IAAEM;EAAkB,CAAC;AACtC,CAAC;AAED,OAAO,MAAMC,yBAAyB,GAAGA,CAAC;EACxCC;AAGF,CAAC,KAAa;EACZ,OAAOA,MAAM,CAACC,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,EAAEC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAACA,IAAI,CAAC,GAAG,CAAC;AAC7D,CAAC","ignoreList":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/Components/CartesianChart/RevealClip/utils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAGhE,KAAK,yBAAyB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;CACxD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,+CAIpC,yBAAyB,KAAG,yBAiB9B,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,aAEvC;IACD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,KAAG,MAEH,CAAC"}
|