Как добавить шанс выпадения и вывод выпавшего числа 'Колесо фартуны'

Рейтинг: 0Ответов: 1Опубликовано: 11.02.2023

Как добавить на это колесо шанс выпадение для каждого числа и что бы оно выводилось в консоль после того как выпадет ?

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>

Ответы

▲ 0

Вы можете изначально определить какой сектор выпадет и сделать анимацию вращения так, как типа “так получилось”. То есть уменьшайте/увеличьте скорость вращения так, чтобы получилось так, как вы хотите. Это тривиальная физика.

Часть с которым я хочу помочь это метод который выдаст вам один из вариантов с определенным шансом. Класс 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));  // Выводим случайный из вариантов с опредленным шансом