Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

What the ...., thousands of lines of code? #84

Open
ChiragMDave opened this issue Sep 3, 2021 · 16 comments
Open

What the ...., thousands of lines of code? #84

ChiragMDave opened this issue Sep 3, 2021 · 16 comments

Comments

@ChiragMDave
Copy link

These guys have written thousands of lines of code for what can be achieved by writing just 50 lines. Including zooming in/out from lastScale and pan moving from lastOffsets using PanGestureHandler, PinchGestureHandler, State.

@joaogabrieldasilva
Copy link

@ChiragMDave ok, but why haven't you done this and shared with us yet?

@ChiragMDave
Copy link
Author

@ChiragMDave ok, but why haven't you done this and shared with us yet?

import React from 'react';
import { Alert, Animated, Easing, View } from 'react-native';
import { PanGestureHandler, PinchGestureHandler, State } from 'react-native-gesture-handler';
import { PressBox } from './PressBox';

const IMAGEWIDTH = 250; const IMAGEHEIGHT = 400;
export default class PinchableBox extends React.Component {
constructor(props) {
super(props);

	this._translateXY = new Animated.ValueXY({ x: 0, y: 0 });
	this._baseScale = new Animated.Value(1);
	this._pinchScale = new Animated.Value(1);
	this._scale = Animated.multiply(this._baseScale, this._pinchScale);
	this._lastScale = 1;

	this._onPanGestureEvent = Animated.event([{ nativeEvent: { translationX: this._translateXY.x, translationY: this._translateXY.y, } }], {
		useNativeDriver: true,
	});

	this._onPanHandlerStateChange = (event) => {
		if (event.nativeEvent.oldState === State.ACTIVE) {
			this._translateXY.extractOffset();
		}
	}

	this._onPinchGestureEvent = Animated.event([{ nativeEvent: { scale: this._pinchScale } }], {
		useNativeDriver: false
	});

	this._onPinchHandlerStateChange = (event) => {
		if (event.nativeEvent.oldState === State.ACTIVE) {
			this._lastScale *= event.nativeEvent.scale;
			this._baseScale.setValue(this._lastScale);
			this._pinchScale.setValue(1);
		}
	};
}

_onDoubleTap = ref => {
	this._translateXY.flattenOffset();
	this._pinchScale.flattenOffset(); this._baseScale.flattenOffset();
	Animated.parallel([
		Animated.spring(
			this._translateXY,
			{ toValue: { x: 0, y: 0 }, friction: 5, useNativeDriver: true }
		),
		Animated.spring(
			this._pinchScale,
			{ toValue: 1, friction: 5, useNativeDriver: true }
		),
		Animated.spring(
			this._baseScale,
			{ toValue: 1, friction: 5, useNativeDriver: true }
		),
	]).start(() => this._lastScale = 1);
};

doubleTapRef = React.createRef();

render() {
	return (
		<PressBox ref={this.doubleTapRef} onDoubleTap={this._onDoubleTap}>
			<PinchGestureHandler
				onGestureEvent={this._onPinchGestureEvent}
				onHandlerStateChange={this._onPinchHandlerStateChange}>
			        <View style={{ flex: 1, alignSelf: 'stretch', justifyContent: 'center', }} collapsable={false}>
				        <PanGestureHandler onBegan={this._onBegan}
					        onGestureEvent={this._onPanGestureEvent}
					        onHandlerStateChange={this._onPanHandlerStateChange}
				        >
					        <Animated.Image
						        source={{ uri: this.props.imageUri }}
						        style={[
							        {
								        alignSelf: 'center',
								        height: this.props.imageHeight ? this.props.imageHeight :IMAGEHEIGHT, 
								        width: this.props.imageWidth ? this.props.imageWidth : IMAGEWIDTH,
								        transform: [
									        { perspective: 200 },
									        { scale: this._scale },
									        { translateX: this._translateXY.x },
									        { translateY: this._translateXY.y },
								        ],
							        },
						        ]}
					        />
				        </PanGestureHandler>
			        </View>
			</PinchGestureHandler>
		</PressBox>
	);
}

}

@elliottkember
Copy link

@ChiragMDave I tried your code - nice work! Here are a few little things I noticed:

  1. The pinch-zoom scales from the centre of the viewport, instead of from the centre of the pinch gesture.
  2. No bounding - the image can be dragged completely out of view
  3. No easing, or spring animations that I could see.

I'm sure these can be achieved in less code than used in this repo, but I wanted to point out that there are a few other features implemented here.

@vbylen
Copy link

vbylen commented Nov 23, 2021

@elliottkember can we write code with the same brevity that addresses your concerns?

Update: checkout this code https://github.com/enzomanuelmangano/animate-with-reanimated/blob/main/04-pinch-gesture-handler-basics/App.tsx

@elliottkember
Copy link

elliottkember commented Dec 9, 2021

@10000multiplier That example's great! The react-native-reanimated and react-native-gesture-handler libraries have some features that would simplify all this calculation a lot. This library has been around since 2018 - I'm sure there have been some new features since then that we can use.

