Wheel of fortune
by Boban Stojanovski
HTML
<h1>
End at:
</h1>
<select>
<option value="0">Stack</option>
<option value="1">10</option>
<option value="2">200</option>
<option value="3">50</option>
<option value="4">100</option>
<option value="5">5</option>
<option value="6">500</option>
</select>
<br>
<div id="wheelOfFortune">
<canvas id="wheel"></canvas>
<div id="spin">SPIN</div>
</div>
CSS
#wheelOfFortune {
display: inline-flex;
position: relative;
overflow: hidden;
}
#wheel {
display: block;
user-select: none;
}
#spin {
font: 1.5rem/0 sans-serif;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
inset: 35%;
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;
-webkit-tap-highlight-color: transparent;
text-transform: uppercase;
}
#spin::after {
content: "";
position: absolute;
top: -17px;
border: 10px solid transparent;
border-bottom-color: currentColor;
border-top: none;
}
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
// Fix negative modulo stackoverflow.com/a/71167019/383904
const mod = (n, m) => ((n % m) + m) % m
const tot = sectors.length
const elSpin = document.querySelector("#spin")
const elWheel = document.querySelector("#wheel")
const ctx = elWheel.getContext`2d`
const dia = 300
ctx.canvas.width = dia
ctx.canvas.height = dia
const rad = dia / 2
const PI = Math.PI
const TAU = 2 * PI
const arc = TAU / tot
const angOffset = TAU * 0.75 // needle is north
let sectorIndex = 0 // Current sector index
let oldAng = 0
let ang = 0 // Angle rotation in radians
let spinAnimation = null
let animationFrameId
//* Get index of current sector */
const getIndex = (ang) => Math.floor(tot - (mod(ang, TAU) / 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 ${26 * arc}px sans-serif`
ctx.fillText(sector.label, rad - 10, 10)
//
ctx.restore()
}
const update = () => {
const currentProgress =
spinAnimation?.effect.getComputedTiming().progress ?? 0
const angDiff = ang - oldAng
const angCurr = angDiff * currentProgress
const angAbs = mod(oldAng + angCurr, TAU)
const sectorIndexNew = getIndex(angAbs)
if (sectorIndex !== sectorIndexNew) {
// Sector changed! Make a tick sound
}
sectorIndex = sectorIndexNew
elSpin.textContent =...