Reputation: 609
Im trying to create a game of spin the wheel using this tutorial:
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
Reputation: 206078
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>
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
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
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.
arc
translate
/rotate
global transformsFor example this is what I got with ~100 html lines (3.5k NOT minified) in total:
Live example at http://raksy.dyndns.org/wheel.html
Upvotes: 9