friendlygiraffe

Inserting a pause/delay/wait into Timeline

Recommended Posts

I've been digging around looking for the best way of inserting a pause or 'wait' into timeline. I found this thread here, (and I am also an experienced AS3 dev making the transition to Javascript) but it didn't work for me

 

What's the best way of achieving this?

var tl = new TimelineMax({delay:0.5, repeat:3, repeatDelay:2});
tl.add( TweenMax.staggerFrom(['#text1_dc','#main_img_dc','#sky_logo_dc'], 1, {autoAlpha:0}, 0.2) );
tl.add( "PAUSE OF 2 SECONDS WOULD GO HERE" );
tl.add( TweenMax.from('#img_skybox_dc', 0.5, {autoAlpha:0}) );

Share this post


Link to post
Share on other sites

Hello friendlygiraffe,

 

Have you looked into the addPause() method?

 

Taken from TimelineLite Docs:

 

Inserts a special callback that pauses playback of the timeline at a particular time or label. This method is more accurate than using a simple callback of your own because it ensures that even if the virtual playhead had moved slightly beyond the pause position, it'll get moved back to precisely the correct position.
 

Remember, the virtual playhead moves to a new position on each tick (frame) of the core timing mechanism, so it is possible, for example for it to be at 0.99 and then the next render happens at 1.01, so if your callback was at exactly 1 second, the playhead would (in this example) move slightly past where you wanted to pause. Then, if you reverse(), it would run into that callback again and get paused almost immediately. However, if you use the addPause() method, it will calibrate things so that when the callback is hit, it'll move the playhead back to EXACTLY where it should be. Thus, if you reverse() it won't run into the same callback again.

 

addPause() Usage:

//insert a pause at exactly 2 seconds into the timeline
 timeline.addPause(2);
 
 //insert a pause at "yourLabel"
 timeline.addPause("yourLabel");
 
 //insert a pause 3 seconds after "yourLabel" and when that pause occurs, call yourFunction
 timeline.addPause("yourLabel+=3", yourFunction);
 
 //insert a pause at exactly 4 seconds and then call yourFunction and pass it 2 parameters, "param1" and "param2" and bind the current scope to the callback
 timeline.addPause(4, yourFunction, ["param1", "param2"], this);

There is also a pause() method:

 

Taken from TimelineLite Docs:

 

Pauses the instance, optionally jumping to a specific time.
 

If you define a time to jump to (the first parameter, which could also be a label for TimelineLite or TimelineMax instances), the playhead moves there immediately and if there are any events/callbacks inbetween where the playhead was and the new time, they will not be triggered because by default suppressEvents (the 2nd parameter) is true. Think of it like picking the needle up on a record player and moving it to a new position before placing it back on the record. If, however, you do not want the events/callbacks suppressed during that initial move, simply set the suppressEvents parameter to false.

 

pause() Usage:

 //pauses wherever the playhead currently is:
 myAnimation.pause();
 
 //jumps to exactly 2-seconds into the animation and then pauses:
 myAnimation.pause(2);
 
 //jumps to exactly 2-seconds into the animation and pauses but doesn't suppress events during the initial move:
 myAnimation.pause(2, false);

Also this forum topic has some useful information that can lead you in the right direction:

 

http://forums.greensock.com/topic/9336-stop-tween-and-resume-after-pause

 

The above link to that topic goes over using a mix of addPause(), pause(), and delayedCall()

 

Does that help? :)

  • Like 1

Share this post


Link to post
Share on other sites

Hi Jonathan, yes that helps and I looked up addPause() - but I was wondering if it's possible to insert the pause without referencing the exact time?

 

My Timeline is likely to change a lot, so I don't want to keep calculating when it needs to go in, rather than adding it directly to the chain of events, if that makes sense

 

One solution I came up with it tweening an unused object eg:

var tl = new TimelineMax({delay:0.5, repeat:3, repeatDelay:2});
tl.add( TweenMax.staggerFrom(['#text1_dc','#main_img_dc','#sky_logo_dc'], 1, {autoAlpha:0}, 0.2) );
tl.add( TweenMax.from('#nullobject', 2, {autoAlpha:0}) );
tl.add( TweenMax.from('#img_skybox_dc', 0.5, {autoAlpha:0}) );

But I'm sure there's a better way...

Share this post


Link to post
Share on other sites

In your last example you aren't really pausing the timeline, you are just adding time where nothing happens. The same can be accomplished by offseting the insertion of your last add() using the position parameter:

 

var tl = new TimelineMax({delay:0.5, repeat:3, repeatDelay:2});
tl.add( TweenMax.staggerFrom(['#text1_dc','#main_img_dc','#sky_logo_dc'], 1, {autoAlpha:0}, 0.2) );

//add next tween 2 seconds after previous tweens end

tl.add( TweenMax.from('#img_skybox_dc', 0.5, {autoAlpha:0}), "+=2" );

Or if you want to add this same kind of "dead space" to a timeline after its been created, look at the shiftChildren() method which can grab a bunch of elements in a timeline and shift their startTime()

  • Like 2

Share this post


Link to post
Share on other sites

Carl, shiftChildren() is really cool.. i missed that! :)

  • Like 1

Share this post


Link to post
Share on other sites

I have a similar issue, but it cannot be solved by the "+=2" method.

 

The issue is that I need my timeline to be exactly 25 seconds long. It is divided into 5 groups of animations, each 5 seconds long.

 

My last section of the timeline contains two animations, but I need them to happen within the first 2 seconds, leaving a space of 3 seconds to fill.

 

So here is where I would want to use a filler to run for 3 seconds. If I use the "+=3" method, it changes the length of the animation, making it only 22 seconds.

 

I suppose I can just add a dummy animation for an element that doesn't exist or something?

Share this post


Link to post
Share on other sites

Yes an easy way to extend a timeline to fit an exact duration is to add an empty set like this:

 

var timeline = new TimelineLite();
timeline.set({}, {}, 5);
timeline.duration(); // == 5
  • Like 5

Share this post


Link to post
Share on other sites

Hi there,

 

i've got a similar question. I also want to wait for some time, but without adding it to the duration of the whole timeline (e.g. Slider is not moving).

 

One way would be:

function sleep(milliseconds) {
	var start = new Date().getTime();
	for (var i = 0; i < 1e7; i++) {
		if ((new Date().getTime() - start) > milliseconds){
			break;
		}
	}
}

var timeline = new TimelineLite();
timeline.add( TweenLite.fromTo("h1", 0.5, {left:-200,top:-200}, {left:30,top:30}) );
timeline.call(sleep, [2000]);
timeline.add( TweenLite.fromTo("h1", 0.5, {left:30,top:30}, {left:-200,top:-200}) );

I know its nasty. Is there a better way doing it with GSAP directly?

Share this post


Link to post
Share on other sites

Hi and welcome to the GreenSock forums.
 
There's a simpler way using just GSAP. You can use the addPause() method. This one basically pauses the timeline and also can execute a callback exactly when the timeline pauses. Like that you can use the callback to restart the timeline later:

function resumeLine(timeLine, time)
{
  TweenLite.delayedCall(time, function()
  {
    timeLine.play();
  });
}

var timeline = new TimelineLite();
timeline.add( TweenLite.fromTo("h1", 0.5, {left:-200,top:-200}, {left:30,top:30}) );
//pause the timeline and execute the callback to restart it later
timeline.addPause(resumeLine, [timeline, 2]);
timeline.add( TweenLite.fromTo("h1", 0.5, {left:30,top:30}, {left:-200,top:-200}) );

Like that the timeline will pause at that exact time and two seconds later it'll start again.

 

Here's the addPause() method docs reference:

 

http://greensock.com/docs/#/HTML5/GSAP/TimelineLite/addPause/

  • Like 3

Share this post


Link to post
Share on other sites

Thanks, that works almost like a charm!

 

Only problem here: if someone presses play and pause while delayedcall is not yet done it will start playing... I just need some extra logic to deal with that.

 

