Skip to content

Instantly share code, notes, and snippets.

@EHakobyan
Created January 12, 2018 12:01
Show Gist options
  • Save EHakobyan/0d72343c3e3615b6fbe9def9b0d8a027 to your computer and use it in GitHub Desktop.
Save EHakobyan/0d72343c3e3615b6fbe9def9b0d8a027 to your computer and use it in GitHub Desktop.
import React, {Component} from 'react';
import {
TouchableOpacity,
Text,
View,
Image,
Animated,
PanResponder,
StyleSheet,
ScrollView,
Dimensions
} from 'react-native';
import PropTypes from 'prop-types';
import R from 'ramda';
import {get} from "../../../Services/requests";
import {commonUrl, publicApiEndPoints} from "../../../Config/config";
import FastImage from "react-native-fast-image";
//import styles from "./Styles/CreatorStyles";
const getTouches = (event) => event.nativeEvent.touches;
const pow2abs = (a, b) => Math.pow(Math.abs(a - b), 2);
const isMultiTouch = (event) => {
const currentTouches = getTouches(event);
return currentTouches.length > 1;
};
const getScale = (event, styles, diffDistance) => {
const {transform = []} = styles;
const currentScale = transform
.map((style) => style.scale)
.reduce((a, b) => b || a, 1);
const newScale = currentScale - (diffDistance / 400);
return newScale;
};
const distance = (touches) => {
const a = touches[0];
const b = touches[1];
if (touches.length === 1) {
return false;
}
return Math.sqrt(
pow2abs(a.pageX, b.pageX) +
pow2abs(a.pageY, b.pageY),
2);
};
class Draggable extends Component {
static defaultProps = {
children: {},
// Behavior
scalable: true || {
min: 0.33,
max: 2,
},
// Styles
styles: {
left: 0,
top: 0,
transform: [
{rotate: '0deg'},
{scale: 1},
],
},
// Callbacks
onStart: () => {
},
onChange: () => {
},
onRelease: () => {
},
}
constructor(props) {
super(props);
this.state = {
showDraggable: true,
dropAreaValues: null,
numberOfTouches: 0,
outfitItemXY: {x: 0, y: 0},
drag: false,
pan: new Animated.ValueXY(),
scale: new Animated.Value(1),
styles: {
...Draggable.defaultProps.styles,
...this.props.styles,
},
};
}
componentWillMount() {
this._val = {x: 0, y: 0};
this.state.pan.addListener((value) => this._val = value);
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderTerminationRequest: () => false,
onPanResponderGrant:this.onMoveStart,
onPanResponderMove: Animated.event([
null, {dx: this.state.pan.x, dy: this.state.pan.y},
], {
listener: this.onMove
}),
onPanResponderRelease: this.onMoveEnd,
onMoveShouldSetPanResponderCapture: (event, {dx, dy}) =>
dx !== 0 && dy !== 0,
});
}
onMoveStart = (e, pos) => {
// console.log(pos);
// console.log(pos.moveX,pos.moveY)
this.setState({
outfitItemXY: {x: pos.moveX, y: pos.moveY},
numberOfTouches: e.nativeEvent.touches.length,
createNew: true
});
// this.refs.test.measureInWindow((x,y) => {
// console.log(x,y)
// })
this.refs.view = this.view
// let copy = React.createElement(View, [], [this.refs.view,this.refs.image]);
// this.clone = React.cloneElement(this.refs.test,...this.view.props);
// this.setState({copy:copy})
this.state.pan.setOffset({x: this.state.pan.x._value, y: this.state.pan.y._value});
this.state.pan.setValue({x: 0, y: 0});
const {styles} = this.state;
const {onStart} = this.props;
this.prevAngle = 0;
this.prevDistance = 0;
this.initialTouchesAngle = 0;
this.pinchStyles = {};
this.initialTouches = getTouches(e);
this.initialStyles = styles;
onStart(e, styles);
this.props.changeScrollState(false)
}
onMove = (e, gestureState) => {
const {styles} = this.state;
const {onChange} = this.props;
const {initialTouches} = this;
const newTouches = getTouches(e);
if (newTouches.length !== initialTouches.length) {
this.initialTouches = newTouches;
} else {
this.onDrag(e, gestureState);
this.onPinch(e);
}
this.updateStyles();
onChange(e, styles);
}
onMoveEnd = (e, pos) => {
// console.log(pos,pos.moveX,'movex',pos.moveY,'movey')
// console.log(pos.vx,'dx',pos.vy,'dy');
this.setState({outfitItemXY: {x: pos.moveX, y: pos.moveY}});
this.state.pan.flattenOffset();
this.setState({pinch: false})
this.props.changeScrollState(true)
const {onRelease} = this.props;
const {styles} = this.state;
onRelease(e, styles);
}
onScale = (event) => {
this.setState({pinch: true})
const {scalable} = this.props;
const {styles} = this.state;
const {initialTouches} = this;
const isObject = R.is(Object, scalable);
if (isObject || scalable) {
const currentDistance = distance(getTouches(event));
const initialDistance = distance(initialTouches);
const increasedDistance = currentDistance - initialDistance;
const diffDistance = this.prevDistance - increasedDistance;
const min = isObject ? scalable.min : 0.33;
const max = isObject ? scalable.max : 4;
const scale = Math.min(Math.max(getScale(event, styles, diffDistance), min), max);
Animated.spring(
this.state.scale,
{toValue: scale}
).start();
this.pinchStyles.transform.push({scale});
this.prevDistance = increasedDistance;
}
}
onPinch = (event) => {
if (isMultiTouch(event)) {
this.pinchStyles = {transform: []};
this.onScale(event);
}
}
updateStyles = () => {
const styles = {
...this.state.styles,
...this.dragStyles,
...this.pinchStyles,
};
this.updateNativeStyles(styles);
this.setState({styles});
}
updateNativeStyles = (styles) => {
this.view.setNativeProps({styles});
}
isDropArea(gesture) {
return gesture.moveY < 200;
}
onDrag = (event, gestureState) => {
const {initialStyles} = this;
const {draggable} = this.props;
const isObject = R.is(Object, draggable);
const left = (isObject ? draggable.x : draggable)
? initialStyles.left + gestureState.dx
: initialStyles.left;
const top = (isObject ? draggable.y : draggable)
? initialStyles.top + gestureState.dy
: initialStyles.top;
this.dragStyles = {left, top};
}
renderItem = () => {
let {pan, scale} = this.state;
let [translateX, translateY] = [pan.x, pan.y];
const panStyle = {
transform: [{translateX}, {translateY}, {scale}]
}
let {x, y} = this.state.outfitItemXY;
let width = Dimensions.get(window).width;
return (
<View style={{position: "relative"}}>
<Animated.View
{...this.panResponder.panHandlers}
style={panStyle}
ref={(c) => {
this.view = c;
}}
>
<FastImage
ref='image'
source={{uri: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ_0rehWRYXOeNtg21oCnbVVdcbosufF8DUJZSMMAGKMNPMeNjyRg'}}
style={{height: 250, width: width / 4}}
resizeMode={FastImage.resizeMode.cover}
/>
</Animated.View>
</View>
)
}
render() {
return (
<TouchableOpacity activeOpacity={.9} onLongPress={() => this.setState({drag: true})} ref='test'
style={{alignItems: "center"}}>
{this.renderDraggable()}
</TouchableOpacity>
);
}
renderDraggable(x, y) {
let {pan, scale} = this.state;
let [translateX, translateY] = [pan.x, pan.y];
const panStyle = {
transform: [{translateX}, {translateY}, {scale}]
}
if (this.state.showDraggable) {
return (
<View style={{position: "relative"}}>
<Animated.View
{...this.panResponder.panHandlers}
style={panStyle}
ref={(c) => {
this.view = c;
}}
>
{this.props.data.item_images[0] &&
<FastImage
ref='image'
source={{uri: commonUrl + this.props.data.item_images[0].photothumb}}
style={{height: 100, width: 100}}
resizeMode={FastImage.resizeMode.contain}
/>
}
</Animated.View>
{this.state.createNew && this.state.copy}
</View>
);
}
}
}
export default class DropContainer extends Component {
constructor() {
super();
this.state = {
draggable: false,
scrollEnabled: true,
data: []
}
}
changedScrollState = (scrollEnabled) => {
this.setState({scrollEnabled})
}
componentDidMount() {
get(`${publicApiEndPoints.getProductCategory}220/?page=0`, null, data => {
data = Object.values(data);
data.splice(data.length - 1, 1);
this.setState({data});
console.log(data, "dataa")
})
}
render() {
return (
<View style={styles.mainContainer}>
<View style={styles.dropZone}>
</View>
<ScrollView
contentContainerStyle={styles.row}
horizontal={true}
showsHorizontalScrollIndicator={false}
scrollEnabled={this.state.scrollEnabled}
>
<View style={styles.items}>
{this.state.data.map((item, index) => {
return (
<Draggable
data={item}
key={index}
changeScrollState={this.changedScrollState}
draggable={false}
/>
)
})
}
</View>
</ScrollView>
</View>
);
}
}
const {width, height} = Dimensions.get('window')
const styles = StyleSheet.create({
mainContainer: {
width: '100%'
},
ballContainer: {
height: 200,
},
row: {
height: height - width,
flexDirection: 'column',
marginTop: width
},
dropZone: {
position: 'absolute',
height: width,
width: width,
backgroundColor: "#00334d"
},
items: {
height: 250,
flexDirection: 'row'
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment