Search code examples
cssanimationalignment

CSS align problem on slot machine's slots


I'm trying to create a slot machine... but have a problem on the CSS side. I didn't see this problem while working on 1 slot band, but I got this problem when tried to have 3 slot bands.

It's spinning as well while having 1 slot band. I tried many things to solve this alignment problem but couldn't solve it.

Align Problem:

Problem

This to while I have 1 slot band:

1 Slot Band

my Codes:

  var degree1;
  degree1 = '505deg';
  var root = document.querySelector(':root');
  root.style.setProperty('--slot1Rotate',degree1);


  var panes = document.querySelectorAll(".slot_item"),
      paneSize = 100,
      zDepth = paneSize / (2 * Math.tan(Math.PI/panes.length));

for (let index = 0; index < panes.length; index++) {
     var xAngle = 360 / panes.length * index;
    panes[index].style.transform= "rotateX("+ xAngle +"deg) translateZ("+ zDepth +"px)";
  }
var machine = document.querySelectorAll('.slot-machine');
var spinBtn = document.querySelector('#spinBtn');

for(let i=0;i<machine.length;i++){
spinBtn.addEventListener('click',function(){
  machine[i].classList.add('animation');
});

machine[i].addEventListener('animationend',function() {
  machine[i].style.transform = 'rotateX('+degree1+')';
})

}
:root{
    --slot1Rotate: 0;
  }
html, body {
  height: 100%;
  perspective: 600;
  background-color: #282a3a;
}

.machine{
    top: 25em;
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: center;
    position: relative;
}

.slots{
  display: flex;
  gap: 10px;
  justify-content: center;
  align-items: center;
 
}
.slot1{

}

.slot2{
  
}
.slot3{

}
.slot-machine{
  width: 120px;
  height: 120px;
  list-style: none;
  padding: 0;
  position:relative;
  transform-style: preserve-3d;
}

.animation{
  
  animation-name: x-spin;
  animation-duration: 5s;
  transition-duration: 3s;
  transition-delay: 1s;
}

.slot_item {
  height: 100px;
  position: absolute;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  width: 100%;
  background: rgba(255, 255, 255, 0.832);
  backface-visibility: hidden;
}
   <div class="machine">
      <div class="slots">
        <ul class="slot-machine slot1">
          <li class="slot_item">1</li>
          <li class="slot_item">2</li>
          <li class="slot_item">3</li>
          <li class="slot_item">4</li>
          <li class="slot_item">5</li>
          <li class="slot_item">6</li>
          <li class="slot_item">7</li>
          <li class="slot_item">8</li>
          <li class="slot_item">9</li>
          <li class="slot_item">10</li>
        </ul>

        <ul class="slot-machine slot2">
          <li class="slot_item">1</li>
          <li class="slot_item">2</li>
          <li class="slot_item">3</li>
          <li class="slot_item">4</li>
          <li class="slot_item">5</li>
          <li class="slot_item">6</li>
          <li class="slot_item">7</li>
          <li class="slot_item">8</li>
          <li class="slot_item">9</li>
          <li class="slot_item">10</li>
      </ul>
      <ul class="slot-machine slot3">
        <li class="slot_item">1</li>
        <li class="slot_item">2</li>
        <li class="slot_item">3</li>
        <li class="slot_item">4</li>
        <li class="slot_item">5</li>
        <li class="slot_item">6</li>
        <li class="slot_item">7</li>
        <li class="slot_item">8</li>
        <li class="slot_item">9</li>
        <li class="slot_item">10</li>
    </ul>
      </div>
      <button id="spinBtn">Spin</button>
    </div>


