Jump to content
Search Community

Callbacks when settings progress

Wargasmic test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I have start and complete callbacks set for my nested timelines as well as a bar with a draggable playhead which sets the progress of the parent timeline. When dragging the playhead from left to right the start and end callbacks of each of the nested timelines seems to be called just fine. Even when I click towards the end of the progress bar, all the start and end callbacks seem to be called in order.

 

However, when I drag the play head in reverse or click back towards the start of the progress bar no callbacks are triggered.

 

Is there any way to have callbacks triggered when setting the progress backwards through the timeline? Or is there a way to set a callback at a specific time that will be tiggered from both directions?

 

Cheers!

Link to comment
Share on other sites

Hi Wargasmic,

 

First, this post from Jack should explain the behavior you are seeing

 

Yep, and it might help to visualize a virtual playhead as it moves across the tween - the onStart fires when the playhead moves from 0 to something more than 0, and onComplete fires when the playhead reaches the end of the tween. If you reverse() the tween, the playhead travels in the opposite direction, so neither the onComplete nor the onStart would fire in that case, but the onReverseComplete would fire when the playhead gets to the beginning of the tween. 

 

 

Full post: http://greensock.com/forums/topic/9413-oncomplete-becomes-onstart-when-reversed/

 

if you want a callback to always run whether the timeline is being played forward or in reverse use call()

 

To do this at the beginning of the timeline is very straight-forward

var nested = new TimelineLIte();
nested.call(someFunction) //add callback to beginning of timeline.
  .to(element, 1, {x:200});

Also, worth noting is that the call at the beginning does not need to be added before the tweens are added. You could do it after the entire timeline is built like

var nested = new TimelineLIte();
  .to(element, 1, {x:200});
  .to(element, 1, {y:200});

// ... a bunch more tweens and other code

// then later

nested.call(someFunction, 0) // insert at time of 0 (the beginning of the timeline)

However adding a callback at the end of a timeline nested timeline and wanting it to run when you play its parent timeline in reverse, or scrub backwards over the end of the nested timeline is not so obvious.

 

Using the examples above one would want to simply use call() as the last thing in the timeline like so:

 

var nested = new TimelineLIte();
nested.call(someFunction)
  .to(element, 1, {x:200})
  .call(someFunction) // add callback at the end


// or later on


nested.call(someFunction, nested.duration()) // add callback at a time equal to the duration of the timeline AKA the end.

However, there is a problem with having the callback at the EXACT end of the timeline. Previously, if a callback was at the end of a timeline it would of course fire when the timeline plays forward and completes. However, the previous logic dictated that when the completed timeline was reversed the callback at the end of the timeline would also fire again, because technically the playhead was passing from the end to a previous time thus sort of "passing over" the callback's insertion point.

 

To put this in perspective imagine a timeline gets to the end and a callback at the very end triggers a message to be shown reading "You have reached the end!".

If the user pushed a button to reverse the timeline, the message "You have reached the end!" would show again. Although it could be argued that this was expected, users found it awkward. 

 

The decision was made that if a timeline was at the end and then reversed, the callback at the end would not fire, thus alleviating the issue of the "double callback" as described above.

 

The downside is that when a timeline is complete and nested, it has no awareness of being inside another timeline that is being reversed. So when you reverse the parent timeline from a time greater than the nested timelines end time back towards the beginning... the nested timeline still runs the same logic that says "I'm going to skip running this callback that is at the end of myself because I just executed it when i got done playing forwards". Again, this nested timeline has no idea that you are monkeying around with its parent.

 

So, I acknowledge that can be a bit to wrap your head around and one could argue whether or not the current logic is right or wrong, but we had to make a decision based on user experience and expectations. 

 

So the solution is simply add your callback just a fraction of a second before the end of the timeline. This avoids the playhead from ever being stuck at the exact same time the callback exists. The playhead will now either be before or after that callback... not sitting on it when the timeline completes.

 

Here is code that illustrates how to get your callbacks in nested timelines to fire when you are scrubbing or playing in any direction

//create the parent timelinevar tl = new TimelineLite({onUpdate:updateSlider}),


tl.to("#redBox", 3, {x:550})


//create a nested timeline
var nested = new TimelineLite({onStart:callback, 
                               onStartParams:["nested onStart"],
                               onComplete:callback, 
                               onCompleteParams:["nested onComplete"]
                              });




nested.call(callback, ["nested call beginning"])
nested.to("#blueBox", 1, {x:550})
//instead of adding callback to the end of the timline, add it just a nanosecond before the end of the timeline
nested.call(callback, ["nested call end"], null, "-=0.0001");


tl.add(nested, 1); //add nested a time of 1 second




function callback(message) {
  console.log(message);
}

http://codepen.io/GreenSock/pen/fmbic?editors=001

 

When you run the demo open the console and scrub back and forth. You will see the onStart and onComplete only fire when moving forward. The callbacks added using call() work in both directions.

 

 

  • Like 3
Link to comment
Share on other sites

Is it possible to move a call around the timeline after it has been added? Say I have added a call at 5 seconds and the timeline is 5 seconds long, but then I adjust the length of timeline to 10 seconds so I now need to move the call to 10 seconds rather than 5.

Link to comment
Share on other sites

Yes, but the trick is that you have to find the callback first

What you can do is use getChildren() to get an Array of all the children of the timeline and then search for the callback by name.

 

call() and set() both produce tweens of 0 duration, so the trick is to find a tween that has a target that is the callback function you are looking for:

 

function moveCallback() {
  var children = tl.getChildren();
  for (var i = 0; i < children.length; i++) {
    //if the target of the child is the callback you are looking for then move it
    if(children[i].target === specialCallback){
      console.log("found the callback")
      children[i].startTime(tl.duration()-0.0001)
    }
  } 
  tl.restart();
  tl.eventCallback("onComplete", null)
}

The demo below has a timeline that initially has a callback called specialCallback that fires in the middle.

When the timeline completes it calls moveCallback function that searches for specialCallback and then moves it to the end.

It then restarts the timeline and removes the onComplete (to prevent an infinite loop)

 

http://codepen.io/GreenSock/pen/BLhqD?editors=001

  • Like 1
Link to comment
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.
×
×
  • Create New...