1

I am coding a page that increments the CSS top and left properties in order to simulate an animation with two stars moving around a button. I calculated the measurements, and it looked fine at first. However, after several minutes, the stars become desynchronized, and don't change animation at the same time. They should be reaching a corner at the same time. Can someone please explain why this is, and how I could fix it? My JSFiddle is here: https://jsfiddle.net/MCBlastoise/1503x4tr/12/

And here is my code:

body {
 margin:0px;
}
.heading {
 text-align:center;
 font-family:'Bungee Shade', Courier New, Courier, Lucida Sans Typewriter, Lucida Typewriter, monospace;
 color:green;
 font-weight:bold;
 font-size:30px;
 margin-top:0px;
}
.text {
 color:red;
 font-family:'Josefin Sans', Futura, Trebuchet MS, Arial, sans-serif;
 font-size:21px;
 text-align:justify;
 margin-top:-15px;
}
br {
 line-height:500%;
}
.container {
 position:relative;
 width:350px;
 height:350px;
 margin-top:42px;
 margin-left:auto;
 margin-right:auto;
}
.star {
 width:40px;
 height:40px;
 position:absolute;
}
#starOne {
 top:0px;
 left:0px;
}
#starTwo {
 top:310px;
 left:310px;
}
.button {
 width:250px;
 height:250px;
 border-style:solid;
 border-color:red;
 border-width:5px;
 border-radius:60px;
 text-align:center;
 position:absolute;
 bottom:50px;
 left:50px;
}
.button:hover {
 background-color: #7CFC00;
 cursor:pointer
}
.button-text {
 font-family:'Righteous', Courier New;
 color:#9400D3;
 font-size:76px;
 line-height:125%;
}
#compliment {
 text-align:center;
 font-family:'VT323', Candara, Calibri, Segoe, Segoe UI, Optima, Arial, sans-serif;
 color:#ffd400;
 font-size:50px;
}
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="Complement.css">
<link type="text/css" rel="stylesheet" href="https://fonts.googleapis.com/css?family=Bungee+Shade|Josefin+Sans|VT323|Righteous">
<title>The Compliment Machine</title>
</head>
<body>
<h2 class="heading">The Compliment Machine</h2>
<p class="text">In the interest of spreading holiday cheer, I have designed this website with one goal in mind. Pressing the button below will randomly generate a compliment. Hopefully, this little experiment will brighten up your day.</p>
<div class="container" id="container">
<img src="Star.png" class="star" id="starOne">
<div class="button" onclick="timedFunction()" onmouseenter="startingFunction(), startingFunction2()" onmouseleave="endFunction()"> <span class="button-text">Click me!</span> </div>
<img src="Star.png" class="star" id="starTwo">
</div>
<br>
<p id="compliment"></p>

<script>
 var userName = prompt("What is your name?");
 var generatedUserName = userName === null || userName === "";
 var compliment = [
  "Have a nice day",
  "you contribute to society",
  "Always be yourself",
  "you are a wonderful person",
  "Keep up the good work",
  "never stop believing in yourself",
  "you have a great sense of humor",
  "You should feel proud of yourself",
  "Never stop trying",
  "you are a winner"
 ];
</script>

<script>
 function timedFunction() {  
  document.getElementsByTagName("DIV")[0].style.display = "none";
  document.getElementsByTagName("DIV")[1].style.display = "none";
  document.getElementsByTagName("IMG")[0].style.display = "none";
  document.getElementsByTagName("IMG")[1].style.display = "none";
  var repeater = setInterval(inspiration, 1000);
 }
 var inspiration = function inspire() {
  var result = Math.random();
  
  //This code block checks for null, undefined, and other falsy values in the prompt.
  if (generatedUserName) {
   if (0 <= result && result < 0.11) {
    userName = "my friend";
   }
   if (0.21 <= result && result < 0.31) {
    userName = "my friend";
   }
   if (0.41 <= result && result < 0.51) {
    userName = "my friend";
   }
   if (0.71 <= result && result < 0.81) {
    userName = "my friend";
   }
   if (0.81 <= result && result < 0.91) {
    userName = "my friend";
   }
   if (0.11 <= result && result < 0.21) {
    userName = "My friend";
   }
   if (0.31 <= result && result < 0.41) {
    userName = "My friend";
   }
   if (0.51 <= result && result < 0.61) {
    userName = "My friend";
   }
   if (0.61 <= result && result < 0.71) {
    userName = "My friend";
   }
   if (0.91 <= result && result < 1) {
    userName = "My friend";
   }
  }
  
  //This code block changes the sentence with ID 'compliment' randomly, based on the value of the variable 'result'.
  if (0 <= result && result < 0.11) {
   document.getElementById("compliment").innerHTML = compliment[0]+", "+userName+"!";
  };
  if (0.11 <= result && result < 0.21) {
   document.getElementById("compliment").innerHTML = userName+", "+compliment[1]+".";
  };
  if (0.21 <= result && result < 0.31) {
   document.getElementById("compliment").innerHTML = compliment[2]+", "+userName+".";
  };
  if (0.31 <= result && result < 0.41) {
   document.getElementById("compliment").innerHTML = userName+", "+compliment[3]+".";
  };
  if (0.41 <= result && result < 0.51) {
   document.getElementById("compliment").innerHTML = compliment[4]+", "+userName+"!";
  };
  if (0.51 <= result && result < 0.61) {
   document.getElementById("compliment").innerHTML = userName+", "+compliment[5]+".";
  };
  if (0.61 <= result && result < 0.71) {
   document.getElementById("compliment").innerHTML = userName+", "+compliment[6]+".";
  };
  if (0.71 <= result && result < 0.81) {
   document.getElementById("compliment").innerHTML = compliment[7]+", "+userName+".";
  };
  if (0.81 <= result && result < 0.91) {
   document.getElementById("compliment").innerHTML = compliment[8]+", "+userName+".";
  };
  if (0.91 <= result && result < 1) {
   document.getElementById("compliment").innerHTML = userName+", "+compliment[9]+".";
  };
 }
 var i = 0;
 function limitedFunction() {
  inspiration();
  i++;
  if (i === 5) {
   document.getElementsByTagName("DIV")[0].style.display = "none";
   document.getElementsByTagName("DIV")[1].style.display = "none";
   document.getElementsByTagName("IMG")[0].style.display = "none";
   document.getElementsByTagName("IMG")[1].style.display = "none";
  }
 }
</script>

<script>
 var starOne = document.getElementById("starOne");
 var starTwo = document.getElementById("starTwo");
 var posLeft = 0;
 var posTop = 0;
 var posLeft2 = 310;
 var posTop2 = 310;
 
 var startingFunction = function starterFunction() {
  toRight = setInterval(moveRight, 1);
 }
 var startingFunction2 = function starterFunction2() {
  toLeft = setInterval(moveLeft, 1);
 }
 
 //The following four functions apply to the first star, which begins at the top-left.
 function moveRight() {
  posLeft++;
  starOne.style.left = posLeft + 'px';
  if (starOne.style.left === "310px") {
   clearInterval(toRight);
   toBottom = setInterval(moveDown, 1);
  }
 }
 
 function moveDown() {
  posTop++;
  starOne.style.top = posTop + 'px';
  if (starOne.style.top === "310px") {
   clearInterval(toBottom);
   toLeft2 = setInterval(moveLeft2, 1);
  }
 }
 
 function moveLeft2() {
  posLeft--;
  starOne.style.left = posLeft + 'px';
  if (starOne.style.left === "0px") {
   clearInterval(toLeft2);
   toTop2 = setInterval(moveUp2, 1);
  }
 }
 
 function moveUp2() {
  posTop--;
  starOne.style.top = posTop + 'px';
  if (starOne.style.top === "0px") {
   clearInterval(toTop2);
   startingFunction();
  }
 }
 
 
 //The following four functions apply to the second star, which begins at the bottom-right.
 function moveLeft() {
  posLeft2--;
  starTwo.style.left = posLeft2 + 'px';
  if (starTwo.style.left === "0px") {
   clearInterval(toLeft);
   toTop = setInterval(moveUp, 1);
  }
 }
 
 function moveUp() {
  posTop2--;
  starTwo.style.top = posTop2 + 'px';
  if (starTwo.style.top === "0px") {
   clearInterval(toTop);
   toRight2 = setInterval(moveRight2, 1);
  }
 }
 
 function moveRight2() {
  posLeft2++;
  starTwo.style.left = posLeft2 + 'px';
  if (starTwo.style.left === "310px") {
   clearInterval(toRight2);
   toBottom2 = setInterval(moveDown2, 1);
  }
 }
 
 function moveDown2() {
  posTop2++;
  starTwo.style.top = posTop2 + 'px';
  if (starTwo.style.top === "310px") {
   clearInterval(toBottom2);
   startingFunction2();
  }
 }
 
 
 //The following function cancels the animation when the mouse leaves the button.
 function endFunction() {
  //The following four if statements apply to the first star, which begins in the top-left.
  if (0 <= posLeft && posLeft <= 310 && posTop === 0) {
   clearInterval(toRight);
  }
  if (0 <= posTop && posTop <= 310 && posLeft === 310) {
   clearInterval(toBottom);
  }
  if (0 <= posLeft && posLeft <= 310 && posTop === 310) {
   clearInterval(toLeft2);
  }
  if (0 <= posTop && posTop <= 310 && posLeft === 0) {
   clearInterval(toTop2);
  }
  
  //The following four if statements apply to the second star, which begins in the bottom-right.
  if (0 <= posLeft2 && posLeft2 <= 310 && posTop2 === 310) {
   clearInterval(toLeft);
  }
  if (0 <= posTop2 && posTop2 <= 310 && posLeft2 === 0) {
   clearInterval(toTop);
  }
  if (0 <= posLeft2 && posLeft2 <= 310 && posTop2 === 0) {
   clearInterval(toRight2);
  }
  if (0 <= posTop2 && posTop2 <= 310 && posLeft2 === 310) {
   clearInterval(toBottom2);
  }
  posLeft = 0;
  posTop = 0;
  posLeft2 = 310;
  posTop2 = 310;
  starOne.style.top = posTop + 'px';
  starOne.style.left = posLeft + 'px';
  starTwo.style.top = posTop2 + 'px';
  starTwo.style.left = posLeft2 + 'px';
 }
