start to work with spin game

This commit is contained in:
u-e 2019-08-06 10:55:50 +03:00
parent 32555b803b
commit 323d688a47
8 changed files with 324 additions and 4 deletions

View File

@ -10,6 +10,7 @@ import { TextInput } from './textInput';
import ScaleSlider from './scaleSlider/scaleSliderView'; import ScaleSlider from './scaleSlider/scaleSliderView';
import UserListItem from './basicUIElements/view/userListItem/userListItem'; import UserListItem from './basicUIElements/view/userListItem/userListItem';
import PostButton from './postButton/postButtonView'; import PostButton from './postButton/postButtonView';
import SpinGame from './spinGame/view/spinGameView';
export { export {
CircularButton, CircularButton,
@ -17,6 +18,7 @@ export {
Icon, Icon,
IconButton, IconButton,
Logo, Logo,
SpinGame,
Modal, Modal,
NumericKeyboard, NumericKeyboard,
PinAnimatedInput, PinAnimatedInput,

View File

@ -0,0 +1,56 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
class RouletteItem extends Component {
constructor(props) {
super(props);
this.state = {
coordX: props.radius,
coordY: props.radius,
};
}
getCoordinates({ width, height }) {
const { radius, index, step, distance } = this.props;
const coordX = Math.round(
radius / 2 + distance * -Math.sin(index * step - Math.PI) - width / 2,
);
const coordY = Math.round(
radius / 2 + distance * Math.cos(index * step - Math.PI) - height / 2,
);
this.setState({ coordX, coordY });
}
render() {
const { item, rouletteRotate } = this.props;
const { coordX, coordY } = this.state;
return (
<View
style={{
position: 'absolute',
left: coordX,
top: coordY,
transform: [{ rotate: `${-rouletteRotate}deg` }],
}}
onLayout={event => this.getCoordinates(event.nativeEvent.layout)}
>
{item}
</View>
);
}
}
RouletteItem.propTypes = {
step: PropTypes.number,
index: PropTypes.number,
radius: PropTypes.number,
distance: PropTypes.number,
rouletteRotate: PropTypes.number,
item: PropTypes.element.isRequired,
};
export default RouletteItem;

View File

@ -1 +1,169 @@
// import React, { Component, Children } from 'react';
import { View, Animated, PanResponder, Easing, ImageBackground, Image } from 'react-native';
import RouletteItem from './rouletteItem';
import styles from './styles';
class Roulette extends Component {
constructor(props) {
super(props);
this.state = {
_animatedValue: new Animated.Value(0),
activeItem: 0,
};
this.step = props.step || (2 * Math.PI) / props.options.length;
this.panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderRelease: () => {
const { enableUserRotate } = this.props;
if (enableUserRotate) this.triggerSpin();
},
});
}
triggerSpin(spinToIndex) {
const { options, turns, onRotate, onRotateChange, duration, easing } = this.props;
const { activeItem } = this.state;
const randomSelected = Math.floor(Math.random() * options.length);
const selectedIndex = spinToIndex != null ? spinToIndex : randomSelected;
const turnsMultiplier = options.length * turns;
const nextItem = selectedIndex + turnsMultiplier;
this.state._animatedValue.setValue(activeItem);
const animation = Animated.timing(this.state._animatedValue, {
toValue: nextItem,
easing,
duration,
});
if (onRotateChange) onRotateChange('start');
animation.start(() => {
if (onRotateChange) onRotateChange('stop');
});
let newActiveItem = nextItem > options.length ? nextItem % options.length : nextItem;
if (newActiveItem == 0) {
newActiveItem = options.length;
}
this.setState(
{ activeItem: newActiveItem },
() => onRotate && onRotate(options[options.length - newActiveItem]),
);
}
render() {
const {
options,
radius,
distance,
customStyle,
rouletteRotate,
background,
marker,
centerImage,
markerWidth,
markerTop,
centerWidth,
centerTop,
markerStyle,
centerStyle,
rotateEachElement,
} = this.props;
const interpolatedRotateAnimation = this.state._animatedValue.interpolate({
inputRange: [0, options.length],
outputRange: [`${rouletteRotate}deg`, `${360 + rouletteRotate}deg`],
});
const displayOptions =
options && options.length > 0 && options[0] && React.isValidElement(options[0]);
return (
<View>
<Animated.View
{...this.panResponder.panHandlers}
style={[
styles.container,
{ width: radius, height: radius, borderRadius: radius / 2 },
{ transform: [{ rotate: interpolatedRotateAnimation }] },
customStyle,
]}
>
<ImageBackground
width={radius}
height={radius}
style={{ width: radius, height: radius, zIndex: 100 }}
source={background}
>
{displayOptions &&
Children.map(options, (child, index) => (
<RouletteItem
item={child}
index={index}
radius={radius}
step={this.step}
distance={distance}
rouletteRotate={rotateEachElement(index)}
/>
))}
</ImageBackground>
</Animated.View>
<Image
source={marker}
resizeMode="contain"
style={[
styles.marker,
{
zIndex: 9999,
top: markerTop,
width: markerWidth,
left: radius / 2 - markerWidth / 2,
},
markerStyle,
]}
/>
{centerImage && (
<Image
source={centerImage}
resizeMode="contain"
style={[
styles.marker,
{
zIndex: 9999,
top: centerTop,
width: centerWidth,
left: radius / 2 - centerWidth / 2,
},
centerStyle,
]}
/>
)}
</View>
);
}
}
Roulette.defaultProps = {
radius: 300,
distance: 100,
rouletteRotate: 0,
enableUserRotate: false,
background: null,
turns: 5,
rotateEachElement: index => 0,
// onRotate: () => {},
// onRotateChange: () => {},
duration: 3500,
easing: Easing.inOut(Easing.ease),
markerTop: 0,
markerWidth: 20,
centerWidth: 20,
centerTop: 0,
centerImage: null,
markerStyle: {},
};
export default Roulette;

View File

@ -0,0 +1,13 @@
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
},
marker: {
position: 'absolute',
},
});
export default styles;

