csbk
csbk

Reputation: 609

how to draw a wheel of fortune?

Im trying to create a game of spin the wheel using this tutorial:

http://www.emanueleferonato.com/2015/07/31/create-a-wheel-of-fortune-for-your-html5-games-with-phaser-in-only-a-few-lines/

however, this tutorial used an image for the wheel and i want to create it in html5/js. something vaguely like this:

https://www.winkbingo.com/images/lp/301114/spin_the_wheel_image.png this is what i have so far:

var ctx = canvas.getContext("2d");
var end = 0;
var color = ['#F0F8FF','#FAEBD7','#00FFFF','#7FFFD4','#00FF00','#FF8C00'];
var labels = ['label1', 'label2','label3','label4','label5','label6'];
var slices = 6

for (var i = 0; i < slices; i++) {
ctx.fillStyle = color[i];
ctx.beginPath();
ctx.moveTo(canvas.width/2,canvas.height/2);
ctx.arc(canvas.width/2,canvas.height/2,canvas.height/2,end, ((1/slices)*Math.PI*2)+end ,false);
ctx.lineTo(canvas.width/2,canvas.height/2);
ctx.fill();
end += ((1/slices)*Math.PI*2)+end;
}

i want the number of segments to be able to change by changing the variable slices(between 1-6). and i also want to display the labels on top. then i want to use this canvas instead of the image in that tutorial code so the wheel spins around with the text. hope that wasnt confusing. anyone know how to do this> i dont mind using any libraries etc.

Upvotes: 12

Views: 41630

Answers (3)

Roko C. Buljan
Roko C. Buljan

Reputation: 206078

Wheel of fortune using JS Canvas

wheel of fortune game javascript

const sectors = [
  {color:"#f82", label:"Stack"},
  {color:"#0bf", label:"10"},
  {color:"#fb0", label:"200"},
  {color:"#0fb", label:"50"},
  {color:"#b0f", label:"100"},
  {color:"#f0b", label:"5"},
  {color:"#bf0", label:"500"},
];

// Generate random float in range min-max:
const rand = (m, M) => Math.random() * (M - m) + m;

const tot = sectors.length;
const elSpin = document.querySelector("#spin");
const ctx = document.querySelector("#wheel").getContext`2d`;
const dia = ctx.canvas.width;
const rad = dia / 2;
const PI = Math.PI;
const TAU = 2 * PI;
const arc = TAU / tot;
const friction = 0.991;  // 0.995=soft, 0.99=mid, 0.98=hard
const angVelMin = 0.002; // Below that number will be treated as a stop
let angVelMax = 0; // Random ang.vel. to accelerate to 
let angVel = 0;    // Current angular velocity
let ang = 0;       // Angle rotation in radians
let isSpinning = false;
let isAccelerating = false;
let animFrame = null; // Engine's requestAnimationFrame

//* Get index of current sector */
const getIndex = () => Math.floor(tot - ang / TAU * tot) % tot;

//* Draw sectors and prizes texts to canvas */
const drawSector = (sector, i) => {
  const ang = arc * i;
  ctx.save();
  // COLOR
  ctx.beginPath();
  ctx.fillStyle = sector.color;
  ctx.moveTo(rad, rad);
  ctx.arc(rad, rad, rad, ang, ang + arc);
  ctx.lineTo(rad, rad);
  ctx.fill();
  // TEXT
  ctx.translate(rad, rad);
  ctx.rotate(ang + arc / 2);
  ctx.textAlign = "right";
  ctx.fillStyle = "#fff";
  ctx.font = "bold 30px sans-serif";
  ctx.fillText(sector.label, rad - 10, 10);
  //
  ctx.restore();
};

//* CSS rotate CANVAS Element */
const rotate = () => {
  const sector = sectors[getIndex()];
  ctx.canvas.style.transform = `rotate(${ang - PI / 2}rad)`;
  elSpin.textContent = !angVel ? "SPIN" : sector.label;
  elSpin.style.background = sector.color;
};

