Skip to content

Commit 2b6ab69

Browse files
committed
feat: introduce deterministic pan
Before, panning was done by linearly interpolating the data points. Now, we have a deterministic pan gesture that accurately computes the data points that are being panned to. Key Highlights: - Introduced a deterministic pan gesture that accurately computes the data points that are being panned to. Before, a simple linear interpolation was used to determine the data points. However, this was inaccurate and doesn't fit our use case. - Modified the linearForX function to getClosestPointForX that finds the closest data point to the given x value (gesture). This method returns the (x, y) on the chart, and the index the input corresponds to in the data array. Next steps: - Implement binary search to find the closest point to the given x value instead of iteratively searching through the data array. - Create a caching mechanism to store the last point that was panned to. If it does not differ from the current point, we can skip propagating the gesture event to the parent component. This allows things like Haptics to be triggered only when the point changes.
1 parent 4cbcb7d commit 2b6ab69

File tree

5 files changed

+803
-79
lines changed

5 files changed

+803
-79
lines changed

example/app/multi_line_chart.tsx

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,24 @@ const gestureStartImpact = () => {
1212
};
1313

1414
export default () => {
15-
const cursorShown = useSharedValue(false);
16-
const x = useSharedValue(0);
17-
const y = useSharedValue(0);
1815
const { bottom, left, right } = useSafeAreaInsets();
1916

17+
const cursorShown = useSharedValue(false);
2018
const opacity = useDerivedValue(() => {
2119
// return cursorShown.value ? 1 : 0;
2220
// Use a timing function to animate the opacity
2321
return withTiming(cursorShown.value ? 1 : 0, { duration: 200 });
2422
});
2523

24+
const msftX = useSharedValue(0);
25+
const msftY = useSharedValue(0);
26+
const aaplX = useSharedValue(0);
27+
const aaplY = useSharedValue(0);
28+
const nvdaX = useSharedValue(0);
29+
const nvdaY = useSharedValue(0);
30+
const unityX = useSharedValue(0);
31+
const unityY = useSharedValue(0);
32+
2633
return (
2734
<ScrollView
2835
style={styles.container}
@@ -40,18 +47,27 @@ export default () => {
4047
isStatic={false}
4148
points={priceMap}
4249
style={styles.chart}
43-
// ExtraCanvasElements={
44-
// <>
45-
// <Group color="blue" opacity={opacity}>
46-
// <Circle cx={x} cy={y} r={10} />
47-
// </Group>
48-
// </>
49-
// }
50+
ExtraCanvasElements={
51+
<>
52+
<Group opacity={opacity}>
53+
<Circle cx={msftX} cy={msftY} r={4} color="purple" />
54+
<Circle cx={aaplX} cy={aaplY} r={4} color="green" />
55+
<Circle cx={nvdaX} cy={nvdaY} r={4} color="black" />
56+
<Circle cx={unityX} cy={unityY} r={4} color="orange" />
57+
</Group>
58+
</>
59+
}
5060
onPanGestureBegin={(payload) => {
5161
"worklet";
5262
cursorShown.value = true;
53-
x.value = payload.event.x;
54-
y.value = payload.event.y;
63+
msftX.value = payload.points.msft.x;
64+
msftY.value = payload.points.msft.y;
65+
aaplX.value = payload.points.aapl.x;
66+
aaplY.value = payload.points.aapl.y;
67+
nvdaX.value = payload.points.nvda.x;
68+
nvdaY.value = payload.points.nvda.y;
69+
unityX.value = payload.points.unity.x;
70+
unityY.value = payload.points.unity.y;
5571
runOnJS(gestureStartImpact)();
5672
}}
5773
onPanGestureEnd={() => {
@@ -60,8 +76,14 @@ export default () => {
6076
}}
6177
onPanGestureChange={(payload) => {
6278
"worklet";
63-
x.value = payload.event.x;
64-
y.value = payload.event.y;
79+
msftX.value = payload.points.msft.x;
80+
msftY.value = payload.points.msft.y;
81+
aaplX.value = payload.points.aapl.x;
82+
aaplY.value = payload.points.aapl.y;
83+
nvdaX.value = payload.points.nvda.x;
84+
nvdaY.value = payload.points.nvda.y;
85+
unityX.value = payload.points.unity.x;
86+
unityY.value = payload.points.unity.y;
6587
}}
6688
>
6789
{(args) => (

0 commit comments

Comments
 (0)