Spinning a wheel of fortune with a predetermined rotation value

Issue

My goal is to (upon clicking a button) spin a wheel multiple times, then end on a specific rotation value (0…360) while easing out the animation. I can currently ‘smoothly’ spin to a specific point on the wheel without any full revolutions. My problem is trying to spin the wheel multiple times and then landing on a specific point to make it look more realistic. Is this achievable with the CSS animaton property or anything else?

Here is my code…

const wheelEl = document.getElementById("wheel");
const sliceSize = 360 / 3;

function spinWheel(index) {
    // Reset animation
    wheelEl.style.transition = "none";
    wheelEl.style.transform = "rotate(0deg)";

    // Play animation on the next frame
    setTimeout(() => {
        wheelEl.style.transition = "all ease 1s";
        
        // Target rotation margin
        let rotMin = (sliceSize * (index))+(sliceSize/15);
        let rotMax = (sliceSize * (index + 1))-(sliceSize/15);
        
        // Target rotation
        let rot = Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);

        wheelEl.style.transform = `rotate(-${rot}deg)`;
    }, 0);
}
#container {
  position: absolute;
  
  text-align: center;
}

#arrow {
    position: absolute;
    top: -5px;
    left: 50%;
    transform: translateX(-50%);

    border-top: 10px solid black;
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;

    z-index: 1;
}

#wheel {
    width: 100px;
    height: 100px;

    border-radius: 50%;
    background-image: conic-gradient(lightpink 0 120deg, lightblue 0 240deg, lightsalmon 0 360deg);
}
<div id="container">
  <div id="arrow"></div>
  <div id="wheel"></div>
  <br />
  <button onclick="spinWheel(2)">Spin wheel</button>
</div>

Solution

You can stick to using transform.

This snippet does two things: adds a random (within bounds) number of 360 degrees to the rotation value and sets the easing function to ease-out so that the rotation slows down towards the end only.

So that the effect can be seen, the time of the full rotation is set to 5 seconds but of course alter this to whatever you want. You could for example make that random within some bounds too if desired.

You could also play with the Beziere function that represents ease-out if say you wanted a longer stretch of it seeming to slow down.

const wheelEl = document.getElementById("wheel");
const sliceSize = 360 / 3;

function spinWheel(index) {
  // Reset animation
  wheelEl.style.transition = "none";
  wheelEl.style.transform = "rotate(0deg)";

  // Play animation on the next frame
  setTimeout(() => {
    wheelEl.style.transition = "all ease-out 5s";

    // Target rotation margin
    const rotMin = (sliceSize * (index)) + (sliceSize / 15);
    const rotMax = (sliceSize * (index + 1)) - (sliceSize / 15);

    // Target rotation
    const fullRots = Math.floor(Math.random() * 5) + 5; // minimum 5 rotations max 9

    const rot = (fullRots * 360) + Math.floor(Math.random() * (rotMax - rotMin + 1) + rotMin);

    wheelEl.style.transform = `rotate(-${rot}deg)`;
  }, 0);
}
#container {
  position: absolute;
  text-align: center;
}

#arrow {
  position: absolute;
  top: -5px;
  left: 50%;
  transform: translateX(-50%);
  border-top: 10px solid black;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  z-index: 1;
}

#wheel {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-image: conic-gradient(lightpink 0 120deg, lightblue 0 240deg, lightsalmon 0 360deg);
}
<div id="container">
  <div id="arrow"></div>
  <div id="wheel"></div>
  <br />
  <button onclick="spinWheel(2)">Spin wheel</button>
</div>

Answered By – A Haworth

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published