Solution

  • your bug happens because of one of your for loop

    they have a incrementally value inside rotateX();,
    this is bad because for every panes there is 10 elements,

    and here is the problem!:
    the program thinks that the 2second panes element is starting from index 10,
    the third start from index 20

    but in reality, we want that the second to start from 0, like the first one,
    same logic for the third one.

    enter image description here


    how I solve that?

    • by deleting the panes for loop,
    • and insert inside the machines for loop

    so for every machine, we can get the machine's panes.

    ❌ so before the index iteration was 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

    ✅ now 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

    I also refactored your code, to be with .forEach();, now is more readable and easy to change.

    /* your selectors */
    let root = document.querySelector(":root");
    let panes = document.querySelectorAll(".slot_item");
    
    let spinBtn = document.querySelector("#spinBtn");
    let machines = document.querySelectorAll(".slot-machine");
    
    /* math data */
    let degree1 = 310; // before was 505 (309 center correcly)
    let paneSize = 100;
    let zDepth = paneSize / (2 * Math.tan(Math.PI / panes.length));
    
    root.style.setProperty("--slot1Rotate", `${degree1}deg`);
    
    /* machines logic */
    machines.forEach((thisMachine) => {
      let thisMachinePanes = thisMachine.querySelectorAll(".slot_item");
    
      /* button clicking logic */
      spinBtn.addEventListener("click", () => {
        thisMachine.classList.add("animation");
      });
    
      /* animation end logic */
      thisMachine.addEventListener("animationend", () => {
        /* for making animation run every time on click, because you can't add a class if there is the same class before */
        thisMachine.classList.remove("animation");
        thisMachine.style.transform = `rotateX(${degree1}deg)`;
      });
    
      /* panes logic */
      thisMachinePanes.forEach((thisPane, index) => {
        let xAngle = (360 / panes.length) * index;
        thisPane.style.transform = `rotateX(${xAngle}deg) translateZ(${zDepth}px)`;
      });
    });
    :root {
      --slot1Rotate: 0;
    }
    
    html,
    body {
      perspective: 600;
      background-color: #282a3a;
      /* centering */
      display: grid;
      place-items: center;
      height: 100vh;
      margin: 0;
    }
    
    .machine {
      /* top: 25rem; don't center like this */
      display: flex;
      gap: 10px;
      align-items: center;
      justify-content: center;
      position: relative;
    }
    
    .slots {
      display: flex;
      gap: 10px;
      justify-content: center;
      align-items: center;
      position: relative;
    }
    
    .slot-machine {
      width: 120px;
      height: 120px;
      list-style: none;
      padding: 0;
      position: relative;
      transform-style: preserve-3d;
      /* default position (from js code) */
      transform: rotateX(var(--slot1Rotate));
    }
    
    .animation {
      animation-name: x-spin;
      animation-duration: 5s;
      transition-duration: 3s;
      transition-delay: 1s;
    }
    
    .slot_item {
      height: 100px;
      position: absolute;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      text-align: center;
      width: 100%;
      background: rgba(255, 255, 255, 0.832);
      backface-visibility: hidden;
    }
    
    
    /* added animation keyframes */
    
    @keyframes x-spin {
      0% {
        transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
      }
      100% {
        /* with the variable changed by js */
        transform: rotatex(var(--slot1Rotate));
      }
    }
    
    .slot1 {}
    
    .slot2 {}
    
    .slot3 {}
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Document</title>
      <link rel="stylesheet" href="style.css">
    </head>
    
    <body>
      <div class="machine">
        <div class="slots">
          <!-- 1 -->
          <ul class="slot-machine slot1">
            <li class="slot_item">1</li>
            <li class="slot_item">2</li>
            <li class="slot_item">3</li>
            <li class="slot_item">4</li>
            <li class="slot_item">5</li>
            <li class="slot_item">6</li>
            <li class="slot_item">7</li>
            <li class="slot_item">8</li>
            <li class="slot_item">9</li>
            <li class="slot_item">10</li>
          </ul>
    
          <!-- 2 -->
          <ul class="slot-machine slot2">
            <li class="slot_item">1</li>
            <li class="slot_item">2</li>
            <li class="slot_item">3</li>
            <li class="slot_item">4</li>
            <li class="slot_item">5</li>
            <li class="slot_item">6</li>
            <li class="slot_item">7</li>
            <li class="slot_item">8</li>
            <li class="slot_item">9</li>
            <li class="slot_item">10</li>
          </ul>
    
          <!-- 3 -->
          <ul class="slot-machine slot3">
            <li class="slot_item">1</li>
            <li class="slot_item">2</li>
            <li class="slot_item">3</li>
            <li class="slot_item">4</li>
            <li class="slot_item">5</li>
            <li class="slot_item">6</li>
            <li class="slot_item">7</li>
            <li class="slot_item">8</li>
            <li class="slot_item">9</li>
            <li class="slot_item">10</li>
          </ul>
        </div>
        <button id="spinBtn">Spin</button>
      </div>
    
      <script src="./script.js"></script>
    </body>
    
    </html>

    enter image description here

    there is a lot of things to correct,
    but at least I solved the aligning issue