Youre sample code has some minor typos:

  • TweenLite.delayedCall(time, function(){ ... });
  • timeline.addPause("+=0", resumeLine, [mainTimeLine, 2]);

Share this post


Link to post
Share on other sites

Just create a boolean for the button handler:

var resumeButton = document.getElementById("resumeButton"),
    delayed = false;

resumeButton.onclick = function()
{
  if(!delayed)
  {
    timeline.play();
  }
}

function resumeLine(timeLine, time)
{
  delayed = true;
  TweenLite.delayedCall(time, function()
  {
    delayed = false;
    timeLine.play();
  });
}

Fixed the typo in the code, thanks. Also by default the addPause() method's position is "+=0", so there's no need to specify, unless you want it to happen at a specific position or label.

 

Rodrigo.

  • Like 1

Share this post


Link to post
Share on other sites

Shure "+=0" is default, but you can't leave out the first parameter. Gives me errors.

 

I came up with another idea to fix my last "problem" :-)

function resumeLine(timeLine, time)
{
	var initial_paused_at = timeLine.time();
	TweenLite.delayedCall(time, function(){
		var diff = initial_paused_at-timeLine.time();
		if( (diff < 0.0000001) && (diff > -0.0000001) ) // 'cause float is inaccurate
			timeLine.play();
	});
}

Edit: if you scroll back while pause is running and hit again addpause, you will end up having two delayed calls. The first will be finished first and too early. I came up with another version. Only disadvantage i see so far: you've got a global variable. In case of more than one timeline you can get problems.

var glb_resume = null;
function resumeLine(timeLine, time)
{
    var initial_paused_at = timeLine.time();
    if(glb_resume!=null)
        glb_resume.kill();

    glb_resume = TweenLite.delayedCall(time, function(){
        var diff = initial_paused_at-timeLine.time();
        if( (diff < 0.0000001) && (diff > -0.0000001) )
            timeLine.play();
        
        glb_resume = null;
    });
}

Any feedback is welcome.

Share this post


Link to post
Share on other sites
I've got a similar problem and I stumble upon a very simple solution. bfret-it made a method called "addDelay", and it seems to work very well. Please take a look at:

 


 

Usage: tl.addDelay(4); //easy!

 

I am grateful to this person!

Share this post


Link to post
Share on other sites

I'm glad that helped you, but it seems counter intuitive to the rest of the GSAP API which has a consistent method of timeline placement, with plain numbers being absolute, and "+=0" / "-=0" strings for relative placement.

 

Simply using

timeline.set({}, {}, "+=4");
accomplishes the same thing and requires no additional methods added. If you really prefer to use one this is much shorter, and still consistent with the GSAP API:

TimelineLite.prototype.addSpace = function (position) {
  return this.set({}, {}, position);
};

Usage: tl.addSpace("+=4"); // adds 4 second space at the end of the timeline
I would avoid calling it addDelay, as delay already has a given meaning in GSAP that is different to what this function provides.
  • Like 5

Share this post


Link to post
Share on other sites

Totally agree with Jamie. There's no need to prototype the classes where the same can be added in a simple way, just see reply #8 of this post.

  • Like 1

Share this post


Link to post
Share on other sites

Anyone know how I can remove all pauses added to my timeline?

 

http://codepen.io/nsohail92/pen/LpMqrE

 

I am trying to create a progress graphic that morphs as the progress goes up. I have an update button in my code that when clicked, updates the morph graphic by checking the value of the range input and adding it to the addPause() method. 

 

This works fine until I change the range over and over again. Looks like the pauses are all over the place and doesn't transition smoothly anymore. 

 

Anyone know how I can get this working properly? I am new to GreenSock.

Share this post


Link to post
Share on other sites

Hi nsohail  :)

 

 

how I can remove all pauses added to my timeline

 

pls try this :

var children = tl.getChildren();
for(var i=children.length; i--{
  if(children[i].data=='isPause'){tl.remove(children[i])} 
};
  • Like 3

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.