setInterval and Javascript Animation

I’m practicing using javascript to animate css. I copied some source code from w3schools that makes a rectangle (the animate div) travel diagonally right across a larger rectangle (container div).
Here’s that original code:

<!DOCTYPE html>
<html>
<style>
#container {
  width: 400px;
  height: 400px;
  position: relative;
  background: yellow;
}
#animate {
  width: 50px;
  height: 50px;
  position: absolute;
  background-color: red;
}
</style>
<body>

<p>
<button onclick="myMove()">Click Me</button>
</p> 

<div id ="container">
<div id ="animate"></div>
</div>

<script>
function myMove() {
  var elem = document.getElementById("animate");   
  var pos = 0;
  var id = setInterval(frame, 5);
  function frame() {
    if (pos == 350) {
      clearInterval(id);
    } else {
      pos++; 
      elem.style.top = pos + 'px'; 
      elem.style.left = pos + 'px'; 
    }
  }
}
</script>

</body>
</html>

I wanted the rectangle to travel in reverse when it got to the bottom right corner of the container div. Here’s how I tried to do it:

<!Doctype html>
<html>
	<title>
	</title>
	
	<head>
	
	</head>
	
	<style>
		#container 
		{
			width: 400px;
			height: 400px;
			position: relative;
			background: blue;
		}
		
		#animate 
		{
			width: 50px;
			height: 50px;
			position: absolute;
			background-color: red;
		}
	</style>
	
	<body onload = "myMove()">
		<div id ="container">
			<div id ="animate">
			</div>
		</div>
		
		<script>
			function myMove() 
			{
				var elem = document.getElementById("animate");   
				var posTop = 0;
				var posLeft = 0;
				var id = setInterval(frame, 5);
				
				function frame() 
				{
					posTop++;
					posLeft++;
					
					if(posTop === 350) 
					{
						while(posTop > 0)
						{
							posTop--;
						}
					} 
					
					if(posLeft === 350)
					{
						while(posLeft > 0)
						{
							posLeft--;
						}
					}
					
					
					elem.style.top = posTop + 'px'; 
					elem.style.left = posLeft + 'px'; 
					
				}
			}
		</script>
	</body>
</html>

For some reason it just restarts the original animation. I notice that this may have something to do with how the setInterval() function works, but I’m not sure.

The function below will keep the box moving back and forth along the same diagonal forever.

function myMove() {
  var container = document.getElementById("container");
  var elem = document.getElementById("animate");
  var id = setInterval(frame, 5);
  var maxDistToTravel = container.offsetWidth - elem.offsetWidth; // container width - red box width
  var pos = 0;
  var end = maxDistToTravel;
  var direction = 1;
  
  function frame() { 
   if (pos === end) {
     direction *= -1; // reverses current direction
     end = Math.abs(maxDistToTravel - end); 
   }
   pos += direction;
   elem.style.top = pos + "px";
   elem.style.left = pos + "px";
  }
}

I can add a counter to track how many full out and back loops have occurred and check for some specified maximum number of out and back travels to occur with the following:

function myMove() {
  var container = document.getElementById("container");
  var elem = document.getElementById("animate");
  var id = setInterval(frame, 5);
  var maxDistToTravel = container.offsetWidth - elem.offsetWidth; // container width - red box width
  var pos = 0;
  var end = maxDistToTravel;
  var direction = 1;
  
  var maxLoops = 2; // maximum number of times to perform out and back
  var loopCounter = 0; // tracks how many out and backs have occurred
  
  function frame() { 
   if (pos === end) { // Are we at the end of current direction?
     if (!pos)  // completed loop?
       loopCounter++;
     if (loopCounter === maxLoops) {
       clearInterval(id);
       return; // prevents any further movement
     }
     direction *= -1; // reverses current direction
     end = Math.abs(maxDistToTravel - end); 
   }
   pos += direction;
   elem.style.top = pos + "px";
   elem.style.left = pos + "px";
  }
}

Thanks, the code works. Now could you explain to me why my original code didn’t work? Why wouldn’t the while loop I had do the same thing?

All those extra while loops do is reset both posTop and postLeft back to 0. Why? Because the setInterval executes the frame function every 5 milliseconds. At each iteration you are incrementing both posTop and posLeft by 1 and then check with if statements if they are each to 350. Once both of those variables are equal to 350, then your while loops decrement each of them all the way back to zero, before exiting the while loops. After each while loop completes, both posTop and posLeft are back to zero, so that it why the red box starts back in the upper left hand corner of the blue when it reaches the bottom right hand corner.

I see. Thanks for the information.

You basically want to move the rectangle from top left corner to bottom right corner and then back. The below pictures shows how the animation will look:

com-video-to-gif

I modified your function myMove() to include a variable add. What i do is adding this variable to the element’s left and top position so on setInterval method it moves one pixel by pixel.

The point to note is that add variable becomes -1 when the position reaches 350 and then the rectangle starts coming back to it’s original potion.

You only change the below function and that all it will work.

function myMove() {
  var elem = document.getElementById("animate");   
  var pos = 0;
  var setPos=350
  var add=1;
  var id = setInterval(frame, 5);
  function frame() {
    if (pos == setPos) {
	  setPos=0;
	  add=-1;
      //clearInterval(id);
    } else {
      pos=pos+add; 
      elem.style.top = pos + 'px'; 
      elem.style.left = pos + 'px'; 
    }
  }
}

Another way is using jQuery Animate method which makes it very simple:

First you add an id to your animate div:

<div id ="animate"></div>

Then add the following scripts to your page:

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
	$(document).ready(function() {
        $("#myButton").click(function () {
			$("#animate").animate({
				left: '350px',
				top: '350px'
			},10000,animateBack);
		});
		
		function animateBack(){
			$("#animate").animate({
				left: '0px',
				top: '0px'
			},10000);
		}
	});
</script>	

I have used 2 animate methods, first one brings the rectangle down to the right and second brings it back.

Both animations brings the same effect. Hope you like it.