Creating a wheel of fortune

Check out the demo here to be excited about what you can build✨✨

A couple of weeks ago, I wanted to explore the magic of SVG✨ so I thought of creating a little sample of a wheel of fortune taking into account SVG collisions using GSAP since it’s a big deal in the SVG community, to make it more fun, I consumed an API that returns taco recipes to help you choose what kind of tacos to eat on taco Tuesday 🌮.

So let’s jump on this mini tutorial on how to build a wheel of fortune

The beginning of the project

Since I’m in love with vite, I usedvite create appto start a react app with vite under the hood to make it fast! besides that, I installed gsap, recharts (which I will explain in a minute), and react-uuid (to generate unique ids)

Creating the wheel

I tried to create the wheel using handcrafted SVG, but I kinda cheat on this part, I saw thisreally cool repothat does kinda what I want and decided to copy its wheel functionality usingrechartswhich is a react library for charts, so here’s the code of how I created the wheel (which is a pie chart but don’t tell anyone):

//we want fixed width and height to match the arrow position that we will be creating later
<PieChart width={400} height={400} style={{ margin: "0 auto" }}>
        /*this is an array of items with the next structure
          id: uuid(),
          name: sliceName,
          times: 1, // this is to indicate the value of the slice
          background: randomColorFunction,
        dataKey="times" // should match the 'times' key
        redraw={false} // to not recalculate the position of the slices after spinning
        {, index) => (
        <Cell key={`cell-${index}`} fill={el.background} />

now, the label on it has a function to render the actual text that is positioned inside the slice, we calculate the x and y coordinates to position the text, so that function looks something like this:

const renderCustomizedLabel = ({
  }) => {
    const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
    const x = cx + radius * Math.cos(-midAngle * RADIAN);
    const y = cy + radius * Math.sin(-midAngle * RADIAN);
    return (

after creating this component you should have something like this: wheel image

Making the wheel spin

to make the wheel spin, I use the next function which incorporates the magic of GSAP

let pos = 0;
async function rotate() {
    let x = randomNumber(1080, 1800); //between 4-6 wheel turns
    pos = pos + x;
    await".recharts-pie", // recharts automatically adds this class to the pie chart
      duration: 1,
      rotation: pos,
      transformOrigin: "50% 50%",
      ease: " power2. ease-in-out",

Adding an arrow to identify the winner

Now the fun part begins, after having the wheel spinning, we want to check which slice is the winner, to do that, I added alittle triangle created on cssand then I assign it an id of #arrow to it

then, to check the collision, I modified the rotate function defined before to check for the collision

const [winner, setWinner] = useState(undefined);
async function rotate() {
    let x = randomNumber(1080, 1800); //between 2-4 wheel turns
    pos = pos + x;
    await".recharts-pie", {
      duration: 1,
      rotation: pos,
      transformOrigin: "50% 50%",
      ease: " power2. ease-in-out",
    //get all the pie slices by the classname
    let pieSectors = document.getElementsByClassName("recharts-pie-sector");
    Array.from(pieSectors).forEach((sector, index) => {
        // iterate through them to check which one is hitting the arrow
      if (Draggable.hitTest(sector, "#arrow", '50px')) {

One thing to notice is that the last param of the hitTest function is a threshold which you can indicate how many pixels can be overlapping between the two components to count it as a hit

Takeaways of this project

you can check the source code inhereand a little demo of the app inhereI added some media queries so the wheel can be playable on all the sizes and a button to call the rotate function

Also, some notes:

  • the smaller the wheel, the harder it is to check for collisions since a lot of pie slices will overlap with each other
  • if you start adding more slices, you will have the same overlapping problem
  • right now the demo has like a 95% accuracy


cd …