|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>Spin N Win</title> |
|
|
|
<link rel="stylesheet" href="https://huggingface.co/spaces/DMTuit/psy4/resolve/main/css/main.css"> |
|
<script src="https://huggingface.co/spaces/DMTuit/psy4/resolve/main/js/main.js"></script> |
|
|
|
<style> |
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
} |
|
|
|
body { |
|
height: 100vh; |
|
display: grid; |
|
place-items: center; |
|
} |
|
|
|
#wheelOfFortune { |
|
display: inline-block; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
#wheel { |
|
display: block; |
|
} |
|
|
|
#spin { |
|
font: 1.5em/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> |
|
|
|
|
|
|
|
</head> |
|
|
|
<body> |
|
<div id="wheelOfFortune"> |
|
<canvas id="wheel" width="300" height="300"></canvas> |
|
<div id="spin">Пуск</div> |
|
</div> |
|
|
|
|
|
|
|
<script> |
|
|
|
const sectors = [ |
|
{ color: '#f82', label: 'Stack', probability: 10 }, |
|
{ color: '#0bf', label: '10', probability: 20 }, |
|
{ color: '#fb0', label: '200', probability: 15 }, |
|
{ color: '#0fb', label: '50', probability: 20 }, |
|
{ color: '#b0f', label: '100', probability: 15 }, |
|
{ color: '#f0b', label: '5', probability: 10 }, |
|
{ color: '#bf0', label: '500', probability: 10 } |
|
] |
|
|
|
const rand = (m, M) => Math.random() * (M - m) + m |
|
const tot = sectors.length |
|
const spinEl = 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 / sectors.length |
|
const friction = 0.991 |
|
let angVel = 0 |
|
let ang = 0 |
|
|
|
const getIndex = () => Math.floor(tot - (ang / TAU) * tot) % tot |
|
|
|
function drawSector(sector, i) { |
|
const ang = arc * i |
|
ctx.save() |
|
|
|
ctx.beginPath() |
|
ctx.fillStyle = sector.color |
|
ctx.moveTo(rad, rad) |
|
ctx.arc(rad, rad, rad, ang, ang + arc) |
|
ctx.lineTo(rad, rad) |
|
ctx.fill() |
|
|
|
ctx.translate(rad, rad) |
|
ctx.rotate(ang + arc / 2) |
|
ctx.textAlign = 'right' |
|
ctx.fillStyle = '#fff' |
|
ctx.font = 'bold 21px sans-serif' |
|
ctx.fillText(sector.label, rad - 10, 10) |
|
|
|
ctx.restore() |
|
} |
|
|
|
function rotate() { |
|
const sector = sectors[getIndex()] |
|
ctx.canvas.style.transform = `rotate(${ang - PI / 2}rad)` |
|
spinEl.textContent = !angVel ? 'SPIN' : sector.label |
|
spinEl.style.background = sector.color |
|
} |
|
|
|
function frame() { |
|
if (!angVel) return |
|
angVel *= friction |
|
if (angVel < 0.002) { |
|
angVel = 0 |
|
const sector = sectors[getIndex()] |
|
localStorage.setItem('hasSpun', 'true') |
|
console.log('Result:', sector.label) |
|
} |
|
ang += angVel |
|
ang %= TAU |
|
rotate() |
|
} |
|
|
|
function engine() { |
|
frame() |
|
requestAnimationFrame(engine) |
|
} |
|
|
|
function init() { |
|
if (!localStorage.getItem('hasSpun')) { |
|
localStorage.setItem('hasSpun', 'false') |
|
} |
|
|
|
sectors.forEach(drawSector) |
|
rotate() |
|
engine() |
|
spinEl.addEventListener('click', () => { |
|
if (localStorage.getItem('hasSpun') === 'false') { |
|
localStorage.setItem('hasSpun', 'true') |
|
angVel = rand(0.25, 0.45) |
|
spinWheel() |
|
} else { |
|
console.log('You have already spun the wheel.') |
|
} |
|
}) |
|
} |
|
|
|
function spinWheel() { |
|
const probabilities = sectors.map(sector => sector.probability) |
|
const totalProbability = probabilities.reduce((a, b) => a + b, 0) |
|
const random = Math.random() * totalProbability |
|
let cumulativeProbability = 0 |
|
for (let i = 0; i < sectors.length; i++) { |
|
cumulativeProbability += sectors[i].probability |
|
if (random < cumulativeProbability) { |
|
ang = (i + 0.5) * arc |
|
break |
|
} |
|
} |
|
} |
|
|
|
init() |
|
</script> |
|
|
|
|
|
|
|
|
|
|
|
</body> |
|
</html> |
|
|