View File

@ -2,12 +2,14 @@ import React, { PureComponent, Fragment } from 'react';
import { injectIntl } from 'react-intl'; import { injectIntl } from 'react-intl';
import { View, Text } from 'react-native'; import { View, Text } from 'react-native';
import get from 'lodash/get'; import get from 'lodash/get';
import wheel from './wheel.png';
import marker from './marker.png';
// Container // Container
import { PointsContainer } from '../../../containers'; import { PointsContainer } from '../../../containers';
// Components // Components
import { BasicHeader } from '../../../components/basicHeader'; import { BasicHeader } from '../../../components/basicHeader';
import { SpinGame } from '../../../components';
// Styles // Styles
import styles from './freeEstmStyles'; import styles from './freeEstmStyles';
@ -20,19 +22,98 @@ class FreeEstmScreen extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {}; this.state = {
rouletteState: '',
option: '',
rouletteCustomState: 'stop',
optionCustom: '',
};
}
_onRotateChange(state) {
this.setState({
rouletteState: state,
});
}
_onRotate(option) {
this.setState({
option: option.index,
});
}
_onRotateCustomChange(state) {
// this.setState({
// rouletteCustomState: state,
// });
}
_onRotateCustom(option) {
this.setState({
optionCustom: option.props.index,
});
} }
render() { render() {
const { intl } = this.props; const { intl } = this.props;
const numbers = [
100,
320,
150,
192,
43,
213,
23,
235,
137,
334,
633,
273,
133,
363,
113,
303,
83,
233,
130,
53,
234,
136,
33,
];
const options = numbers.map(o => ({ index: o }));
const { rouletteCustomState, rouletteState, option, optionCustom } = this.state;
// const options = numbers.map(o => ({ index: o }));
const customOptions = numbers.map(o => <Text index={o}>{o}</Text>);
return ( return (
<PointsContainer> <PointsContainer>
{({ isLoading, balance: _balance }) => ( {({ isLoading, balance: _balance }) => (
<Fragment> <Fragment>
<BasicHeader title={intl.formatMessage({ id: 'free_estm.title' })} /> <BasicHeader title={intl.formatMessage({ id: 'free_estm.title' })} />
<View style={styles.container}> <View style={styles.container}>
<Text>free esteem</Text> <Text>{rouletteState}</Text>
<Text>{option}</Text>
<Text>{optionCustom}</Text>
<SpinGame
enableUserRotate={rouletteCustomState === 'stop'}
background={null}
onRotate={_option =>
this.setState({
optionCustom: _option.props.index,
})
}
onRotateChange={state =>
this.setState({
rouletteCustomState: state,
})
}
marker={marker}
options={customOptions}
rotateEachElement={index => ((index * 360) / options.length) * -1 - 90}
markerWidth={20}
/>
</View> </View>
</Fragment> </Fragment>
)} )}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB