Pausing an animation with jQuery

· Leave a comment · in JavaScript, jQuery

Starting an animation with jQuery is easy.

Stopping an animation with jQuery is easy.

But what if we want to “pause” and restart the animation?

Well, not so easy – so I dug in and figured a way to make this work cross-browser.

We are going to move a Constitution class Starship image horizontally across the screen:

For fun, we will use a field of stars as a background:

Our play and pause buttons:

Markup
The ship image will be contained in a parent element.

We have three attributes on our image:
data-distance – Distance the ship will travel
data-duration – Duration of the animation in milliseconds
data-loop – Loop the animation, true or false

The initial state of our control is “paused”.

<div class="space">
	<img class="ship" src="ship2.png" data-distance="650" data-duration="5000" data-loop="true" />
</div>
<input class="controls paused" type="image" src="btn_play.png">

CSS

.space {
	width:650px;
	height:100px;
	position:relative;
	background:#000 url(bg_space.jpg);
	overflow:hidden;
	clear:both;
}
.ship {
	position:absolute;
	top:20px;
	left:0px;
}

jQuery
The first shot I took at this, I simply used “.stop(true)” to stop the animation, then called the animation again to start. Thinking that the animation would just pick up where it left off – and it does, but – the position of the image is correct, not the duration. This causes the animation to slow down after it has been stopped and restarted.

Here’s why.

The distance the image will move is from 0-650px using it’s “left” CSS property. The duration is 5000.
The animation is a calculation using both of these values.

So if we stop it midway, say at 325px, then restart it, the full duration gets applied. This unwantedly causes the animation to be slower since the image will now move the remainder of the way but uses the original duration.

What we need is a new calculated duration based on the remaining distance the image needs to travel. This assures consistent, smooth animation. So I wrote some simple math to calculate that new duration.

Keep in mind that this is based on using the CSS “left” property to move the animation. You can adjust the code to use “right”, etc. I was going to make the code more agnostic but it would have increased the code block. Wanted to keep it as small as possible for this post.

Note: On the jQuery website, “As of jQuery 1.7, stopping a toggled animation prematurely with .stop() will trigger jQuery’s internal effects tracking.”

So now it appears jQuery “remembers” the state of the animation, which I thought would be an issue but turns out to actually help.

//animate object
function animateObj(obj,_distance,_duration){
	if( typeof _distance === "undefined" || typeof _duration === "undefined" ){
		var _distance = parseFloat($(obj).attr("data-distance"));
		var _duration = parseFloat($(obj).attr("data-duration"));
	}
	
	//calc new duration
	var _pos = parseFloat( $(obj).css("left") );
	var _duration = _duration - (_duration / ( _distance / _pos ));

	//animate object
	$(obj).stop(true).animate({
		left:_distance
	},_duration,"linear",function(){
		$(this).css("left","0"); //reset
		if( $(this).attr("data-loop") === "true" ){
			animateObj( this,
				parseFloat($(obj).attr("data-distance")),
				parseFloat($(obj).attr("data-duration"))
			);
		}
	});
}

//pause animation
function pauseAnim(obj){
	$(obj).stop(true);
}

$(document).ready(function(){
	//toggle buttons
	$(".controls").click(function(){
		if( $(this).hasClass("paused") ){
			$(this).attr("src","btn_pause.png");
			$(this).removeClass("paused");
			animateObj( $(".ship") );
		}
		else{
			$(this).attr("src","btn_play.png");
			$(this).addClass("paused");
			pauseAnim( $(".ship") );
		}
	});
});

Put it all together and you can see the full working examples here.

You can probably update this to work with opacity also, I did some initial tests but haven’t had time to confirm that the calculations work for opacity.

Tested in:
jQuery version 1.7.2, 1.8
FF 3.6+, Safari, Chrome, IE8+
iOS

Great books are available on JavaScript and jQuery.

This entry was posted in JavaScript, jQuery and tagged , , , .
Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

To include code in your comment: Paste your code in the comment form, select it and then click the language link button below. This will wrap your code in a <pre> tag(or shortcode) and format it when submitted.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="">