Как добавить шанс выпадения и вывод выпавшего числа 'Колесо фартуны'
Как добавить на это колесо шанс выпадение для каждого числа и что бы оно выводилось в консоль после того как выпадет ?
const sectors = [
{ color:"#333", label: '200'},
{ color:"#1b1b1b", label: '350'},
{ color:"#333", label: '500'},
{ color:"#1b1b1b", label: '750'},
{ color:"#333", label: '1000'},
{ color:"#1b1b1b", label: '5000'},
{ color:"#333", label: '3000'},
{ color:"#fff27e", label: '1000000'}
]
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 // 0.995=soft, 0.99=mid, 0.98=hard
let angVel = 0 // Angular velocity
let ang = 0 // Angle in radians
const getIndex = () => Math.floor(tot - (ang / TAU) * tot) % tot
function 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 15px 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 = sector.label
spinEl.style.background = sector.color
}
function frame() {
if (!angVel) return
angVel *= friction // Decrement velocity by friction
if (angVel < 0.002) angVel = 0 // Bring to stop
ang += angVel // Update angle
ang %= TAU // Normalize angle
rotate()
}
function engine() {
frame()
requestAnimationFrame(engine)
}
function init() {
sectors.forEach(drawSector)
rotate() // Initial rotation
engine() // Start engine
spinEl.addEventListener('click', () => {
if (!angVel) angVel = rand(0.25, 0.45)
})
}
init()
#wheelOfFortune {
display: inline-flex;
position: relative;
overflow: hidden;
color: none;
background: none;
border: 3px solid #ffffff5e;
border-radius: 100%;
}
#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: #ffffff5e;
color: #ffffff5e;
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"></div>
</div>
Ответы (1 шт):
Вы можете изначально определить какой сектор выпадет и сделать анимацию вращения так, как типа “так получилось”. То есть уменьшайте/увеличьте скорость вращения так, чтобы получилось так, как вы хотите. Это тривиальная физика.
Часть с которым я хочу помочь это метод который выдаст вам один из вариантов с определенным шансом. Класс Random имеет 2 функции: number - это функция, которая возвращает случайное число между min и max. Она нужна для работы следующей функции, которая в свою очередь и совершает выбор.
Принцип такой: вы передаете коллекцию Map с типом <[Item, Chance]> в аргумент функции и она вам возвращает один из элементов Item, если конечно коллекция не пуста. Снизу подробный пример.
class Random {
static number(min, max) {
return Math.random() * (max - min) + min;
}
static case (cases) {
const summary = Array.from(cases).reduce((previous, current) => previous + current[1], 0);
const random = Random.number(0, summary);
let selection = undefined;
let start = 0;
for (const [type, chance] of cases) {
const end = start + chance;
if (start <= random && random < end) {
selection = type;
break;
}
start = end;
}
if (selection === undefined) {
throw new ReferenceError(`Can't select value. Maybe stack is empty.`);
} else {
return selection;
}
}
}
const sectors = [
{ color:"#333", label: '200'},
{ color:"#1b1b1b", label: '350'},
{ color:"#333", label: '500'},
{ color:"#1b1b1b", label: '750'},
{ color:"#333", label: '1000'},
{ color:"#1b1b1b", label: '5000'},
{ color:"#333", label: '3000'},
{ color:"#fff27e", label: '1000000'},
];
const cases = new Map([ // Создаем коллекцию Map
[sectors[0], 35], // Задаем параметры по структуре [элемент, шанс]
[sectors[1], 28], // Таким образом задаем шанс для всех элементов
[sectors[2], 17],
[sectors[3], 10],
[sectors[4], 5],
[sectors[5], 1.9],
[sectors[6], 3],
[sectors[7], 0.1],
]); // Суммарное количество шансов необязательно должно быть 100, но желательно, чтобы было легче в собственных расчетах.
console.log(Random.case(cases)); // Выводим случайный из вариантов с опредленным шансом