@ledgerhq/lumen-ui-rnative-visualization 0.1.14 → 0.1.16
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/Axis.constants.js +21 -0
- package/dist/module/lib/Components/Axis/Axis.constants.js.map +1 -0
- package/dist/module/lib/Components/Axis/index.js +5 -0
- package/dist/module/lib/Components/Axis/index.js.map +1 -0
- package/dist/module/lib/Components/CartesianChart/CartesianChart.js +34 -22
- package/dist/module/lib/Components/CartesianChart/CartesianChart.js.map +1 -1
- package/dist/module/lib/Components/CartesianChart/context/useBuildChartContext.js +5 -4
- package/dist/module/lib/Components/CartesianChart/context/useBuildChartContext.js.map +1 -1
- package/dist/module/lib/Components/CartesianChart/context/useBuildChartContext.test.js +54 -0
- package/dist/module/lib/Components/CartesianChart/context/useBuildChartContext.test.js.map +1 -1
- package/dist/module/lib/Components/CartesianChart/utils.js +22 -12
- package/dist/module/lib/Components/CartesianChart/utils.js.map +1 -1
- package/dist/module/lib/Components/Line/utils.js +6 -1
- package/dist/module/lib/Components/Line/utils.js.map +1 -1
- package/dist/module/lib/Components/Line/utils.test.js +88 -0
- package/dist/module/lib/Components/Line/utils.test.js.map +1 -0
- package/dist/module/lib/Components/LineChart/LineChart.js +19 -31
- package/dist/module/lib/Components/LineChart/LineChart.js.map +1 -1
- package/dist/module/lib/Components/LineChart/LineChart.stories.js +38 -0
- package/dist/module/lib/Components/LineChart/LineChart.stories.js.map +1 -1
- package/dist/module/lib/Components/LineChart/LineChart.test.js +192 -0
- package/dist/module/lib/Components/LineChart/LineChart.test.js.map +1 -1
- package/dist/module/lib/Components/Point/Point.js +8 -2
- package/dist/module/lib/Components/Point/Point.js.map +1 -1
- package/dist/module/lib/Components/Point/constants.js +9 -0
- package/dist/module/lib/Components/Point/constants.js.map +1 -0
- package/dist/module/lib/Components/Point/pointContext/MagneticPointsProvider.js +35 -0
- package/dist/module/lib/Components/Point/pointContext/MagneticPointsProvider.js.map +1 -0
- package/dist/module/lib/Components/Point/pointContext/MagneticPointsProvider.test.js +153 -0
- package/dist/module/lib/Components/Point/pointContext/MagneticPointsProvider.test.js.map +1 -0
- package/dist/module/lib/Components/Point/pointContext/index.js +5 -0
- package/dist/module/lib/Components/Point/pointContext/index.js.map +1 -0
- package/dist/module/lib/Components/Point/pointContext/magneticPointsContext.js +10 -0
- package/dist/module/lib/Components/Point/pointContext/magneticPointsContext.js.map +1 -0
- package/dist/module/lib/Components/Point/utils.js +26 -6
- package/dist/module/lib/Components/Point/utils.js.map +1 -1
- package/dist/module/lib/Components/Point/utils.test.js +84 -2
- package/dist/module/lib/Components/Point/utils.test.js.map +1 -1
- package/dist/module/lib/Components/ReferenceLine/utils.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/ChartTooltipItem.js +3 -3
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/ChartTooltipItem.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/DefaultScrubberTooltip.js +5 -5
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/DefaultScrubberTooltip.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/DefaultScrubberTooltip.test.js +5 -5
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/constants.js +1 -2
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/constants.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js +31 -10
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.test.js +4 -4
- package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.test.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/ScrubberProvider.js +35 -7
- package/dist/module/lib/Components/Scrubber/ScrubberProvider.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/utils.js +64 -0
- package/dist/module/lib/Components/Scrubber/utils.js.map +1 -1
- package/dist/module/lib/Components/Scrubber/utils.test.js +128 -1
- package/dist/module/lib/Components/Scrubber/utils.test.js.map +1 -1
- package/dist/module/lib/utils/domain/domain.js.map +1 -1
- package/dist/module/lib/utils/scales/scales.js +13 -4
- package/dist/module/lib/utils/scales/scales.js.map +1 -1
- package/dist/module/lib/utils/scales/scales.test.js +29 -0
- package/dist/module/lib/utils/scales/scales.test.js.map +1 -1
- package/dist/module/lib/utils/ticks/ticks.js +13 -3
- package/dist/module/lib/utils/ticks/ticks.js.map +1 -1
- package/dist/module/lib/utils/ticks/ticks.test.js +34 -0
- package/dist/module/lib/utils/ticks/ticks.test.js.map +1 -1
- package/dist/typescript/src/lib/Components/Axis/Axis.constants.d.ts +5 -0
- package/dist/typescript/src/lib/Components/Axis/Axis.constants.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Axis/Axis.types.d.ts +39 -0
- package/dist/typescript/src/lib/Components/Axis/Axis.types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Axis/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/Axis/index.d.ts.map +1 -0
- 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/context/useBuildChartContext.d.ts +5 -4
- package/dist/typescript/src/lib/Components/CartesianChart/context/useBuildChartContext.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts +11 -3
- package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/CartesianChart/utils.d.ts +18 -8
- package/dist/typescript/src/lib/Components/CartesianChart/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Line/utils.d.ts +4 -0
- 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/types.d.ts +10 -3
- package/dist/typescript/src/lib/Components/LineChart/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Point/Point.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Point/Point.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Point/constants.d.ts +7 -0
- package/dist/typescript/src/lib/Components/Point/constants.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Point/pointContext/MagneticPointsProvider.d.ts +7 -0
- package/dist/typescript/src/lib/Components/Point/pointContext/MagneticPointsProvider.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Point/pointContext/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/Point/pointContext/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Point/pointContext/magneticPointsContext.d.ts +13 -0
- package/dist/typescript/src/lib/Components/Point/pointContext/magneticPointsContext.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Point/types.d.ts +7 -0
- package/dist/typescript/src/lib/Components/Point/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Point/utils.d.ts +8 -6
- package/dist/typescript/src/lib/Components/Point/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/ReferenceLine/utils.d.ts +3 -2
- package/dist/typescript/src/lib/Components/ReferenceLine/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/DefaultScrubberTooltip.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/constants.d.ts +1 -2
- package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/constants.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.d.ts +5 -1
- package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/types.d.ts +13 -0
- package/dist/typescript/src/lib/Components/Scrubber/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/utils.d.ts +33 -3
- package/dist/typescript/src/lib/Components/Scrubber/utils.d.ts.map +1 -1
- package/dist/typescript/src/lib/utils/domain/domain.d.ts +5 -4
- package/dist/typescript/src/lib/utils/domain/domain.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/scales/scales.d.ts +11 -5
- package/dist/typescript/src/lib/utils/scales/scales.d.ts.map +1 -1
- package/dist/typescript/src/lib/utils/ticks/ticks.d.ts +13 -5
- package/dist/typescript/src/lib/utils/ticks/ticks.d.ts.map +1 -1
- package/dist/typescript/src/lib/utils/types.d.ts +3 -28
- package/dist/typescript/src/lib/utils/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/lib/Components/Axis/Axis.constants.ts +23 -0
- package/src/lib/Components/Axis/Axis.types.ts +40 -0
- package/src/lib/Components/Axis/index.ts +2 -0
- package/src/lib/Components/CartesianChart/CartesianChart.tsx +39 -23
- package/src/lib/Components/CartesianChart/context/useBuildChartContext.test.ts +56 -0
- package/src/lib/Components/CartesianChart/context/useBuildChartContext.ts +8 -8
- package/src/lib/Components/CartesianChart/types.ts +11 -3
- package/src/lib/Components/CartesianChart/utils.ts +22 -12
- package/src/lib/Components/Line/utils.test.ts +90 -0
- package/src/lib/Components/Line/utils.ts +6 -1
- package/src/lib/Components/LineChart/LineChart.stories.tsx +36 -0
- package/src/lib/Components/LineChart/LineChart.test.tsx +156 -0
- package/src/lib/Components/LineChart/LineChart.tsx +30 -40
- package/src/lib/Components/LineChart/types.ts +10 -3
- package/src/lib/Components/Point/Point.tsx +9 -3
- package/src/lib/Components/Point/constants.ts +6 -0
- package/src/lib/Components/Point/pointContext/MagneticPointsProvider.test.tsx +162 -0
- package/src/lib/Components/Point/pointContext/MagneticPointsProvider.tsx +45 -0
- package/src/lib/Components/Point/pointContext/index.ts +5 -0
- package/src/lib/Components/Point/pointContext/magneticPointsContext.ts +19 -0
- package/src/lib/Components/Point/types.ts +7 -0
- package/src/lib/Components/Point/utils.test.ts +95 -5
- package/src/lib/Components/Point/utils.ts +35 -7
- package/src/lib/Components/ReferenceLine/utils.ts +4 -7
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/ChartTooltipItem.tsx +3 -3
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/DefaultScrubberTooltip.test.tsx +5 -5
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/DefaultScrubberTooltip.tsx +4 -5
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/constants.ts +1 -2
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.test.ts +4 -4
- package/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.ts +29 -15
- package/src/lib/Components/Scrubber/ScrubberProvider.tsx +41 -5
- package/src/lib/Components/Scrubber/types.ts +13 -0
- package/src/lib/Components/Scrubber/utils.test.ts +150 -0
- package/src/lib/Components/Scrubber/utils.ts +93 -3
- package/src/lib/utils/domain/domain.ts +6 -5
- package/src/lib/utils/index.ts +0 -2
- package/src/lib/utils/scales/scales.test.ts +19 -0
- package/src/lib/utils/scales/scales.ts +15 -9
- package/src/lib/utils/ticks/ticks.test.ts +45 -0
- package/src/lib/utils/ticks/ticks.ts +19 -9
- package/src/lib/utils/types.ts +3 -26
|
@@ -5,9 +5,15 @@ import Animated, { useSharedValue } from 'react-native-reanimated';
|
|
|
5
5
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
6
6
|
|
|
7
7
|
import { useCartesianChartContext } from '../CartesianChart/context';
|
|
8
|
+
import { useMagneticPointsContext } from '../Point/pointContext';
|
|
8
9
|
import { ScrubberContextProvider } from './context';
|
|
9
10
|
import type { ScrubberProviderProps } from './types';
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
applyMagnetisation,
|
|
13
|
+
getDataIndexFromPosition,
|
|
14
|
+
resolvePixelX,
|
|
15
|
+
buildSortedMagnets,
|
|
16
|
+
} from './utils';
|
|
11
17
|
|
|
12
18
|
const LONG_PRESS_MIN_DURATION_MS = 50;
|
|
13
19
|
|
|
@@ -30,29 +36,46 @@ export function ScrubberProvider({
|
|
|
30
36
|
height,
|
|
31
37
|
enableScrubbing,
|
|
32
38
|
onScrubberPositionChange,
|
|
39
|
+
magnetRadius = 6,
|
|
40
|
+
style,
|
|
33
41
|
}: Readonly<ScrubberProviderProps>) {
|
|
34
42
|
const [scrubberPosition, setScrubberPosition] = useState<
|
|
35
43
|
number | undefined
|
|
36
44
|
>();
|
|
37
45
|
|
|
38
46
|
const { getXScale, getXAxisConfig, dataLength } = useCartesianChartContext();
|
|
47
|
+
const { getMagneticPoints, version } = useMagneticPointsContext();
|
|
39
48
|
|
|
40
49
|
// All values touched by the gesture's JS-thread callback live in a single
|
|
41
50
|
// ref. Reading via `latest.current` keeps the callbacks reference-stable
|
|
42
51
|
// across data, scale, and prop updates, which in turn keeps `composed` and
|
|
43
52
|
// the gesture surface JSX stable so re-rendering the provider on each
|
|
44
53
|
// index change never tears down the GestureDetector or the View tree.
|
|
54
|
+
const sortedMagnets = useMemo(() => {
|
|
55
|
+
const magneticIndices = getMagneticPoints();
|
|
56
|
+
return buildSortedMagnets({
|
|
57
|
+
magneticIndices,
|
|
58
|
+
getPixelForIndex: (index) =>
|
|
59
|
+
resolvePixelX(index, getXScale, getXAxisConfig()),
|
|
60
|
+
});
|
|
61
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
62
|
+
}, [version, getXScale, getXAxisConfig, getMagneticPoints]);
|
|
63
|
+
|
|
45
64
|
const latest = useRef({
|
|
46
65
|
getXScale,
|
|
47
66
|
getXAxisConfig,
|
|
48
67
|
dataLength,
|
|
49
68
|
onChange: onScrubberPositionChange,
|
|
50
69
|
lastIndex: undefined as number | undefined,
|
|
70
|
+
magnetRadius,
|
|
71
|
+
sortedMagnets,
|
|
51
72
|
});
|
|
52
73
|
latest.current.getXScale = getXScale;
|
|
53
74
|
latest.current.getXAxisConfig = getXAxisConfig;
|
|
54
75
|
latest.current.dataLength = dataLength;
|
|
55
76
|
latest.current.onChange = onScrubberPositionChange;
|
|
77
|
+
latest.current.magnetRadius = magnetRadius;
|
|
78
|
+
latest.current.sortedMagnets = sortedMagnets;
|
|
56
79
|
|
|
57
80
|
const setScrubberPositionAndNotify = useCallback(
|
|
58
81
|
(index: number | undefined) => {
|
|
@@ -78,12 +101,25 @@ export function ScrubberProvider({
|
|
|
78
101
|
const ref = latest.current;
|
|
79
102
|
const scale = ref.getXScale();
|
|
80
103
|
if (!scale || ref.dataLength <= 0) return;
|
|
81
|
-
|
|
104
|
+
|
|
105
|
+
const xAxisConfig = ref.getXAxisConfig();
|
|
106
|
+
|
|
107
|
+
let index = getDataIndexFromPosition(
|
|
82
108
|
pixelX,
|
|
83
109
|
scale,
|
|
84
|
-
|
|
110
|
+
xAxisConfig,
|
|
85
111
|
ref.dataLength,
|
|
86
112
|
);
|
|
113
|
+
|
|
114
|
+
if (ref.magnetRadius > 0) {
|
|
115
|
+
index = applyMagnetisation({
|
|
116
|
+
resolvedIndex: index,
|
|
117
|
+
pixelX,
|
|
118
|
+
sortedMagnets: ref.sortedMagnets,
|
|
119
|
+
magnetRadius: ref.magnetRadius,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
87
123
|
setScrubberPositionAndNotify(index);
|
|
88
124
|
},
|
|
89
125
|
[setScrubberPositionAndNotify],
|
|
@@ -128,7 +164,7 @@ export function ScrubberProvider({
|
|
|
128
164
|
// context as expected.
|
|
129
165
|
const surface = useMemo(
|
|
130
166
|
() => (
|
|
131
|
-
<View style={{ width, height }}>
|
|
167
|
+
<View style={[{ width, height }, style]}>
|
|
132
168
|
{children}
|
|
133
169
|
{enableScrubbing && (
|
|
134
170
|
<GestureDetector gesture={composed}>
|
|
@@ -140,7 +176,7 @@ export function ScrubberProvider({
|
|
|
140
176
|
)}
|
|
141
177
|
</View>
|
|
142
178
|
),
|
|
143
|
-
[width, height, children, enableScrubbing, composed],
|
|
179
|
+
[width, height, style, children, enableScrubbing, composed],
|
|
144
180
|
);
|
|
145
181
|
|
|
146
182
|
const contextValue = useMemo(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
3
|
|
|
3
4
|
import type { DrawingArea } from '../../utils/types';
|
|
4
5
|
|
|
@@ -35,6 +36,18 @@ export type ScrubberProviderProps = {
|
|
|
35
36
|
* Optional external callback fired whenever the scrubber position changes.
|
|
36
37
|
*/
|
|
37
38
|
onScrubberPositionChange?: (index: number | undefined) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Pixel radius within which the scrubber magnetically snaps to registered
|
|
41
|
+
* magnetic points. Set to `0` to disable magnetisation.
|
|
42
|
+
* @default 6
|
|
43
|
+
*/
|
|
44
|
+
magnetRadius?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Optional style applied to the wrapping `View` that holds the chart and the
|
|
47
|
+
* gesture overlay.Used to offset the(enlarged) SVG group so its drawing area
|
|
48
|
+
* aligns with the container footprint.
|
|
49
|
+
*/
|
|
50
|
+
style?: StyleProp<ViewStyle>;
|
|
38
51
|
};
|
|
39
52
|
|
|
40
53
|
export type ChartTooltipItemData = {
|
|
@@ -5,10 +5,14 @@ import {
|
|
|
5
5
|
getNumericScale,
|
|
6
6
|
} from '../../utils/scales/scales';
|
|
7
7
|
import {
|
|
8
|
+
applyMagnetisation,
|
|
9
|
+
buildSortedMagnets,
|
|
8
10
|
getDataIndexFromPosition,
|
|
11
|
+
nearestIndex,
|
|
9
12
|
resolvePixelX,
|
|
10
13
|
resolvePixelY,
|
|
11
14
|
} from './utils';
|
|
15
|
+
import type { MagnetEntry } from './utils';
|
|
12
16
|
|
|
13
17
|
describe('getDataIndexFromPosition', () => {
|
|
14
18
|
describe('with a categorical (band) scale', () => {
|
|
@@ -170,3 +174,149 @@ describe('resolvePixelY', () => {
|
|
|
170
174
|
expect(result).toBe(scale(50));
|
|
171
175
|
});
|
|
172
176
|
});
|
|
177
|
+
|
|
178
|
+
describe('buildSortedMagnets', () => {
|
|
179
|
+
it('returns an empty array when the set is empty', () => {
|
|
180
|
+
const result = buildSortedMagnets({
|
|
181
|
+
magneticIndices: new Set(),
|
|
182
|
+
getPixelForIndex: () => 0,
|
|
183
|
+
});
|
|
184
|
+
expect(result).toEqual([]);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('returns entries sorted by pixelX', () => {
|
|
188
|
+
const result = buildSortedMagnets({
|
|
189
|
+
magneticIndices: new Set([3, 1, 2]),
|
|
190
|
+
getPixelForIndex: (i) => i * 50,
|
|
191
|
+
});
|
|
192
|
+
expect(result).toEqual([
|
|
193
|
+
{ index: 1, pixelX: 50 },
|
|
194
|
+
{ index: 2, pixelX: 100 },
|
|
195
|
+
{ index: 3, pixelX: 150 },
|
|
196
|
+
]);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('filters out indices where getPixelForIndex returns undefined', () => {
|
|
200
|
+
const result = buildSortedMagnets({
|
|
201
|
+
magneticIndices: new Set([0, 1, 2]),
|
|
202
|
+
getPixelForIndex: (i) => (i === 1 ? undefined : i * 100),
|
|
203
|
+
});
|
|
204
|
+
expect(result).toEqual([
|
|
205
|
+
{ index: 0, pixelX: 0 },
|
|
206
|
+
{ index: 2, pixelX: 200 },
|
|
207
|
+
]);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('returns an empty array when all indices resolve to undefined', () => {
|
|
211
|
+
const result = buildSortedMagnets({
|
|
212
|
+
magneticIndices: new Set([0, 1]),
|
|
213
|
+
getPixelForIndex: () => undefined,
|
|
214
|
+
});
|
|
215
|
+
expect(result).toEqual([]);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('nearestIndex', () => {
|
|
220
|
+
const magnets = (...pixelXs: number[]): MagnetEntry[] =>
|
|
221
|
+
pixelXs.map((px, i) => ({ index: i, pixelX: px }));
|
|
222
|
+
|
|
223
|
+
it('returns -1 for an empty array', () => {
|
|
224
|
+
expect(nearestIndex([], 100)).toBe(-1);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('returns 0 for a single-element array', () => {
|
|
228
|
+
expect(nearestIndex(magnets(200), 100)).toBe(0);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('returns the index of the exact match', () => {
|
|
232
|
+
expect(nearestIndex(magnets(100, 200, 300), 200)).toBe(1);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('returns the closer index when target is between two values', () => {
|
|
236
|
+
expect(nearestIndex(magnets(100, 200), 160)).toBe(1);
|
|
237
|
+
expect(nearestIndex(magnets(100, 200), 140)).toBe(0);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('favors the left index when equidistant', () => {
|
|
241
|
+
expect(nearestIndex(magnets(100, 200), 150)).toBe(0);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('returns the last index when target is beyond all values', () => {
|
|
245
|
+
expect(nearestIndex(magnets(100, 200), 500)).toBe(1);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('returns the first index when target is before all values', () => {
|
|
249
|
+
expect(nearestIndex(magnets(100, 200), 0)).toBe(0);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('applyMagnetisation', () => {
|
|
254
|
+
const toMagnets = (...indices: number[]): MagnetEntry[] =>
|
|
255
|
+
indices.map((i) => ({ index: i, pixelX: i * 100 }));
|
|
256
|
+
|
|
257
|
+
it('returns resolvedIndex when sortedMagnets is empty', () => {
|
|
258
|
+
expect(
|
|
259
|
+
applyMagnetisation({
|
|
260
|
+
resolvedIndex: 2,
|
|
261
|
+
pixelX: 200,
|
|
262
|
+
sortedMagnets: [],
|
|
263
|
+
magnetRadius: 30,
|
|
264
|
+
}),
|
|
265
|
+
).toBe(2);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('returns resolvedIndex when magnetRadius is 0', () => {
|
|
269
|
+
expect(
|
|
270
|
+
applyMagnetisation({
|
|
271
|
+
resolvedIndex: 1,
|
|
272
|
+
pixelX: 200,
|
|
273
|
+
sortedMagnets: toMagnets(2),
|
|
274
|
+
magnetRadius: 0,
|
|
275
|
+
}),
|
|
276
|
+
).toBe(1);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('returns resolvedIndex when nearest magnet is outside radius', () => {
|
|
280
|
+
expect(
|
|
281
|
+
applyMagnetisation({
|
|
282
|
+
resolvedIndex: 2,
|
|
283
|
+
pixelX: 200,
|
|
284
|
+
sortedMagnets: toMagnets(0, 4),
|
|
285
|
+
magnetRadius: 30,
|
|
286
|
+
}),
|
|
287
|
+
).toBe(2);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('snaps to nearest magnet when within radius', () => {
|
|
291
|
+
expect(
|
|
292
|
+
applyMagnetisation({
|
|
293
|
+
resolvedIndex: 2,
|
|
294
|
+
pixelX: 280,
|
|
295
|
+
sortedMagnets: toMagnets(3),
|
|
296
|
+
magnetRadius: 30,
|
|
297
|
+
}),
|
|
298
|
+
).toBe(3);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('snaps at the exact boundary of magnetRadius', () => {
|
|
302
|
+
expect(
|
|
303
|
+
applyMagnetisation({
|
|
304
|
+
resolvedIndex: 2,
|
|
305
|
+
pixelX: 270,
|
|
306
|
+
sortedMagnets: toMagnets(3),
|
|
307
|
+
magnetRadius: 30,
|
|
308
|
+
}),
|
|
309
|
+
).toBe(3);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('does not snap when distance exceeds magnetRadius by 1', () => {
|
|
313
|
+
expect(
|
|
314
|
+
applyMagnetisation({
|
|
315
|
+
resolvedIndex: 2,
|
|
316
|
+
pixelX: 269,
|
|
317
|
+
sortedMagnets: toMagnets(3),
|
|
318
|
+
magnetRadius: 30,
|
|
319
|
+
}),
|
|
320
|
+
).toBe(2);
|
|
321
|
+
});
|
|
322
|
+
});
|
|
@@ -4,10 +4,15 @@ import {
|
|
|
4
4
|
isNumericScale,
|
|
5
5
|
} from '../../utils/scales/scales';
|
|
6
6
|
import type {
|
|
7
|
-
AxisConfigProps,
|
|
8
7
|
CartesianChartContextValue,
|
|
9
8
|
ChartScaleFunction,
|
|
10
9
|
} from '../../utils/types';
|
|
10
|
+
import type { BaseAxisProps } from '../Axis';
|
|
11
|
+
|
|
12
|
+
export type MagnetEntry = {
|
|
13
|
+
index: number;
|
|
14
|
+
pixelX: number;
|
|
15
|
+
};
|
|
11
16
|
|
|
12
17
|
const isNumberArray = (arr: string[] | number[]): arr is number[] =>
|
|
13
18
|
typeof arr[0] === 'number';
|
|
@@ -49,7 +54,7 @@ const findClosestIndex = (
|
|
|
49
54
|
export const getDataIndexFromPosition = (
|
|
50
55
|
pixelX: number,
|
|
51
56
|
scale: ChartScaleFunction,
|
|
52
|
-
axisConfig: Partial<
|
|
57
|
+
axisConfig: Partial<BaseAxisProps> | undefined,
|
|
53
58
|
dataLength: number,
|
|
54
59
|
): number => {
|
|
55
60
|
if (dataLength <= 0) return 0;
|
|
@@ -116,7 +121,7 @@ export const resolvePixelY = (
|
|
|
116
121
|
export const resolvePixelX = (
|
|
117
122
|
dataIndex: number,
|
|
118
123
|
getXScale: CartesianChartContextValue['getXScale'],
|
|
119
|
-
axisConfig?:
|
|
124
|
+
axisConfig?: BaseAxisProps,
|
|
120
125
|
): number | undefined => {
|
|
121
126
|
const scale = getXScale();
|
|
122
127
|
if (!scale) return undefined;
|
|
@@ -124,3 +129,88 @@ export const resolvePixelX = (
|
|
|
124
129
|
const xValue = typeof axisValue === 'number' ? axisValue : dataIndex;
|
|
125
130
|
return getPointOnScale(xValue, scale);
|
|
126
131
|
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Resolves each magnetic index to its pixel position and returns them sorted
|
|
135
|
+
* by `pixelX` ascending. Indices that cannot be projected are filtered out.
|
|
136
|
+
* The sorted output enables early-exit in {@link applyMagnetisation}.
|
|
137
|
+
*/
|
|
138
|
+
export const buildSortedMagnets = ({
|
|
139
|
+
magneticIndices,
|
|
140
|
+
getPixelForIndex,
|
|
141
|
+
}: {
|
|
142
|
+
magneticIndices: ReadonlySet<number>;
|
|
143
|
+
getPixelForIndex: (index: number) => number | undefined;
|
|
144
|
+
}): MagnetEntry[] => {
|
|
145
|
+
if (magneticIndices.size === 0) return [];
|
|
146
|
+
|
|
147
|
+
const magnets: MagnetEntry[] = [];
|
|
148
|
+
|
|
149
|
+
for (const index of magneticIndices) {
|
|
150
|
+
const pixelX = getPixelForIndex(index);
|
|
151
|
+
if (pixelX !== undefined) magnets.push({ index, pixelX });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
magnets.sort((a, b) => a.pixelX - b.pixelX);
|
|
155
|
+
|
|
156
|
+
return magnets;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Binary search for the magnet whose `pixelX` is closest to `pixelX`.
|
|
161
|
+
* Returns -1 when the array is empty. Favors the left neighbor on ties.
|
|
162
|
+
*/
|
|
163
|
+
export const nearestIndex = (
|
|
164
|
+
sortedMagnets: readonly MagnetEntry[],
|
|
165
|
+
pixelX: number,
|
|
166
|
+
): number => {
|
|
167
|
+
if (sortedMagnets.length === 0) return -1;
|
|
168
|
+
|
|
169
|
+
let left = 0;
|
|
170
|
+
let right = sortedMagnets.length;
|
|
171
|
+
|
|
172
|
+
while (left < right) {
|
|
173
|
+
const mid = Math.floor((left + right) / 2);
|
|
174
|
+
if (sortedMagnets[mid].pixelX < pixelX) {
|
|
175
|
+
left = mid + 1;
|
|
176
|
+
} else {
|
|
177
|
+
right = mid;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (left === 0) return 0;
|
|
182
|
+
if (left === sortedMagnets.length) return left - 1;
|
|
183
|
+
|
|
184
|
+
const distBefore = pixelX - sortedMagnets[left - 1].pixelX;
|
|
185
|
+
const distAfter = sortedMagnets[left].pixelX - pixelX;
|
|
186
|
+
|
|
187
|
+
return distBefore <= distAfter ? left - 1 : left;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Given a resolved data index and the raw pixel position, checks whether any
|
|
192
|
+
* magnetic point is within `magnetRadius` pixels of `pixelX`. If so, returns
|
|
193
|
+
* the closest magnetic index; otherwise returns the original `resolvedIndex`.
|
|
194
|
+
*/
|
|
195
|
+
export const applyMagnetisation = ({
|
|
196
|
+
resolvedIndex,
|
|
197
|
+
pixelX,
|
|
198
|
+
sortedMagnets,
|
|
199
|
+
magnetRadius,
|
|
200
|
+
}: {
|
|
201
|
+
resolvedIndex: number;
|
|
202
|
+
pixelX: number;
|
|
203
|
+
sortedMagnets: readonly MagnetEntry[];
|
|
204
|
+
magnetRadius: number;
|
|
205
|
+
}): number => {
|
|
206
|
+
if (magnetRadius <= 0 || sortedMagnets.length === 0) return resolvedIndex;
|
|
207
|
+
|
|
208
|
+
const nearest = nearestIndex(sortedMagnets, pixelX);
|
|
209
|
+
if (
|
|
210
|
+
nearest >= 0 &&
|
|
211
|
+
Math.abs(sortedMagnets[nearest].pixelX - pixelX) <= magnetRadius
|
|
212
|
+
) {
|
|
213
|
+
return sortedMagnets[nearest].index;
|
|
214
|
+
}
|
|
215
|
+
return resolvedIndex;
|
|
216
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AxisBounds,
|
|
1
|
+
import type { AxisBounds, BaseAxisProps } from '../../Components/Axis';
|
|
2
|
+
import type { Series } from '../types';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Compute the X domain (index-based) from series data and axis config.
|
|
@@ -7,7 +8,7 @@ import type { AxisBounds, AxisConfigProps, Series } from '../types';
|
|
|
7
8
|
*/
|
|
8
9
|
export const computeXDomain = (
|
|
9
10
|
series: Series[],
|
|
10
|
-
axisConfig?: Partial<
|
|
11
|
+
axisConfig?: Partial<BaseAxisProps>,
|
|
11
12
|
): AxisBounds => {
|
|
12
13
|
const axisData = axisConfig?.data;
|
|
13
14
|
|
|
@@ -44,7 +45,7 @@ export const computeXDomain = (
|
|
|
44
45
|
*/
|
|
45
46
|
export const computeYDomain = (
|
|
46
47
|
series: Series[],
|
|
47
|
-
axisConfig?: Partial<
|
|
48
|
+
axisConfig?: Partial<BaseAxisProps>,
|
|
48
49
|
): AxisBounds => {
|
|
49
50
|
let min = 0;
|
|
50
51
|
let max = 0;
|
|
@@ -76,7 +77,7 @@ export const computeYDomain = (
|
|
|
76
77
|
*/
|
|
77
78
|
export const computeDataLength = (
|
|
78
79
|
series: Series[],
|
|
79
|
-
axisConfig?: Partial<
|
|
80
|
+
axisConfig?: Partial<BaseAxisProps>,
|
|
80
81
|
): number => {
|
|
81
82
|
if (axisConfig?.data && axisConfig.data.length > 0) {
|
|
82
83
|
return axisConfig.data.length;
|
|
@@ -86,7 +87,7 @@ export const computeDataLength = (
|
|
|
86
87
|
|
|
87
88
|
const applyDomainOverride = (
|
|
88
89
|
autoBounds: AxisBounds,
|
|
89
|
-
domainOverride?:
|
|
90
|
+
domainOverride?: BaseAxisProps['domain'],
|
|
90
91
|
): AxisBounds => {
|
|
91
92
|
if (!domainOverride) return autoBounds;
|
|
92
93
|
|
package/src/lib/utils/index.ts
CHANGED
|
@@ -53,6 +53,25 @@ describe('getNumericScale', () => {
|
|
|
53
53
|
expect(range[0]).toBe(20);
|
|
54
54
|
expect(range[1]).toBe(400);
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
it('rounds the domain outward when nice is true (default)', () => {
|
|
58
|
+
const scale = getNumericScale({
|
|
59
|
+
scaleType: 'linear',
|
|
60
|
+
domain: { min: 0, max: 3769 },
|
|
61
|
+
range: { min: 0, max: 400 },
|
|
62
|
+
});
|
|
63
|
+
expect(scale.domain()).toEqual([0, 4000]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('keeps the domain exact when nice is false', () => {
|
|
67
|
+
const scale = getNumericScale({
|
|
68
|
+
scaleType: 'linear',
|
|
69
|
+
domain: { min: 0, max: 3769 },
|
|
70
|
+
range: { min: 0, max: 400 },
|
|
71
|
+
nice: false,
|
|
72
|
+
});
|
|
73
|
+
expect(scale.domain()).toEqual([0, 3769]);
|
|
74
|
+
});
|
|
56
75
|
});
|
|
57
76
|
|
|
58
77
|
describe('getCategoricalScale', () => {
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
import { scaleBand, scaleLinear, scaleLog } from 'd3-scale';
|
|
2
2
|
|
|
3
|
+
import type { AxisBounds, BaseAxisProps } from '../../Components/Axis';
|
|
3
4
|
import type {
|
|
4
|
-
AxisBounds,
|
|
5
|
-
AxisConfigProps,
|
|
6
5
|
CategoricalScale,
|
|
7
6
|
ChartScaleFunction,
|
|
8
7
|
NumericScale,
|
|
9
8
|
} from '../types';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
|
-
* Creates a numeric scale
|
|
13
|
-
*
|
|
11
|
+
* Creates a numeric scale.
|
|
12
|
+
*
|
|
13
|
+
* When `nice` is `true` (default), the domain is rounded outward to clean
|
|
14
|
+
* boundaries via d3's `.nice()` (e.g. `[4, 98]` → `[0, 100]`). Set `nice` to
|
|
15
|
+
* `false` to keep the domain exactly as provided so data fills the range
|
|
16
|
+
* boundary-to-boundary.
|
|
14
17
|
*/
|
|
15
18
|
export const getNumericScale = ({
|
|
16
19
|
scaleType,
|
|
17
20
|
domain,
|
|
18
21
|
range,
|
|
22
|
+
nice = true,
|
|
19
23
|
}: {
|
|
20
24
|
scaleType: 'linear' | 'log';
|
|
21
25
|
domain: AxisBounds;
|
|
22
26
|
range: AxisBounds;
|
|
27
|
+
nice?: boolean;
|
|
23
28
|
}): NumericScale => {
|
|
24
29
|
const scale = scaleType === 'log' ? scaleLog() : scaleLinear();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.nice()
|
|
28
|
-
|
|
30
|
+
scale.domain([domain.min, domain.max]);
|
|
31
|
+
if (nice) {
|
|
32
|
+
scale.nice();
|
|
33
|
+
}
|
|
34
|
+
return scale.range([range.min, range.max]);
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
export const getCategoricalScale = ({
|
|
@@ -52,7 +58,7 @@ export const getCategoricalScale = ({
|
|
|
52
58
|
* Checks if a scale type config value refers to a band (categorical) scale.
|
|
53
59
|
*/
|
|
54
60
|
export const isBandScaleType = (
|
|
55
|
-
scaleType:
|
|
61
|
+
scaleType: BaseAxisProps['scaleType'],
|
|
56
62
|
): scaleType is 'band' => scaleType === 'band';
|
|
57
63
|
|
|
58
64
|
/**
|
|
@@ -36,6 +36,24 @@ describe('getTickValues', () => {
|
|
|
36
36
|
it('should return full domain for band scales', () => {
|
|
37
37
|
expect(getTickValues(bandScale)).toEqual([0, 1, 2, 3, 4]);
|
|
38
38
|
});
|
|
39
|
+
|
|
40
|
+
it('should return numeric axis data verbatim (no d3-invented intermediate ticks)', () => {
|
|
41
|
+
expect(getTickValues(numericScale, undefined, [0, 2, 4])).toEqual([
|
|
42
|
+
0, 2, 4,
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should return indices for string axis data', () => {
|
|
47
|
+
expect(
|
|
48
|
+
getTickValues(numericScale, undefined, ['Jan', 'Feb', 'Mar']),
|
|
49
|
+
).toEqual([0, 1, 2]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should prioritize explicit ticks over axis data', () => {
|
|
53
|
+
expect(
|
|
54
|
+
getTickValues(numericScale, [10, 20], ['Jan', 'Feb', 'Mar']),
|
|
55
|
+
).toEqual([10, 20]);
|
|
56
|
+
});
|
|
39
57
|
});
|
|
40
58
|
|
|
41
59
|
describe('getTickPosition', () => {
|
|
@@ -121,6 +139,33 @@ describe('buildTicksData', () => {
|
|
|
121
139
|
expect(result[1].label).toBe('Tue');
|
|
122
140
|
});
|
|
123
141
|
|
|
142
|
+
it('should derive ticks from numeric axis data (no intermediate ticks)', () => {
|
|
143
|
+
const result = buildTicksData(numericScale, { data: [0, 2, 4] });
|
|
144
|
+
expect(result.map((t: { value: number }) => t.value)).toEqual([0, 2, 4]);
|
|
145
|
+
expect(result.map((t: { label: string }) => t.label)).toEqual([
|
|
146
|
+
'0',
|
|
147
|
+
'2',
|
|
148
|
+
'4',
|
|
149
|
+
]);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should derive ticks from string axis data without intermediate values', () => {
|
|
153
|
+
const stringScale = getNumericScale({
|
|
154
|
+
scaleType: 'linear',
|
|
155
|
+
domain: { min: 0, max: 2 },
|
|
156
|
+
range: { min: 0, max: 500 },
|
|
157
|
+
});
|
|
158
|
+
const result = buildTicksData(stringScale, {
|
|
159
|
+
data: ['Jan', 'Feb', 'Mar'],
|
|
160
|
+
});
|
|
161
|
+
expect(result.map((t: { value: number }) => t.value)).toEqual([0, 1, 2]);
|
|
162
|
+
expect(result.map((t: { label: string }) => t.label)).toEqual([
|
|
163
|
+
'Jan',
|
|
164
|
+
'Feb',
|
|
165
|
+
'Mar',
|
|
166
|
+
]);
|
|
167
|
+
});
|
|
168
|
+
|
|
124
169
|
it('should apply tick formatter', () => {
|
|
125
170
|
const formatter = (v: number | string): string => `$${v}`;
|
|
126
171
|
const result = buildTicksData(numericScale, undefined, [0, 50], formatter);
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import type { BaseAxisProps } from '../../Components/Axis';
|
|
1
2
|
import { isCategoricalScale, isNumericScale } from '../scales/scales';
|
|
2
|
-
import type {
|
|
3
|
-
AxisConfigProps,
|
|
4
|
-
ChartScaleFunction,
|
|
5
|
-
DrawingArea,
|
|
6
|
-
} from '../types';
|
|
3
|
+
import type { ChartScaleFunction, DrawingArea } from '../types';
|
|
7
4
|
|
|
8
5
|
export const APPROXIMATE_TICK_COUNT = 5;
|
|
9
6
|
|
|
@@ -15,13 +12,26 @@ export type TickData = {
|
|
|
15
12
|
|
|
16
13
|
/**
|
|
17
14
|
* Resolves which numeric tick values should appear on the axis.
|
|
18
|
-
*
|
|
15
|
+
*
|
|
16
|
+
* Priority:
|
|
17
|
+
* 1. Explicit `ticks` provided by the consumer.
|
|
18
|
+
* 2. Axis `data` — when provided, ticks come from the data itself (numeric
|
|
19
|
+
* values for numeric data, indices for string data) so the rendered ticks
|
|
20
|
+
* mirror exactly what the consumer asked for, with no d3-invented
|
|
21
|
+
* intermediate values.
|
|
22
|
+
* 3. Scale-specific defaults (band domain, or `scale.ticks()` for numeric).
|
|
19
23
|
*/
|
|
20
24
|
export const getTickValues = (
|
|
21
25
|
scale: ChartScaleFunction,
|
|
22
26
|
explicitTicks?: number[],
|
|
27
|
+
axisData?: BaseAxisProps['data'],
|
|
23
28
|
): number[] => {
|
|
24
29
|
if (explicitTicks) return explicitTicks;
|
|
30
|
+
if (axisData && axisData.length > 0) {
|
|
31
|
+
return typeof axisData[0] === 'number'
|
|
32
|
+
? (axisData as number[])
|
|
33
|
+
: axisData.map((_, i) => i);
|
|
34
|
+
}
|
|
25
35
|
if (isCategoricalScale(scale)) return scale.domain();
|
|
26
36
|
if (isNumericScale(scale)) return scale.ticks(APPROXIMATE_TICK_COUNT);
|
|
27
37
|
return [];
|
|
@@ -47,7 +57,7 @@ export const getTickPosition = (
|
|
|
47
57
|
*/
|
|
48
58
|
export const getTickLabel = (
|
|
49
59
|
tick: number,
|
|
50
|
-
axisData:
|
|
60
|
+
axisData: BaseAxisProps['data'],
|
|
51
61
|
formatter?: (value: number | string) => string,
|
|
52
62
|
): string => {
|
|
53
63
|
const hasStringLabels =
|
|
@@ -71,12 +81,12 @@ export const getTickLabel = (
|
|
|
71
81
|
*/
|
|
72
82
|
export const buildTicksData = (
|
|
73
83
|
scale: ChartScaleFunction,
|
|
74
|
-
axisConfig?:
|
|
84
|
+
axisConfig?: BaseAxisProps,
|
|
75
85
|
explicitTicks?: number[],
|
|
76
86
|
formatter?: (value: number | string) => string,
|
|
77
87
|
): TickData[] => {
|
|
78
|
-
const tickValues = getTickValues(scale, explicitTicks);
|
|
79
88
|
const axisData = axisConfig?.data;
|
|
89
|
+
const tickValues = getTickValues(scale, explicitTicks, axisData);
|
|
80
90
|
|
|
81
91
|
return tickValues.map((tick) => ({
|
|
82
92
|
position: getTickPosition(scale, tick),
|