</script>

</body>
</html>

1 Answers1

0

How about you use an alternative approach i.e. use css animation property for the animation and don't use setInterval at all. Use the keyframes and animate the stars on hover. Here is the working example

var starOne = document.getElementById("starOne");
var starTwo = document.getElementById("starTwo");
var posLeft = 0;
var posTop = 0;
var posLeft2 = 310;
var posTop2 = 310;
  document.getElementById("btn").addEventListener("mouseover",function(){
  starOne.classList.add("topStarAnimate");
   starTwo.classList.add("bottomStarAnimate");
});
  document.getElementById("btn").addEventListener("mouseleave",function(){
  starOne.classList.remove("topStarAnimate");
   starTwo.classList.remove("bottomStarAnimate");
});
body {
 margin:0px;
}
.heading {
 text-align:center;
 font-family:'Bungee Shade', Courier New, Courier, Lucida Sans Typewriter, Lucida Typewriter, monospace;
 color:green;
 font-weight:bold;
 font-size:30px;
 margin-top:0px;
}
.text {
 color:red;
 font-family:'Josefin Sans', Futura, Trebuchet MS, Arial, sans-serif;
 font-size:21px;
 text-align:justify;
 margin-top:-15px;
}
br {
 line-height:500%;
}
.container {
 position:relative;
 width:350px;
 height:350px;
 margin-top:42px;
 margin-left:auto;
 margin-right:auto;
}
.star {
 width:40px;
 height:40px;
 position:absolute;
}
#starOne {
 top:0px;
 left:0px;
}
#starTwo {
 top:310px;
 left:310px;
}
@keyframes topstar {
0%,100%{
  top:0px;
  left:0px;
}
25%{
 top:0px; 
 left:310px;
}
50%{
  top:310px;
  left:310px;
}
75%{
  top:310px;
  left:0px;
}
}
@keyframes bottomstar {
0%,100%{
  top:310px;
  left:310px;
}
25%{
 top:310px; 
 left:0px;
}
50%{
  top:0px;
  left:0px;
}
75%{
  top:0px;
  left:310px;
}

}
.topStarAnimate{
  animation: topstar 4s infinite;
}
.bottomStarAnimate{
  animation: bottomstar 4s infinite;
}
.button {
 width:250px;
 height:250px;
 border-style:solid;
 border-color:red;
 border-width:5px;
 border-radius:60px;
 text-align:center;
 position:absolute;
 bottom:50px;
 left:50px;
}
.button:hover {
 background-color: #7CFC00;
 cursor:pointer
}
.button-text {
 font-family:'Righteous', Courier New;
 color:#9400D3;
 font-size:76px;
 line-height:125%;
}
<!DOCTYPE html>
<title>The Compliment Machine</title>
<body>
<div class="container" id="container">
<img src="Star.png" class="star" id="starOne">
<div class="button" onclick="timedFunction()" id="btn"> <span class="button-text">Click me!</span> </div>
<img src="Star.png" class="star" id="starTwo">
</div>
<br>
<p id="compliment"></p>


</body>
acesmndr
  • 8,137
  • 3
  • 23
  • 28
  • I understand that keyframes are an alternative method to create animations. However, my original question was why the two would reach a corner at separate times with the current animation. If any solutions to the issue are presented, I would rather they use the method already in use. – MCBlastoise Jan 24 '17 at 02:25
  • I am not 100% sure about this but it might be due to the drift in the setInterval calls that you are seeing the animation not working properly. You can refer to the first answer of [this question](http://stackoverflow.com/questions/985670/will-setinterval-drift) to realize that the *setInterval drifts by certain milliseconds* on each calls which when added up in minutes results in larger noticable difference. Thus I prefer and recommend using the css for animation for larger duration. – acesmndr Jan 24 '17 at 03:53
  • Thank you. I thought it might be something like this. I will refer to your answer on keyframes now. – MCBlastoise Jan 24 '17 at 04:05