Search code examples
javascripthtmlcanvashtml5-canvas

Remove the value from the wheel of fortune


I have used the wheel of fortune code by Roko C. Buljan from here: how to draw a wheel of fortune?

I'm new to using canvas but I've figured out most of the what the code is doing - maths is defo not my forte!

I'm struggling to add the functionality that when the wheel has stopped spinning and has landed on the slice, how can I either remove it completely or change the colour of the slice and stop the wheel landing on it again? Is this possible?

Thanks for your answers/advice in advance!

const fruits = [{
    color: '#cf6f',
    label: 'Apple',
    value: 1
  },
  {
    color: '#0051',
    label: 'Lemon',
    value: 2
  },
  {
    color: '#efd',
    label: 'Raspberry',
    value: 3
  },
  {
    color: '#6b9',
    label: 'Blueberry',
    value: 4
  },
  {
    color: '#afb',
    label: 'Mango',
    value: 5
  },
];

const rand = (min, max) => Math.random() * (max - min) + min;
const numOfFruits = fruits.length;
const spin = document.querySelector('#spin');
const ctx = document.querySelector('#wheel').getContext('2d');
const diameter = ctx.canvas.width;
const radius = diameter / 2;
const PI = Math.PI; // 3.141592653589793
const TAU = 2 * PI; // 6.283185307179586
const arc = TAU / fruits.length; // 0.8975979010256552

const friction = 0.97; // 0.995=soft, 0.99=mid, 0.98=hard
let angVel = 0; // Angular velocity
let angle = 0; // angle in radians

const getIndex = () =>
  Math.floor(numOfFruits - (angle / TAU) * numOfFruits) % numOfFruits;

function drawSector(sector, index) {
  const angle = arc * index;
  console.log('angle', angle)
  console.log(index)
  console.log(sector)
  ctx.save();
  // COLOR
  ctx.beginPath();
  ctx.fillStyle = sector.color;
  ctx.moveTo(radius, radius);
  ctx.arc(radius, radius, radius, angle, angle + arc);
  ctx.lineTo(radius, radius);
  ctx.fill();
  // positioning of the text
  ctx.translate(radius, radius);
  ctx.rotate(angle + arc / 2);
  ctx.textAlign = 'right';
  ctx.fillStyle = '#243447';
  ctx.font = 'bold 1.3em Courier New';
  ctx.fillText(sector.label, radius - 10, 10);
  //
  ctx.restore();
}

function rotate() {
  const slice = fruits[getIndex()];
  ctx.canvas.style.transform = `rotate(${angle - PI / 2}rad)`;
  spin.textContent = !angVel ? 'SPIN' : slice.label;
  spin.style.background = slice.color;
}

// Called when the wheel stops
function stopSpinning() {
  const slice = fruits[getIndex()];
  console.log('Landed on', slice.label);
}

function frame() {
  if (!angVel) return;
  const isSpinning = angVel > 0;
  angVel *= friction; // Decrement velocity by friction
  if (angVel < 0.002) angVel = 0; // Bring to stop
  angle += angVel; // Update angle
  angle %= TAU; // Normalize angle
  rotate();

  if (isSpinning && angVel === 0) {
    // If the wheel has stopped spinning
    stopSpinning();
  }
}

const engine = () => {
  frame();
  requestAnimationFrame(engine);
};

// INIT
fruits.forEach(drawSector);
rotate(); // Initial rotation
engine(); // Start engine
spin.addEventListener('click', () => {
  if (!angVel) {
    angVel = rand(2, 1);
  }
});
<div id="wheelOfFortune">
  <canvas id="wheel" width="400" height="400"></canvas>
  <div id="spin">SPIN</div>
</div>


Solution

  • In your stopSpinning we could just remove the item that it landed on, we do that with:
    .splice(getIndex(),1)
    if you never use it before, read more here:
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

    I also had to do a few more changes to accomodate the fact that now the array changes, for example the const numOfFruits = fruits.length instead of using that we just use the length directly when we need it

    Try this code below:

    let fruits = [
      {color: 'red', value: 1 },
      {color: 'blue', value: 2 },
      {color: 'pink', value: 3 },
      {color: 'green', value: 4 },
      {color: 'cyan', value: 5 },
    ];
    
    const rand = (min, max) => Math.random() * (max - min) + min;
    const spin = document.querySelector('#spin');
    const canvas = document.querySelector('#wheel')
    const ctx = canvas.getContext('2d');
    const radius = canvas.width / 2;
    const PI = Math.PI; // 3.141592653589793
    const TAU = 2 * PI; // 6.283185307179586
    
    const friction = 0.97; // 0.995=soft, 0.99=mid, 0.98=hard
    let angVel = 0; // Angular velocity
    let angle = 0; // angle in radians
    
    const getIndex = () =>
      Math.floor(fruits.length - (angle / TAU) * fruits.length) % fruits.length;
    
    // Called when the wheel stops
    function stopSpinning() {
      const slice = fruits[getIndex()];
      console.log('Landed on', slice.value);
      fruits.splice(getIndex(),1) 
      init()
    }
    
    function drawSector(sector, index) {
      const angle = (TAU / fruits.length) * index;
      ctx.save();
      // COLOR
      ctx.beginPath();
      ctx.fillStyle = sector.color;
      ctx.moveTo(radius, radius);
      ctx.arc(radius, radius, radius, angle, angle + TAU / fruits.length);
      ctx.lineTo(radius, radius);
      ctx.fill();
      // positioning of the text
      ctx.translate(radius, radius);
      ctx.rotate(angle + (TAU / fruits.length) / 2);
      ctx.textAlign = 'right';
      ctx.fillStyle = 'black';
      ctx.font = 'bold 1.3em Courier New';
      ctx.fillText(sector.value, radius - 10, 10);
      //
      ctx.restore();
    }
    
    function rotate() {
      const slice = fruits[getIndex()];
      ctx.canvas.style.transform = `rotate(${angle - PI / 2}rad)`;
      spin.textContent = !angVel ? 'SPIN' : slice.value;
    }
    
    function frame() {
      if (!angVel) return;
      const isSpinning = angVel > 0;
      angVel *= friction; // Decrement velocity by friction
      if (angVel < 0.002) angVel = 0; // Bring to stop
      angle += angVel; // Update angle
      angle %= TAU; // Normalize angle
      rotate();
    
      if (isSpinning && angVel === 0) {
        // If the wheel has stopped spinning
        stopSpinning();
      }
    }
    
    function init() {
      fruits.forEach(drawSector);
      rotate(); // Initial rotation
      engine(); // Start engine
    }
    
    const engine = () => {
      frame();
      requestAnimationFrame(engine);
    };
    
    
    init()
    spin.addEventListener('click', () => {
      if (!angVel) angVel = rand(2, 1);
    });
    <div id="wheelOfFortune">
      <canvas id="wheel" width="100" height="100"></canvas>  
      <button id="spin">SPIN</button>
    </div>