i am trying to create a spinning wheel using canvas and html5. its working but my end goal is to try to point the arrow to the exact winning color. so for example if the winning color is the green one, the wheel should turn and stop until the outside arrow faces the winning color. i have attached the code below if someone can or is willing to help.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const spinButton = document.getElementById('spinButton');
const resultDisplay = document.getElementById('result');
const arrow = document.getElementById('arrow');
const wheel = {
sections: [
{ number: 'Prize 1', color: '#FF4136' },
{ number: 'Prize 2', color: '#0074D9' },
{ number: 'Prize 3', color: '#2ECC40' },
{ number: 'Prize 4', color: '#FFDC00' },
{ number: 'Prize 5', color: '#FF851B' },
{ number: 'Prize 6', color: '#B10DC9' }
],
centerX: canvas.width / 2,
centerY: canvas.height / 2,
radius: 200,
startAngle: 0,
draw() {
const angle = (2 * Math.PI) / this.sections.length;
const textRadius = this.radius - 20; // Radius for positioning text
for (let i = 0; i < this.sections.length; i++) {
const textAngle = angle * i + angle / 2; // Angle to position text at the center of each section
const x = this.centerX + Math.cos(textAngle) * textRadius;
const y = this.centerY + Math.sin(textAngle) * textRadius;
ctx.beginPath();
ctx.moveTo(this.centerX, this.centerY);
ctx.arc(this.centerX, this.centerY, this.radius, i * angle, (i + 1) * angle);
ctx.closePath();
ctx.fillStyle = this.sections[i].color;
ctx.fill();
ctx.stroke();
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.sections[i].number, x, y);
}
}
};
let rotationAngle = 0;
let spinning = false;
function spinWheel() {
if (spinning) return; // Prevent multiple spins
const randomIndex = Math.floor(Math.random() * wheel.sections.length);
const result = wheel.sections[randomIndex].number;
resultDisplay.textContent = `You won: ${result}`;
// Calculate random rotation angle
const randomRotation = Math.floor(Math.random() * 720) + 3600;
// Spin animation
spinning = true;
const spinInterval = setInterval(() => {
rotationAngle += 20; // Change the rotation speed by adjusting this value
if (rotationAngle >= randomRotation) {
clearInterval(spinInterval);
spinning = false;
}
drawWheel(rotationAngle);
}, 20);
}
function drawWheel(rotation) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
wheel.draw();
ctx.save();
ctx.translate(wheel.centerX, wheel.centerY);
ctx.rotate(rotation * Math.PI / 180);
ctx.translate(-wheel.centerX, -wheel.centerY);
wheel.draw();
ctx.restore();
}
wheel.draw(); // Initial drawing
spinButton.addEventListener('click', spinWheel);
#upperContainer {
position: fixed;
top: 50px; /* Adjust as needed */
left: 50px; /* Adjust as needed */
}
#arrow {
width: 0;
height: 0;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 15px solid black; /* Change to left border */
position: absolute;
left: -5px; /* Adjust as needed */
top: 50%;
transform: translateY(-50%);
}
#canvas {
border: 1px solid black;
border-radius: 50%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wheel of Fortune</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="upperContainer">
<div id="arrow"></div>
<canvas id="canvas" width="500" height="500"></canvas>
</div>
<button id="spinButton">Spin</button>
<div id="result"></div>
<script src="script.js"></script>
</body>
</html>
2
Answers
I’ve added a
getTargetRotation
function to make sure the arrow points to the exact winning colour:I used your code with this function to create a CodeSandbox for testing, hope it’s helpful
https://codesandbox.io/p/sandbox/spin-9lcs65?file=%2Fscript.js%3A74%2C20
Since we are guessing the final result, we might as well guess the starting speed. So I start with speed 10 degrees and keep incrementing until I reach the desired one. Why? I introduced some friction to make it spin realistically, and I found it easier to just guess the correct speed iteratively.