Would you like to draft up a PR to @openspacelabs/react-native-zoomable-view and we can work on the implementation? It will be quite a big refactor, but I think it would be great to work towards it.

@vbylen
Copy link

vbylen commented Dec 9, 2021

@elliottkember indeed, v2 of react-native-gesture-handler just came out with a rewrite of the old API!

You may want to get familiar with some of the examples: https://github.com/software-mansion/react-native-gesture-handler/tree/master/example/src/new_api.

I'm not in a position right now where I can put much time in this, but in the future I'd be glad to help out with a PR if needed!

@elliottkember
Copy link

@elliottkember indeed, v2 of react-native-gesture-handler just came out with a rewrite of the old API!

You may want to get familiar with some of the examples: https://github.com/software-mansion/react-native-gesture-handler/tree/master/example/src/new_api.

I'm not in a position right now where I can put much time in this, but in the future I'd be glad to help out with a PR if needed!

Superb. I'll have a look at the new API soon, thank you for the link. It would be neat to aim for a simpler implementation of this component - it works well enough that there is no real rush, but it seems doable and a fun project.

My colleague Thomas did all the real work fixing bugs for our fork, I am just helping out with the handover.

@vbylen
Copy link

vbylen commented Jan 5, 2022

@elliottkember might want to check out this gist https://gist.githubusercontent.com/intergalacticspacehighway/9e931614199915cb4694209f12bf6f11/raw/dc67da12841d2e7e34b2e4f50a03953cffa86d76/PinchToZoom.tsx

It works great.

Hats off to @intergalacticspacehighway

@elliottkember
Copy link

@10000multiplier This is awesome. Super impressive work @intergalacticspacehighway!

As it turns out, we may have a need to implement this in a new version of the library. There are many benefits to react-native-gesture-handler. However it is likely we would have to start with the most basic features to begin with, so it may start with a much simpler API while we get going.

I'll update this thread when I have something more concrete to share, but if you are interested in helping with this, let me know!

@vbylen
Copy link

vbylen commented Jan 27, 2022

@elliottkember here's my updated version with the new API. Works like a charm on iOS, haven't tested it on Android.

https://gist.github.com/10000multiplier/264779c850e083ec3cb92eb8413559c0

@elliottkember
Copy link

@10000multiplier This is great! Unfortunately this doesn't solve the use-case where a user can zoom and pan the image like a map, which is how we use it. We're working through it but it's a difficult transform. It's important to be able to zoom the image in at the location the user is pinching.

@elliottkember
Copy link

@10000multiplier We've spent the last couple of days working this into a new version of the plugin. You can check it out in the V3 branch in our repo.

The new version has dependencies on react-native-reanimated and react-native-gesture-handler, but the code is very short. None of the configuration props are implemented yet, but it's quite functional and seems to be very performant. I will be testing it on a really old Android tablet when it arrives.

Big shout-out to @thomasttvo for doing all the math, I nearly broke my brain trying!

@vbylen
Copy link

vbylen commented Jan 29, 2022

@elliottkember @thomasttvo awesome job guys. Looks great.

@kesha-antonov
Copy link

Hi all,

I've made zoom package on reanimated & gesture-handler
Hope it could be useful for somebody: https://github.com/kesha-antonov/react-native-zoom-reanimated

1.mp4

@SimonErich
Copy link
Contributor

@kesha-antonov that's amazing.
I love it. As far as I can see it does not have all of the features and configurations of this package or @elliottkember s package, but it is still a very good alternative.

I have added it to the readme disclaimer.

As for the question in the title of this issue:
Yes, the code was written this way, because back then (when we first started this component - and even before we published it), there was no reanimated and a lot of other issues too.

Funny enough:
I already had a working prototype with reanimated1, when it came out.
It worked really well and was - performancewise - nice, but I lost the code with my harddrive.

To be honest, that was also what made me stop working on this package, because I was frustrated of losing all this progress of a complete rewrite and did not want to start again.
Especially, because we are not using react-native internally anymore and so there was no business case for us to work on it, apart from the love for Opensource.

I am glad though, that now with your 2 packages there are alternatives out there.

@kesha-antonov
Copy link

@kesha-antonov that's amazing.

I love it. As far as I can see it does not have all of the features and configurations of this package or @elliottkember s package, but it is still a very good alternative.

I have added it to the readme disclaimer.

As for the question in the title of this issue:

Yes, the code was written this way, because back then (when we first started this component - and even before we published it), there was no reanimated and a lot of other issues too.

Funny enough:

I already had a working prototype with reanimated1, when it came out.

It worked really well and was - performancewise - nice, but I lost the code with my harddrive.

To be honest, that was also what made me stop working on this package, because I was frustrated of losing all this progress of a complete rewrite and did not want to start again.

Especially, because we are not using react-native internally anymore and so there was no business case for us to work on it, apart from the love for Opensource.

I am glad though, that now with your 2 packages there are alternatives out there.

Thanks man!

Yeah, sad story with that hard drive)

I also wrote my package internally almost a year ago I think. But was busy with other stuff, and now I've found time to open source that finally)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants