Search code examples
javascriptcsscss-animationscoordinates

I wonder how to get the coordinates of the element through getBoundingClientRect when the animation stops


I want to get the correct coordinates when the element that moves with CSS Animation stops.

The getBoundingClientRect value continues to change during the animation. My goal is to get the exact coordinate values of the elements when I pause the animation.

I paused the animation and got the coordinates. But the coordinates were not accurate.

The way I tried to force myself to achieve my goal is the 'thinkCoords' Function in the code below.

Delay with setTimeout to obtain the correct current coordinates.

But what I want is no delay. I want to get the correct coordinates at the same time as the animation pause.

To get the exact current coordinates the moment the animation stops, What should I do?

    let el = document.getElementById('el');
    let stopCoords = document.getElementById('stopCoords');
    let currentCoords = document.getElementById('currentCoords');
    let thinkCoords =
       document.getElementById('thinkCoords');
    let stopCoordsText = document.getElementById('stopCoordsText');
    let currentCoordsText = document.getElementById('currentCoordsText');
    let thinkCoordsText = document.getElementById('thinkCoordsText');
    
stopCoords.addEventListener('click',()=>{
     el.classList.toggle('stop')
     let coordsX = el.getBoundingClientRect().x;
     stopCoordsText.innerText = `${coordsX}`;
    })
currentCoords.addEventListener('click',()=>{
     let coordsX = el.getBoundingClientRect().x;
     currentCoordsText.innerText = `${coordsX}`;
    })

thinkCoords.addEventListener('click',()=>{
      el.classList.toggle('stop');
      setTimeout(()=>{
     let coordsX = el.getBoundingClientRect().x;
     thinkCoordsText.innerText = `${coordsX}`;
      },1000)
      

    })
   

 #el {
      width: 2px;
      height: 20px;
      background: #000;
      animation-name: moving;
      animation-duration: 0.9s;
      animation-delay: none;
      animation-iteration-count: infinite;
      animation-play-state: running;
      animation-timing-function: ease;
      animation-fill-mode: fowards;
    }
    #el.stop{
      animation-play-state: paused;
    }

    @keyframes moving{
        0% {
            transform:translate(0em);
          }
        50%{
          transform:translate(10em); 
         }
        100%{
            transform:translate(0em);
          }
    }

    button {
      margin-top:100px;
    }
   

 <div id="el"></div>

    <button id='stopCoords'>anime Paused and Coords value</button>
    <button id='currentCoords'>Current Coords value</button>
    <button id='thinkCoords'>
    Try my think code
    </button>

    <p>stopping Coords : <span id='stopCoordsText'></span> </p>
    <p>current Coords : <span id='currentCoordsText'></span> </p>
    <p>Try my think Coords : <span id='thinkCoordsText'></span> </p>

https://codepen.io/qirtudgus/pen/bGvXXpd


Solution

  • The animation's time will get updated only later on (I would have thought at the next painting frame, but at least in Firefox it seems to not be always the case...), and that's only in this time update that the pause will become effective.

    We apparently don't have an event for when the animation's pause actually occur, so there doesn't seem to be a bullet-proof hook for this.

    However since you wanted to have it all synchronous, this can actually be done by updating the .currentTime of the animation through its Animation interface:

    let el = document.getElementById('el');
    let stopCoords = document.getElementById('stopCoords');
    let currentCoords = document.getElementById('currentCoords');
    let thinkCoords = document.getElementById('thinkCoords');
    let stopCoordsText = document.getElementById('stopCoordsText');
    let currentCoordsText = document.getElementById('currentCoordsText');
    let thinkCoordsText = document.getElementById('thinkCoordsText');
    
    stopCoords.addEventListener('click', () => {
      // access you animation as an Animation object
      const anim = el.getAnimations()[0];
      anim.pause();
      anim.currentTime = anim.currentTime; // force pausing synchronously
      let coordsX = el.getBoundingClientRect().x;
      stopCoordsText.innerText = `${coordsX}`;
    })
    currentCoords.addEventListener('click', () => {
      let coordsX = el.getBoundingClientRect().x;
      currentCoordsText.innerText = `${coordsX}`;
    })
    #el {
      width: 2px;
      height: 20px;
      background: #000;
      animation-name: moving;
      animation-duration: 0.9s;
      animation-delay: none;
      animation-iteration-count: infinite;
      animation-play-state: running;
      animation-timing-function: ease;
      animation-fill-mode: fowards;
    }
    
    #el.stop {
      animation-play-state: paused;
    }
    
    @keyframes moving {
      0% {
        transform: translate(0em);
      }
      50% {
        transform: translate(10em);
      }
      100% {
        transform: translate(0em);
      }
    }
    
    button {
      margin-top: 100px;
    }
    <div id="el"></div>
    
    <button id='stopCoords'>anime Paused and Coords value</button>
    <button id='currentCoords'>Current Coords value</button>
    
    <p>stopping Coords : <span id='stopCoordsText'></span> </p>
    <p>current Coords : <span id='currentCoordsText'></span> </p>