smod smod - 3 months ago 16
CSS Question

clearInterval issue (jquery, javascript)

I have some problems with a school assignment. Anyway, when I use startInterval, I assign and intervalID so I can later clear the interval. Unfortunately, it does not clear when you press the "stop this madness" button. Anyone know why?

(if you are wondering about all the background color stuff I used a jquery plugin which I didn't add to this snippet)



var intervalID;
$('.gal').click(function() {
var photoID = jQuery(this).attr("id");
alert(alerts[photoID]);
});

var alerts = {
//row one
"1:1": "This animal is a penguin!",
"1:2": "This animal is a lion!",
"1:3": "This animal is a cat!",
"1:4": "This animal is a giraffe!",
//row two
"2:1": "Cool looking ancient building!",
"2:2": "Cool looking modern building!",
"2:3": "Cool building from dubai!",
"2:4": "Cool building by the water!"
};

$("#stop").click(function() {
clearInterval(intervalID);
});

$(window).load(function() {
animate();
});

function animate() {
intervalID = setInterval(function() {
var width = 25;
$(".gal").animate({
'marginLeft': '-=25px'
});
$(".gal").animate({
'marginLeft': '+=25px'
});
$("#title").animate({
'marginLeft': '+=' + width + 'px'
}, "slow");
$("#title").animate({
'marginLeft': '-=' + width + 'px'
}, "slow");
$("body").animate({
'backgroundColor': 'lightyellow'
}, 1000);
$("body").animate({
'backgroundColor': 'yellow'
}, 1000);
$("body").animate({
'backgroundColor': 'orange'
}, 1000);
$("body").animate({
'backgroundColor': 'red'
}, 1000);
$("body").animate({
'backgroundColor': 'lightpink'
}, 1000);
$("body").animate({
'backgroundColor': 'pink'
}, 1000);
$("body").animate({
'backgroundColor': 'purple'
}, 1000);
$("body").animate({
'backgroundColor': 'blue'
}, 1000);
$("body").animate({
'backgroundColor': 'lightblue'
}, 1000);
$("body").animate({
'backgroundColor': 'cyan'
}, 1000);
$("body").animate({
'backgroundColor': 'green'
}, 1000);
$("body").animate({
'backgroundColor': 'lightgreen'
}, 1000);
}, 0.1);
}

body {
background-color: lightyellow;
}
#title {
display: block;
/*position:absolute;*/
}
.gal {
display: block;
margin: 20px;
width: 250px;
height: 200px;
border: 5px solid black;
}
#stop {
position: fixed;
bottom: 0;
right: 0;
border: 3px solid red;
}

<!DOCTYPE html>
<html lang="en">

<head>
<title>JS Functions</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/jquery.color-animation/1/mainfile"></script>

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>

<body>
<div class="container-fluid">
<button id="stop" class="btn-warning">Stop This Madness!</button>
<h1 id="title" style="margin-left: 20px;" class="text-primary">Image Gallery:</h1>
<div class="row">
<div class="col-md-3">
<img id="1:1" src="http://ngm.nationalgeographic.com/2012/11/emperor-penguins/img/02-airborne-penguin-exits-water_1600.jpg" class="gal">
</div>
<div class="col-md-3">
<img id="1:2" src="http://efdreams.com/data_images/dreams/lion/lion-03.jpg" class="gal">
</div>
<div class="col-md-3">
<img id="1:3" src="https://s3.graphiq.com/sites/default/files/stories/t2/tiny_cat_12573_8950.jpg" class="gal" />
</div>
<div class="col-md-3">
<img id="1:4" src="https://upload.wikimedia.org/wikipedia/commons/0/02/Giraffe_Ithala_KZN_South_Africa_Luca_Galuzzi_2004.JPG" class="gal">
</div>
</div>
<div class="row">
<div class="col-md-3">
<img id="2:1" src="http://cdn.mos.cms.futurecdn.net/78b7453e70727aae7eed989ff2cee83d.jpg" class="gal" />
</div>
<div class="col-md-3">
<img id="2:2" src="http://thegrumpyoldlimey.com/images/buildings/dome_feature.jpg" class="gal" />
</div>
<div class="col-md-3">
<img id="2:3" src="https://d3dupjkkwlat3o.cloudfront.net/399433011453/2071971/576xN?1410992818" class="gal" />
</div>
<div class="col-md-3">
<img id="2:4" src="http://www.jazzhostels.com/blog/wp-content/uploads/2014/09/hemispheric-photo-valencia-spain-cc.jpg" class="gal">
</div>
</div>
</div>
<script></script>
<script src="script.js"></script>
</body>

