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...