I have used the wheel of fortune code by Roko C. Buljan from here: how to draw a wheel of fortune?
I asked ChatGPT to modify this code. I want each sector to have a different size percentage. ChatGPT helped me draw the correct rotation at the correct scale. However, when pressing the spin button, the arrow of the wheel shows the wrong result. I think it’s wrong in the getIndex() function but don’t know how to fix it. Please see the image and the code below to understand better.
<style>
#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;
}
</style>
<div id="wheelOfFortune">
<canvas id="wheel" width="300" height="300"></canvas>
<div id="spin">SPIN</div>
</div>
<script>
const sectors = [
{ color: "#f82", label: "Stack", size: 10 },
{ color: "#0bf", label: "10", size: 10 },
{ color: "#fb0", label: "200", size: 10 },
{ color: "#0fb", label: "50", size: 10 },
{ color: "#b0f", label: "100", size: 10 },
{ color: "#f0b", label: "5", size: 10 },
{ color: "#bf0", label: "500", size: 40 },
];
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 friction = 0.991; // Deceleration rate
let angVelMax = 0;
let angVel = 0;
let ang = 0;
let isSpinning = false;
let isAccelerating = false;
let animFrame = null;
// Function to generate random float in range
const rand = (m, M) => Math.random() * (M - m) + m;
// Function to get index of current sector
const getIndex = () => {
const currentAngle = ang % TAU;
let accumulatedAngle = 0;
for (let i = 0; i < sectors.length; i++) {
const sector = sectors[i];
const sectorAngle = (sector.size / totalSize) * TAU;
if (currentAngle >= accumulatedAngle && currentAngle < accumulatedAngle + sectorAngle) {
return i;
}
accumulatedAngle += sectorAngle;
}
return 0; // Default to the first sector
};
// Get total size percentage
const totalSize = sectors.reduce((total, sector) => total + sector.size, 0);
// Draw sectors and prizes texts to canvas
const drawSector = (sector, i) => {
const startAngle = (TAU * (i > 0 ? sectors.slice(0, i).reduce((acc, curr) => acc + curr.size, 0) : 0)) / totalSize;
const endAngle = (TAU * sector.size) / totalSize;
ctx.save();
// Draw sector
ctx.beginPath();
ctx.fillStyle = sector.color;
ctx.moveTo(rad, rad);
ctx.arc(rad, rad, rad, startAngle, startAngle + endAngle);
ctx.lineTo(rad, rad);
ctx.fill();
// Draw text
ctx.translate(rad, rad);
ctx.rotate(startAngle + endAngle / 2);
ctx.textAlign = "right";
ctx.fillStyle = "#fff";
ctx.font = "bold 20px sans-serif";
ctx.fillText(sector.label, rad - 10, 10);
ctx.restore();
};
// CSS rotate CANVAS Element
const rotate = () => {
const sectorIndex = getIndex();
const sector = sectors[sectorIndex];
// Calculate rotation angle for canvas
const rotationAngle = ang - PI / 2;
// Update CSS transform for canvas
ctx.canvas.style.transform = `rotate(${rotationAngle}rad)`;
// Update text and background color for spin button
//elSpin.textContent = !angVel ? "SPIN" : sector.label;
elSpin.textContent = sector.label;
elSpin.style.background = sector.color;
// Log current sector index for debugging
console.log(sectorIndex);
};
const frame = () => {
if (!isSpinning) return;
if (angVel >= angVelMax) isAccelerating = false;
// Accelerate
if (isAccelerating) {
angVel ||= 0.002; // Initial velocity kick
angVel *= 1.06; // Accelerate
}
// Decelerate
else {
isAccelerating = false;
angVel *= friction; // Decelerate by friction
// SPIN END:
if (angVel < 0.002) {
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); // Randomize max angular velocity
ang = 0; // Reset angle for new spin
engine(); // Start spinning!
});
// Initialize wheel
sectors.forEach(drawSector);
rotate(); // Initial rotation
</script>
The results:
Please help me! Thank you!!!