创建减速旋转的财富轮

问题描述 投票:0回答:1

我正在制作命运之轮或轮盘赌。一切都运转良好,只是旋转部分,我希望旋转在旋转结束时减慢。我应该在脚本中更改或添加哪里?

let index = Math.floor(Math.random() * this.max)
let rotations = 360 * ((Math.ceil(Math.random() * 10)) + 20) + ((index - 1) / this.max * 360) + (Math.floor(Math.random() * (360/this.max)))
// let rotations = ((index - 1) / this.max * 360)
let seconds = 2 + Math.ceil(Math.random() * 2)
console.log(rotations)
console.log(index)
console.log(this.prizes[index])
const randomAnswer = this.prizes[index]

如何在旋转结束时减慢旋转速度,像命运之轮一样?

javascript
1个回答
1
投票

结构

轮子和数字

轮子是通过将

.circle
类并使用
conic-gradient()
作为背景将其分成 8 个相等的三角形而制成的。然后我在
span
div 中放置了 8 个
.circle
元素(编号)。根据数字,在
.circle
span CSS 中设置准确位置并旋转值,使其面向圆心(这样,获胜的 span 值始终是可读的)。

箭头

在圆圈上方,我放了一个向下箭头。这个箭头在定义获胜元素方面起着关键作用。

旋转

开始

设置一个随机起点,然后在某个给定时间内将圆跨越。我可以通过调整CSS让它以不同的速度旋转,也可以控制旋转的时间,使其不以匀速旋转。我总是设置过渡持续时间以及计算的随机旋转。

结束

然后,我使用

setTimeout
在从输入字段传入的秒数后停止旋转。之后,我确定哪个
span
元素最接近箭头,并传入我们的获胜元素以显示其值。

代码

// Function to get a current rotation
// Source: https://stackoverflow.com/a/54492696/15167500
function getCurrentRotation(el) {
  var st = window.getComputedStyle(el, null);
  var tm = st.getPropertyValue("-webkit-transform") ||
           st.getPropertyValue("-moz-transform") ||
           st.getPropertyValue("-ms-transform") ||
           st.getPropertyValue("-o-transform") ||
           st.getPropertyValue("transform") ||
           "none";
  if (tm != "none") {
    var values = tm.split('(')[1].split(')')[0].split(',');
    /*
    a = values[0];
    b = values[1];
    angle = Math.round(Math.atan2(b,a) * (180/Math.PI));
    */
    //return Math.round(Math.atan2(values[1],values[0]) * (180/Math.PI)); //this would return negative values the OP doesn't wants so it got commented and the next lines of code added
    var angle = Math.round(Math.atan2(values[1],values[0]) * (180/Math.PI));
    return (angle < 0 ? angle + 360 : angle); //adding 360 degrees here when angle < 0 is equivalent to adding (2 * Math.PI) radians before
  }
  
  return 0;
}

// Function to get a random rotation between 0 and 360 degrees
function getRandomRotation() {
  return Math.random() * 360;
}

// Function to get a rotation to .circle span
function getRotationToSpan(number) {
  return 360 / 8 * Math.abs(number - 7);
}

// Create Spin to Element
const useSpin = (container) => {
  const circle = container.querySelector('.circle');
  // from the test, I change the starting rotation from 0
  // default start number 7, now I set start number to Random(1, 7)
  const randomStartNumber = Math.floor(Math.random() * 7) + 1; // between 1 and 7
  circle.style.transform = `rotate(${getRotationToSpan(randomStartNumber)}deg)`;
  
  const arrow = container.querySelector('.arrow');

  let latestRotation = getCurrentRotation(circle);
  
  // Function to handle the spinning animation
  function spin(button = undefined) {
    // Config
    const direction = 1; // 1 (left) or -1 (right)
    const duration = 10;
    const fakeSpinCount = 4;

    // Calculate rotation degree
    const randomRotation = getRandomRotation();
    const fakeSpinRotation = fakeSpinCount * 360;
    const nextRotation = (randomRotation + fakeSpinRotation) * direction;
    latestRotation += nextRotation;

    // If spin() call with HTML.Element, set disabled status
    if (button) {
      button.disabled = 'disabled';
    }

    // Set animation to circle; Start spin by rotate()
    circle.style.transition = `transform ${duration}s cubic-bezier(0.25, 0.1, 0.25, 1)`;
    circle.style.transform = `rotate(${latestRotation}deg)`;

    // Wait, while transform is running (duration)
    setTimeout(() => {
      // Remove animation from circle
      circle.style.transition = '';
      
      // If spin() call with HTML.Element, remove disabled status
      if (button) {
        button.removeAttribute('disabled');
      }

      // Calculate the closest number to the arrow's rotation
      const spans = circle.querySelectorAll('span');
      const arrowRotation = -arrow.getBoundingClientRect().top + latestRotation;
      let minDifference = Infinity;
      let closestNumber;

      spans.forEach((span) => {
        const spanRotation = -span.getBoundingClientRect().top + latestRotation;
        const difference = Math.abs(spanRotation - arrowRotation);
        if (difference < minDifference) {
          minDifference = difference;
          closestNumber = span.textContent;
        }
      });

      console.log('Closest number:', closestNumber);
    }, duration * 1000);
  }
  
  return {
    spin,
  }
}

const { spin } = useSpin(document.querySelector('.spin-container'));
.spin-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.circle {
  position: relative;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: conic-gradient(from -22.5deg, #4ab2e5 0, #4ab2e5 12.5%, #001b66 12.5%, #001b66 25%, #4ab2e5 25%, #4ab2e5 37.5%, #001b66 37.5%, #001b66 50%, #4ab2e5 50%, #4ab2e5 62.5%, #001b66 62.5%, #001b66 75%, #4ab2e5 75%, #4ab2e5 87.5%, #001b66 87.5%, #001b66 100%);
  font-size: 24px;
  color: #ffffff;
}

.circle span {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.5em;
  height: 1.5em;
  line-height: 1.5em;
  text-align: center;
  border-radius: 50%;
  transform: translate(-50%, -50%) rotate(calc(45deg * var(--n))) translate(80px) rotate(90deg);
}

.circle span:nth-child(odd) {
  background-color: #4ab2e5;
}

.circle span:nth-child(even) {
  background-color: #001b66;
}

.arrow {
  width: 0;
  height: 0;
  border: 15px solid transparent;
  border-top-color: #000;
}

.prize {
  font-size: 16px;
  font-weight: bold;
  color: #000;
}
<button onclick="spin(this)">SPIN</button>

<div class="spin-container">
  <div class="prize">Prize</div>
  <div class="arrow"></div>

  <div class="circle">
    <span style="--n: 0;">1</span>
    <span style="--n: 1;">2</span>
    <span style="--n: 2;">3</span>
    <span style="--n: 3;">4</span>
    <span style="--n: 4;">5</span>
    <span style="--n: 5;">6</span>
    <span style="--n: 6;">7</span>
    <span style="--n: 7;">8</span>
  </div>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.