const frame = () => {

  if (!isSpinning) return;

  if (angVel >= angVelMax) isAccelerating = false;

  // Accelerate
  if (isAccelerating) {
    angVel ||= angVelMin; // Initial velocity kick
    angVel *= 1.06; // Accelerate
  }
  
  // Decelerate
  else {
    isAccelerating = false;
    angVel *= friction; // Decelerate by friction  

    // SPIN END:
    if (angVel < angVelMin) {
      isSpinning = false;
      angVel = 0;
      cancelAnimationFrame(animFrame);
    }
  }

  ang += angVel; // Update angle
  ang %= TAU;    // Normalize angle
  rotate();      // CSS rotate!
};

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

elSpin.addEventListener("click", () => {
  if (isSpinning) return;
  isSpinning = true;
  isAccelerating = true;
  angVelMax = rand(0.25, 0.40);
  engine(); // Start engine!
});

// INIT!
sectors.forEach(drawSector);
rotate(); // Initial rotation
#wheelOfFortune {
  display: inline-flex;
  position: relative;
  overflow: hidden;
}

#wheel {
  display: block;
}

#spin {
  font: 1.5rem/0 sans-serif;
  user-select: none;
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 30%;
  height: 30%;
  margin: -15%;
  background: #fff;
  color: #fff;
  box-shadow: 0 0 0 8px currentColor, 0 0px 15px 5px rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  transition: 0.8s;
}

#spin::after {
  content: "";
  position: absolute;
  top: -17px;
  border: 10px solid transparent;
  border-bottom-color: currentColor;
  border-top: none;
}
<div id="wheelOfFortune">
  <canvas id="wheel" width="300" height="300"></canvas>
  <div id="spin">SPIN</div>
</div>

Stop at defined position

Whilst the above example uses requestAnimationFrame, to handle acceleration, deceleration etc, if instead you want to trick the user by controlling the end result and stopping the wheel at a specific angle or approximate sector angle — please refer to this related answer: Stop Wheel of Fortune at Predefined Angle or Index

Upvotes: 48

dougtesting.net
dougtesting.net

Reputation: 571

I am the creator of a Javascript library called Winwheel.js which allows easy creation of winning/prize wheels on HTML canvas.

The wheels can be code drawn or use graphically rich images and it leverages Greensock's animation platform for the spinning and other animation effects.

Here is an example of how easy it is to create a basic code-drawn wheel using Winwheel.js...

var theWheel = new Winwheel({
  'numSegments'  : 8,
  'segments'     :
  [
    {'fillStyle' : '#eae56f', 'text' : 'Prize 1'},
      {'fillStyle' : '#89f26e', 'text' : 'Prize 2'},
      {'fillStyle' : '#7de6ef', 'text' : 'Prize 3'},
      {'fillStyle' : '#e7706f', 'text' : 'Prize 4'},
      {'fillStyle' : '#eae56f', 'text' : 'Prize 5'},
      {'fillStyle' : '#89f26e', 'text' : 'Prize 6'},
      {'fillStyle' : '#7de6ef', 'text' : 'Prize 7'},
      {'fillStyle' : '#e7706f', 'text' : 'Prize 8'}
  ],
  'animation' :
  {
    'type'     : 'spinToStop',
    'duration' : 5,
    'spins'    : 8
  }
});

There is a full set of tutorials for Winwheel.js to help you get started on my site. If you are interested please visit http://dougtesting.net/

Upvotes: 4

6502
6502

Reputation: 114481

Just the plain canvas of html5 has all that is needed to draw a quite good-looking "wheel of fortune" with very little code, no need for libraries.

  • You can draw pie slices using arc
  • You can draw rotated text by using the translate/rotate global transforms
  • you can add shadows and glow effects
  • you can use radial and linear gradients to simulate lighting
  • you can use multi-pass renderings (e.g. rendering a lighting gradient over something already drawn
  • the speed on modern browsers is quite good... fast enough to render a spinning wheel in realtime (I'd expect drawing a single pre-computed rotating image would be faster especially on mobile devices, this approach would however require to have shadows in another canvas on top of the rotating wheel).

For example this is what I got with ~100 html lines (3.5k NOT minified) in total:

html5 wheel of fortune

Live example at http://raksy.dyndns.org/wheel.html

Upvotes: 9

Related Questions