Spinner wheel
Discount spinner
<Script runBeforeMount={true} :as="animation"> const offers = [ { label: '10% OFF', color: 'red' }, { label: '10% OFF', color: 'red' }, { label: '10% OFF', color: 'red' }, { label: '10% OFF', color: 'red' }, { label: '20% OFF', color: 'maroon' }, { label: '30% OFF', color: 'blue' }, { label: '40% OFF', color: 'purple' }, { label: '50% OFF', color: 'green' }, { label: 'Try Again', color: 'red' } ] setStates({ isInteracted: false, isSpinning: false, offers, selectedOffer: null, finalSegment: null }) const rotation = new Animated.Value(0) const segmentCount = offers.length const segmentAngle = 360 / segmentCount const style = { transform: [{ rotate: rotation.interpolate({ inputRange: [0, 360], outputRange: ['0deg', '360deg'] }) }] } </Script> <Script :dependencies={[animation, state.isSpinning]} :as="actions"> function startWheel() { if (state.isSpinning) return setState('isSpinning', true) setState('isInteracted', true) const spin = Animated.loop( Animated.sequence([ Animated.timing(animation.rotation, { toValue: 360, duration: 1500, easing: rn.Easing.linear, useNativeDriver: true }), Animated.timing(animation.rotation, { toValue: 0, duration: 0, useNativeDriver: true }) ]), { iterations: Infinity } ) spin.start() } function stopWheel() { if (!state.isSpinning) return setState('isSpinning', false) if (animation.spin) { animation.spin.stop() } animation.rotation.stopAnimation(currentValue => { const currentRotation = currentValue % 360 const finalIndex = Math.floor(Math.random() * animation.segmentCount) const desiredRotation = 360 - (finalIndex * animation.segmentAngle + animation.segmentAngle / 2) let delta = desiredRotation - currentRotation if (delta < 0) delta += 360 delta += 360 * 3 const targetRotation = currentValue + delta Animated.timing(animation.rotation, { toValue: targetRotation, duration: 5000, easing: rn.Easing.out(rn.Easing.quad), useNativeDriver: true }).start(() => { setState('selectedOffer', state.offers[finalIndex].label) setState('finalSegment', finalIndex) }) }) } </Script> <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <View style={{ width: 300, height: 300, position: 'relative' }}> <AnimatedView style={[ { position: 'absolute', top: 10, left: 10, width: 280, height: 280, borderRadius: 140, backgroundColor: 'orange', overflow: 'hidden', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.3, shadowRadius: 3 }, animation.style ]}> <Fragment :forEach={state.offers} :as="offer"> <View style={{ position: 'absolute', left: 140, top: 140 - 10, width: 140, height: 20 }}> <AnimatedView style={{ width: '100%', height: '100%', transform: [ { translateX: -70 }, { rotate: ((data.offerIndex * animation.segmentAngle + animation.segmentAngle / 2) - 90) + 'deg' }, { translateX: 70 } ], backgroundColor: "white", justifyContent: 'center' }}> <Text py={4} style={{ width: '100%', color: offer.color, fontWeight: 'bold', fontSize: 12, textAlign: 'center' }}> {offer.label} </Text> </AnimatedView> </View> </Fragment> </AnimatedView> <Text style={{ position: 'absolute', top: 0, left: "50%", transform: [{ translateX: -15 }], fontSize: 20, fontWeight: 'bold' }}> <Icon icon="fontisto:caret-down" color="success" /> </Text> </View> <View style={{ flexDirection: 'row', marginTop: 30 }}> <Button action={actions.startWheel} disabled={state.isSpinning || state.isInteracted} style={{ marginHorizontal: 10, paddingVertical: 12, paddingHorizontal: 24, borderRadius: 24 }} > <Text style={{ color: '#fff', fontSize: 16 }}>START</Text> </Button> <Button action={actions.stopWheel} disabled={!state.isSpinning} color="danger" style={{ marginHorizontal: 10, paddingVertical: 12, paddingHorizontal: 24, borderRadius: 24 }} > <Text style={{ color: '#fff', fontSize: 16 }}>STOP</Text> </Button> </View> <Text :if={state.selectedOffer} style={{ marginTop: 20, fontSize: 18, fontWeight: 'bold', color: '#333' }}> You won: {state.selectedOffer} </Text> </View>
{}
Loading...