Search code examples
javascripthtmlcssrequestanimationframe

How to set a duration for requestAnimationFrame


requestAnimationFrame is good solution to creating javascript based animations. But i can not set a duration for this function. I want to play animations for a certain time. I tried some fps solutions but these are not smooth.

How can i fill this water in x seconds? enter image description here

const water = document.querySelector('.water')
let scale = 0

const fillGlass = () => {
  scale += 0.01
  water.style.transform = `scaleY(${scale})`

  if (scale <= 1) {
    requestAnimationFrame(fillGlass)
  }
}

requestAnimationFrame(fillGlass)
.glass {
  margin: 100px;
  width: 150px;
  height: 250px;
  border: 3px solid #000;
  border-top: 0;
  border-bottom-width: 12px
}

.water {
  height: 100%;
  background-color: #BBDEFB;
  transform: scaleY(0);
  transform-origin: bottom center;
}
<div class="glass">
  <div class="water"></div>
</div>


Solution

  • Simply, you can control it with animation-duration. If you want to add dynamic value, I have just added a parameter to pass value to CSS

    .glass {
      margin: 100px;
      width: 150px;
      height: 250px;
      border: 3px solid #000;
      border-top: 0;
      border-bottom-width: 12px
    }
    
    .water {
      height: 100%;
      background-color: #BBDEFB;
      transform-origin: bottom center;
      animation-name: animation;
      animation-duration: var(--value);
    }
    
    @keyframes animation {
      from { transform:scaleY(0) }
      to { transform:scaleY(1) }
    }
    <div class="glass">
      <div class="water" style='--value:20s'></div>
    </div>

    you can change --value in HTML, it will affect on CSS

    As per your need, in JS

    const water = document.querySelector('.water')
    let scale = 0
    let time = 2000  // 20 second * 100 
    
     const myInterval = setInterval(()=> {
      scale += 1/time
      water.style.transform = `scaleY(${scale})`
      if (scale >= 1) {
        clearInterval(myInterval);
      }
    }, 10);
    .glass {
      margin: 100px;
      width: 150px;
      height: 250px;
      border: 3px solid #000;
      border-top: 0;
      border-bottom-width: 12px
    }
    
    .water {
      height: 100%;
      background-color: #BBDEFB;
      transform: scaleY(0);
      transform-origin: bottom center;
    }
    <div class="glass">
      <div class="water"></div>
    </div>

    More Functions

    const start = document.querySelector('.start')
    const stop = document.querySelector('.stop')
    const fill = document.querySelector('.fill')
    const empty = document.querySelector('.empty')
    const water = document.querySelector('.water')
    
    
    let scale = 0
    let time = 2000 // 20 second * 100 
    let myInterval;
    
    start.addEventListener('click', () => {
      myInterval = setInterval(() => {
        scale += 1 / time
        water.style.transform = `scaleY(${scale})`
        if (scale >= 1) {
          clearInterval(myInterval);
        }
      }, 10);
    })
    
    stop.addEventListener('click', () => {
      clearInterval(myInterval);
    })
    
    fill.addEventListener('click', () => {
      scale = 1
      water.style.transform = `scaleY(${scale})`
    
    })
    
    empty.addEventListener('click', () => {
      scale = 0
      water.style.transform = `scaleY(${scale})`
    })
    .glass {
      margin: 100px;
      width: 150px;
      height: 250px;
      border: 3px solid #000;
      border-top: 0;
      border-bottom-width: 12px
    }
    
    .water {
      height: 100%;
      background-color: #BBDEFB;
      transform: scaleY(0);
      transform-origin: bottom center;
    }
    <button type="button" class="start">Start</button>
    <button type="button" class="stop">Stop</button>
    <button type="button" class="fill">Instant Fill</button>
    <button type="button" class="empty">Instant Empty</button>
    
    <div class="glass">
      <div class="water"></div>
    </div>