Skip to content

Instantly share code, notes, and snippets.

@kmagiera
Created October 23, 2018 13:53
Show Gist options
  • Save kmagiera/476a43fdccc69e39863909262a367518 to your computer and use it in GitHub Desktop.
Save kmagiera/476a43fdccc69e39863909262a367518 to your computer and use it in GitHub Desktop.
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
const {
event,
Value,
cond,
add,
multiply,
eq,
startClock,
Clock,
set,
divide,
pow,
diff,
sub,
and,
abs,
lessThan,
greaterThan,
stopClock,
debug,
sqrt,
exp,
block,
} = Animated;
function spring(dt, position, velocity, anchor, mass = 1, tension = 300) {
const dist = sub(position, anchor);
const acc = divide(multiply(-1, tension, dist), mass);
return set(velocity, add(velocity, multiply(dt, acc)));
}
const DEFAULT_GRAVITY_STRENGTH = 400;
const DEFAULT_GRAVITY_FALLOF = 40;
function gravity(
dt,
position,
velocity,
anchor,
mass = 1,
strength = DEFAULT_GRAVITY_STRENGTH,
falloff = DEFAULT_GRAVITY_FALLOF
) {
const dx = sub(position, anchor);
const drsq = multiply(dx, dx);
const dr = sqrt(drsq);
const a = divide(
multiply(
-1,
strength,
dr,
exp(divide(multiply(-0.5, drsq), multiply(falloff, falloff)))
),
mass
);
const div = cond(dr, divide(a, dr), 0);
return set(velocity, add(velocity, multiply(dt, dx, div)));
// return set(velocity, [debug('gravity', div), 0]);
}
function damping(dt, velocity, mass = 1, damping = 12) {
const acc = divide(multiply(-1, damping, velocity), mass);
return set(velocity, add(velocity, multiply(dt, acc)));
}
function _interaction(clock, dt, drag, dragState) {
const dragging = new Value(0);
const start = new Value(0);
const x = new Value(0);
const vx = new Value(0);
const anchor = new Value(0);
const step = cond(
eq(dragState, State.ACTIVE),
[
cond(dragging, 0, [startClock(clock), set(dragging, 1), set(start, x)]),
set(anchor, add(start, drag)),
[springy(dt, x, vx, anchor), springy(dt, x, vx, 0), friction(dt, vx)],
],
[set(dragging, 0), springy(dt, x, vx, 0), friction(dt, vx)]
);
return block([step, set(x, add(x, multiply(vx, dt)))]);
}
const POSITION_THRESHOLD = 1;
const EPS = 1e-3;
const VELOCITY = 30;
function stopWhenNeeded(dt, position, velocity, clock) {
const ds = diff(position);
const noMovementFrames = new Value(0);
return cond(
lessThan(abs(ds), EPS),
[
set(noMovementFrames, add(noMovementFrames, 1)),
cond(greaterThan(noMovementFrames, 5), stopClock(clock)),
],
set(noMovementFrames, 0)
);
}
function force(dt, position, velocity) {
return set(velocity, cond(lessThan(position, 0), VELOCITY, -VELOCITY));
}
function interaction(gestureTranslation, gestureState) {
const dragging = new Value(0);
const start = new Value(0);
const position = new Value(0);
const anchor = new Value(0);
const velocity = new Value(0);
const clock = new Clock();
const dt = divide(diff(clock), 1000);
return cond(
eq(gestureState, State.ACTIVE),
[
cond(dragging, 0, [set(dragging, 1), set(start, position)]),
set(anchor, add(start, gestureTranslation)),
// spring attached to pan gesture "anchor"
spring(dt, position, velocity, anchor, 1, 100),
damping(dt, velocity),
// spring attached to the center position (0)
// spring(dt, position, velocity, 0),
// damping(dt, velocity),
set(position, add(position, multiply(velocity, dt))),
],
[
set(dragging, 0),
startClock(clock),
spring(dt, position, velocity, 0),
damping(dt, velocity),
set(position, add(position, multiply(velocity, dt))),
]
);
}
class Box extends Component {
constructor(props) {
super(props);
// const gesture = { x: new Value(0), y: new Value(0) };
const gestureX = new Value(0);
const state = new Value(-1);
this._onGestureEvent = event([
{
nativeEvent: {
translationX: gestureX,
state: state,
},
},
]);
const clock = new Clock();
const dt = divide(diff(clock), 1000);
this._transX = interaction(gestureX, state);
// this._transY = interaction(clock, dt, gesture.y, state);
}
render() {
return (
<PanGestureHandler
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onGestureEvent}>
<Animated.View
style={[
styles.box,
{
transform: [{ translateX: this._transX }],
},
]}
/>
</PanGestureHandler>
);
}
}
export default class Example extends Component {
render() {
return (
<View style={styles.container}>
<Box style={styles.box} />
</View>
);
}
}
const BOX_SIZE = 100;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
box: {
width: BOX_SIZE,
height: BOX_SIZE,
alignSelf: 'center',
backgroundColor: 'teal',
margin: BOX_SIZE / 2,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment