I built a pinch to zoom effect using react-native-gesture-handler and react-native-reanimated. The user can pinch anywhere on the image and zoom in or out with the position between the fingers as the zoom origin. This is great. What I am having trouble with is in allowing the user to zoom in or out in multiple pinch gestures. This requires remembering the offsets and zoom scale from the user's prior pinch gesture. With the code I currently have, when a user pinches a second time, the gesture handler remembers the zoom scale value from the first pinch gesture, does not update the zoom origin properly. How can I fix this without increasing the number of transform statements?
const prevZoomScale = useSharedValue(1)
const currZoomScale = useSharedValue(1)
const zoomScale = useDerivedValue(() => { return prevZoomScale.value * currZoomScale.value }, [prevZoomScale.value, currZoomScale.value])
const tempZoomScale = useSharedValue(1)
const prevOriginOffset = useSharedValue({x: 0, y: 0})
const tempOriginOffset = useSharedValue({x: 0, y: 0})
const currOriginOffset = useSharedValue({x: 0, y: 0})
const pinchOriginOffset = useDerivedValue(() =>
{
return {
x: (prevOriginOffset.value.x + currOriginOffset.value.x),
y: (prevOriginOffset.value.y + currOriginOffset.value.y)
}
},
[prevOriginOffset.value.x, prevOriginOffset.value.y, currOriginOffset.value.x, currOriginOffset.value.y]
)
const onPinchEvent = useAnimatedGestureHandler<PinchGestureHandlerGestureEvent>({
onStart: (_) => {
prevZoomScale.value = tempZoomScale.value
currZoomScale.value = 1
prevOriginOffset.value = tempOriginOffset.value
currOriginOffset.value = {x: _.focalX - SIZE / 2, y: _.focalY - SIZE / 2}
},
onActive: (event) => {
if ((event.scale * prevZoomScale.value) > 1) {
currZoomScale.value = event.scale
}
},
onEnd: (_) => {
tempZoomScale.value = zoomScale.value
tempOriginOffset.value = pinchOriginOffset.value
},
const animatedStyle = useAnimatedStyle(
() => ({
transform: [
{
translateX: (pinchOriginOffset.value.x)
},
{
translateY: (pinchOriginOffset.value.y)
},
{
scale: zoomScale.value
},
{
translateX: - (pinchOriginOffset.value.x)
},
{
translateY: - ( pinchOriginOffset.value.y)
}
],
}),
[]
)
return (
<View style={[styles.zoomScrollContainer, { backgroundColor: color.core.black }]}>
<PinchGestureHandler
onGestureEvent={onPinchEvent}
>
<Animated.View >
<Animated.Image
source={{ uri: zoomedImageUri }}
style={[styles.imageStyle, animatedStyle]}
>
</Animated.Image>
</Animated.View>
</PinchGestureHandler>
</View>
)