简体   繁体   中英

Proper way to sync setInterval and transition

Problem statement

To move the square along the perimeter of the viewport on click of the button as can be seen in the example:

https://codepen.io/vineetrok/pen/XRowdB

What do I need?

I'm using this code in combination with the transition property in the CSS. I think combination of transition and setInterval() is causing a delay. Is there a better and efficient method to accomplish this only using javascript?

Following is my code:

HTML

 <div class="box" style="left:0;top:0"></div>
  <button type="button" name="button" onclick="init()">Start!</button>

CSS

.box{
transition: all 1s linear;
}

JS

var elem = document.querySelector(".box");
var viewportWidth = window.innerWidth;
var viewportHeight = window.innerHeight;
var dimension = elem.clientWidth;
var deltaX = viewportWidth - dimension;
var deltaY = viewportHeight - dimension;

function move(x,y){
  if(x <=0 && y==0){
    elem.style.left=(deltaX)+"px";
  }
  else if(x==(deltaX) && y==0){
    elem.style.top=(deltaY)+"px";
  }
  else if(x==(deltaX) && y==(deltaY)){
    elem.style.left="0px";
  }
  else if(x==0 && y==(deltaY)){
    elem.style.top="0px";
  }

}

function getCoordinates(elem){
  return {
    x: elem.getBoundingClientRect().left,
    y: elem.getBoundingClientRect().top
  }
}

var init = function(){
  var clearTimer = 1;
  var startTimer = setInterval(function(){ 
    move(getCoordinates(elem).x,getCoordinates(elem).y )
    }, 1000);
      clearTimer++;
      if(clearTimer>=4){
        clearInterval(startTimer);
      }
    }

I would generally say that using both css and javascript to manage a transition is going to cause trouble. Part of the problem is that javascript timers aren't very precise. If you set a timer for 1 second it doesn't actually sleep for exactly one second. The exact amount of time it sleeps can vary depending on how busy the CPU is, what the user is doing, etc. It is very easy for the javascript timer to take longer than the CSS animation.

Since you are using jQuery I would use the jQuery.animate function to run things. It has a callback function that is invoked when the animation completes, and you can use that to execute the next step of the animation without any timers at all. That will make sure there aren't any delays. It should also be fairly performant. CSS animations are usually the slowest in terms of computer performance, so I expect jQuery.anmiate to probably be a bit better. There are other libraries out there designed for high performance animations, but unless performance actually becomes a problem, I wouldn't worry about it. Right now your issue is likely the imprecise timing of the timeout method, and not any performance issues.

Here's my go at it (I developed something from scratch instead of reusing your code) :

 let box=document.getElementById("box"), isLeft = false, isTop = false const toggleLeft = () => { box.style.left = (isLeft=!isLeft) ? "calc( 100% - 50px )" : "0"; setTimeout(toggleTop, 2000); } const toggleTop = () => { box.style.top = (isTop=!isTop) ? "calc( 100% - 50px )" : "0"; setTimeout(toggleLeft, 2000); } setTimeout(toggleLeft, 1000) 
 #box { width: 50px; height: 50px; background: #00f; position: absolute; top: 0; left: 0; -webkit-transition: all 2s ease-in-out; transition: all 2s ease-in-out; } 
 <div id="box"></div> 

And a more condensed and recursive version :

 let box=document.getElementById("box"), is = { left : false, top : false } const toggle = what => { box.style[what] = (is[what]=!is[what]) ? "calc( 100% - 50px )" : "0"; setTimeout(()=>toggle(what==="left"?"top":"left"), 2000); } setTimeout(()=>toggle("left"), 100) 
 #box { width: 50px; height: 50px; background: #00f; position: absolute; top: 0; left: 0; -webkit-transition: all 2s ease-in-out; transition: all 2s ease-in-out; } 
 <div id="box"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM