Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
danehansen

onUpdate on TimelineLite

Recommended Posts

Lets say I have a complex TimelineLite instance, which is maybe tweening some DOM elements' CSS properties but also is tweening some pure JS properties which are used in drawing on canvas. Any time one of those canvas related properties updates, I want to call a function that redraws the canvas, but if some of those tweens are overlapping, I want to be sure that I am not redrawing the canvas more than once per tick. Is there a baked in way to achieve this? Or is my best bet to have the drawing method be a pre-throttled method? Cons to that would be that the throttling is then set at a hard ms time, rather than at the current requestAnimationFrame rate.

See the Pen by 30o9uw69 (@30o9uw69) on CodePen

Link to comment
Share on other sites

I forgot to clarify, this TimelineLite instance may also include portions where no canvas related properties are being tweened, and therefore I do not want to call the draw method unnecessarily, which is why I am not putting the onUpdate param on the TimelineLite instance itself, but instead just on the TweenLite instances of canvas properties.

Link to comment
Share on other sites

I guess it depends on the plumbing of the canvas stuff you're using. There are a lot of ways you could do it. Fundamentally, it's not ideal to make your animation engine track when it's appropriate to re-render your canvas stuff because you may change things outside of animations too and you don't want to be locked into constantly managing that. Here are a few approaches off the top of my head:

 

Canvas library tracks changes & updates

Ideally, your canvas objects (the things you're animating/changing) should internally flag the need for re-renders. For example, if you change the "width" of something, it's gonna need to be redrawn but you don't want to immediately do that because you might have 100 other things that also get changed on that tick and you should only re-render ONCE per requestAnimationFrame (aggregate all your changes) like the browsers do. 

 

So perhaps you use getter/setter functions on your elements so that when you set them, they tell their parent canvas "hey, I'm dirty...make sure you redraw me when you have a chance". Like parentCanvas.dirty = true.

 

Then, you TweenLite.ticker.addEventListener("tick", yourRenderFunction) that evaluates "hey, am I dirty? If so, run my redraw routine". 

 

That way, you never have to use onUpdates or manually trigger redraws - the system handles it all automatically in an intelligent way. 

 

Create a plugin that manages it for you.

Alternatively, you could create a simple GSAP plugin that handles all that render stuff for you. The concept is somewhat similar to above, but it's offloading things to a plugin instead of internally managing things in the plumbing of your canvas library. So, for example, a "RenderPlugin":

.to(....{x:100, render:yourCanvas})

(Or you could even just add the canvas reference as a static property on the plugin itself to save yourself some typing, and merely call render:1...totally up to you)

 

When that plugin loads, it adds that "tick" listener to GSAP's ticker kinda like:

TweenLite.ticker.addEventListener("tick", function() {
    if (dirty) {
        yourCanvas.render();
        dirty = false;
    }
});

And in the "set" part of the plugin (this is the function that runs on every tick of each tween), all you'd do is:

set: function(value) {
    dirty = true;
}

That way, anytime any tween sets a value (well, any tween with render:yourCanvas), it'll simply set that simple flag and then only once per tick will it actually call yourCanvas.render(). So 100 tweens could fire and they all set dirty = true and then your tick listener eventually is like "oh, I'm dirty, let me trigger the render now that GSAP is done with everything on this requestAnimationFrame tick."

 

Those are just a few options for you. There are more :) 

 

Does that help at all?

  • Like 2
Link to comment
Share on other sites

ya i'm liking the last option, but i'm thinking of an alteration that i will make all these canvas properties getter/setters on one object, they all flag as dirty for the object to render, then the object has one additional render method that the parent, who owns the timeline, runs onUpdate. then i dont have to mess with adding/removing a listener to TweenLite's tick. thanks!

Link to comment
Share on other sites

I do it like this using getters/setters. The benefit of this way over a plugin is that you can set it without a tween and it will still flag itself as dirty.

class Foo {
  
  dirty = true;

  constructor(x = 0) {
    this._x = x;
  }

  get x() { return this._x; }
  set x(value) {
    if (this._x !== value) {
      this._x = value;
      this.dirty = true;
    } 
  }
}

Simple demo...

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

 

.

  • Like 2
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.
×