</html>




Answer

Two general points you need to know:

  1. The delay for setInterval() is specified in milliseconds, and you have specified a delay of 0.1 - which means you've tried to schedule your function to run 10000 times per second. In practice JS doesn't let you go under 5ms: any shorter delay specified will be rounded up, but still that means your function will run approximately 200 times per second.

  2. When you call .animate() multiple times on the same element, as you are doing with .gal, #title, and body, it queues up additional animations that will be run after the current ones finish.

Putting those two points together, and every 5ms your code adds multiple animations to the queue, each of which takes a lot longer than 5ms. So even when you call clearInterval(), you've already got tons of animations still queued up and they will take a long time to complete.

You can stop animations currently underway and clear a given element's animation queue using the .stop() method:

$(".gal").stop(true);

But trying to manage ongoing animations using setInterval() is always going to be a bit clunky, especially where you have multiple animations with different times specified. But fortunately the .animate() method lets you provide a callback function that will run after the animation completes, so you can schedule additional processing from there.

You asked in a comment about whether there's a more efficient way to manage the animations: for all those colour changes I'd suggest using an array, then when the current colour change completes call .animate() again for the next colour in the array.

So maybe something like the following, noting that I've removed some of the code that didn't relate to the animations in order to make this answer a bit shorter, and I've split the animation code into three functions to make it clearer for you what each one is doing:

$("#stop").click(function() {
  $(".gal, #title, body").stop(true);
});

$(window).load(function() {
  animateGallery();
  animateTitle();
  animateBody();
});

function animateGallery() {
  $(".gal").animate({
    'marginLeft': '-=25px'
  }, "slow").animate({
    'marginLeft': '+=25px'
  }, "slow", animateGallery); // note the function set as final argument
                              // - it will be called when animation finishes
}

function animateTitle() {
  var width = 25;
  $("#title").animate({
    'marginLeft': '+=' + width + 'px'
  }, "slow").animate({
    'marginLeft': '-=' + width + 'px'
  }, "slow", animateTitle); // note the function set as final argument
}
    
var colors = ['lightyellow', 'yellow', 'orange', 'red', 'lightpink', 'pink', 'purple', 'blue', 'lightblue', 'cyan', 'green', 'lightgreen'];
var currentColor = 0;

function animateBody() {
  $("body").animate({
    'backgroundColor': colors[currentColor]
  }, 1000, animateBody); // note the function set as final argument
  currentColor = (currentColor + 1) % colors.length;
}
#title { display: block; }
.gal { display: block; margin: 20px; width: 250px; height: 200px; border: 5px solid black; }
#stop { position: fixed; z-index: 100; bottom: 0; right: 0; border: 3px solid red; }
<!DOCTYPE html>
<html lang="en">
<head>
  <title>JS Functions</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <script src="//cdn.jsdelivr.net/jquery.color-animation/1/mainfile"></script>
</head>
<body>
  <div class="container-fluid">
    <button id="stop" class="btn-warning">Stop This Madness!</button>
    <h1 id="title" style="margin-left: 20px;" class="text-primary">Image Gallery:</h1>
    <div class="row">
      <div class="col-md-3">
        <img id="2:1" src="http://cdn.mos.cms.futurecdn.net/78b7453e70727aae7eed989ff2cee83d.jpg" class="gal" />
      </div>
      <div class="col-md-3">
        <img id="2:2" src="http://thegrumpyoldlimey.com/images/buildings/dome_feature.jpg" class="gal" />
      </div>
      <div class="col-md-3">
        <img id="2:3" src="https://d3dupjkkwlat3o.cloudfront.net/399433011453/2071971/576xN?1410992818" class="gal" />
      </div>
      <div class="col-md-3">
        <img id="2:4" src="http://www.jazzhostels.com/blog/wp-content/uploads/2014/09/hemispheric-photo-valencia-spain-cc.jpg" class="gal">
      </div>
    </div>
  </div>
</body>
</html>