Jump to content
Search Community

onComplete without tween

BradLee test
Moderator Tag

Go to solution Solved by OSUblake,

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

Hey all,

 

My specific question is - is there a way to declare an onComplete() without attaching it to a tween in a timeline. For example, I have: 

 

    tl.to(btn,  timing, {boxShadow: shadowLowered, onComplete: () => { myFunc(); })

 

what I would like to do is separate the tween and the onComplete like this:

 

    tl.to(btn,  timing, {boxShadow: shadowLowered})

      .({onComplete: () => { myFunc }})

 

 

When animations start getting complicated this way of writing would make things a lot easier to read. A more general question is, are there examples of 'neat' ways of writing complex timelines. For example, I came across this a while back that makes my life a lot easier - 

 

  var tl = new TimelineLite({paused: true});

 

  tl.to ....

 

  tl.play();

 

This allows me to 1st declare a timeline, then define it, then play it, making things very readable, rather than trying to do all 3 steps at once.

 

 

Link to comment
Share on other sites

To call a function from any time in a timeline you can use call()

 

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

 

To answer your question about neat ways of building complex timelines, we are big fans of creating functions that return timelines to a master timeline via add().

This technique is explained here:

http://greensock.com/forums/topic/12361-using-functions-to-build-a-timeline/?p=51321

 

There is a link in there to our homepage animation which is a great example of this technique

  • Like 2
Link to comment
Share on other sites

  • Solution

Can you explain what your definition of "neat" is? That's pretty subjective. For example, some people think this is neat...

var combining = "all", 
    your = "vars",
    like = "this";
But that's garbage to me. Not only is it very error-prone, but it's effin' annoying trying to add, remove, or reorder the declarations, especially the first and last ones.

 

Preferences aside, lets look at how a tween is created.

TweenLite.to(target: Object, duration: Number, vars: Object): TweenLite;
 

The vars object will be added to the tween, so this is true.

var config = {
  x: 100
};

var tween = TweenLite.to(element, 1, config);

console.log(config === tween.vars); // => true
 

 

That means that they are the same object, so you can access and change either one later on. Since callbacks aren't tweened, you can change them on the fly. Can you figure out what's going to happen here?

var config = {
  x: 100,
  onComplete: function() {
    console.log("I'm the callback");
  }
};

var tween = TweenLite.to("div", 0.1, config);

config.onComplete = function() {
  console.log("No you're not!!!");
};

TweenLite.delayedCall(0.2, () => {
  
  tween.vars.onComplete = function() {
    console.log("Yes I am!!!");
  };
  tween.restart();
});
 

 

See the Pen 8c03b49b9c1a9dcadf9f46871f1b157e?editors=0011 by osublake (@osublake) on CodePen

 

I don't think a lot people realize this, but unless there's a call for an immediate render, a tween/timeline does not start playing as soon as it's created. Your animation will start on the next computer cycle, which means you really don't need to pause your timelines unless you want to defer its playback. But more importantly, this means that you can split the creation of your timeline up into different chunks. It doesn't have to be one big monolithic block of code. So using loops and other functions to create your timeline is perfectly ok. You can even conditionally add stuff to a timeline like this.

tl.to(element, 1, { x: 100 });

if (someCondition) {
  tl.to(element, 1, { y: 100 });
}

tl.to(element, 1, { x: 0 });
 

 

zfWYlXv.jpg?1

 

 

So getting back to your idea about adding a callback using destructuring assignment...

tl.to(btn, timing, {boxShadow: shadowLowered})
  .({ onComplete: () => { myFunc }})
 

It might be possible, but I don't how to go about doing it. You need to get a reference to the last tween. They're added to a linked list, so it should be the timeline's _last property, but that's not a public property, and probably for a good reason. 

 

I think a much safer approach would be to use a public method. Here's a few that might help you out.

 

.add() - add a callback to timeline

.getChildren() - get tweens from a timeline

.getTweensOf() - get tweens of an object from timeline

.recent() - get the most recently added item in the timeline

 

See if you can figure out how the different callbacks are being created and fire in the correct order. It might be confusing at first, especially the one that uses .recent().

 

See the Pen be47dfb513f54026ec591dc444903f69?editors=0011 by osublake (@osublake) on CodePen

 

My approach to complex timelines is to avoid them if possible. I generally don't use a master timeline unless it's for something like the GreenSock home page animation.

 

I first try to see if I can logically group things together into arrays. From there you can simplify and group a lot of things together by chaining methods calls like filter, map, and reduce. Reduce is really useful because you can use a timeline as the accumulator object.

See the Pen e950b59669be60ae57cb43550d5192df?editors=0010 by osublake (@osublake) on CodePen

 

I also try to create as many abstractions as possible, separating my code into smaller, reusable pieces. Here's a demo where I mess around with mixins. A mixin is a subclass that you can apply to another class to create a new type of class. On the surface it may look a little silly, maybe even stupid, but what it's doing is a really useful pattern for large or complex apps. 

 

I have 2 mixins, one to create content, and the other to animate content. To decouple my person classes, I use an event emitter/dispatcher. It might look the person cards are being animated as timeline, but there are no direct links between the different cards. When a card's animation has finished, it sends out a message letting any subscribers know that the next animation should be begin.

 

See the Pen ?editors=0010 by osublake (@osublake) on CodePen

  • Like 4
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...