Jump to content
GreenSock

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

Understanding overwrite:all

Recommended Posts

Working on an app where users can position an SVG on the "stage" and pick an "IN" animation. Uses a from tween that starts offstage and ends wherever the user has positioned the SVG. I pulled the stage setup, some of the code and a few buttons as well as a preselected "already-added" SVG to the Codepen. 

 

There's a master timeline and each SVG becomes an element defined in a new svgObject containing its own timelines for animation onto the stage (the "IN" timeline), animation while on the stage (the "ONSTAGE" timeline) and animation off the stage (the "OUT" timeline). 

 

There can be multiple SVGs and each can have it's own tweens as well as start and end times, positions, etc for each of the 3 timelines. Kind of like this...

 

timeline_setup.svg

 

Right now, I'm just trying to figure out how to dynamically change the "IN" tween if the user clicks a different "IN" option button. Also, trying to figure out how to properly pass new vars like ease changes. My thought was to overwrite the "in" tween and "in" timeline every time a new "in" option is chosen and to do the same for the out tween and timeline. (The onstage timeline might contain multiple options where I'll need to give the user the option to add/chain new vars and tweens)

 

I must not understand the overwrite var and I also must not understand invalidate. I added...

overwrite:'all',onOverwrite:overwrittenTween 

 ... to the tweens but the overwrittenTween function is never running. I'm doing this at the end of each "IN" tween button click listener function...

var theTweens = masterTL.getChildren();
console.log("theTweens",theTweens); 

... (masterTL is the master timeline), and the tweens are all still there and growing with each click of a new "in" tween option. Also, trying to change the ease is not working as I thought it was supposed to. When I add a new ease like this:

activeSVG.twIn.vars.ease = newEase;
activeSVG.twIn.seek(0).invalidate();

The tween seems to break.

 

As hinted at above, for each SVG, there's an object structured like this...

var newSVG = (function() {
  var SVG = {
    el: $('#svg-0'), // the SVG itself
    id: "0",
    gp: $('#gp-0'), // there's a group that wraps each SVG with the same id#
    rotating: null, // GSAP Draggable object
    dragging: null, // GSAP Draggable object
    resizing: null, // GSAP Draggable object
    tlIn: new TimelineMax(), // in timeline
    twIn: null, // in tween
    tlStage: new TimelineMax(), // onstage timeline
    twStage: null, // onstage tween
    tlOut: new TimelineMax(), // out timeline
    twOut: null // out tween
  }
  return SVG;
});

... so I can set all the in/out/stage timelines and tweens for each object there. I bet I'm missing something really obvious.

See the Pen mExpQY by swampthang (@swampthang) on CodePen

Link to post
Share on other sites

Hello swampthang,

 

Have you looked at the various overwrite properties available?

 

http://greensock.com/docs/#/HTML5/GSAP/TweenMax/from/

 

overwrite : String (or integer) - Controls how (and if) other tweens of the same target are overwritten. There are several modes to choose from, but "auto" is the default (although you can change the default mode using theTweenLite.defaultOverwrite property):
  • "none" (0) (or false) - no overwriting will occur.
  • "all" (1) (or true) - immediately overwrites all existing tweens of the same target even if they haven't started yet or don't have conflicting properties.
  • "auto" (2) - when the tween renders for the first time, it will analyze tweens of the same target that are currently active/running and only overwrite individual tweening properties that overlap/conflict. Tweens that haven't begun yet are ignored. For example, if another active tween is found that is tweening 3 properties, only 1 of which it shares in common with the new tween, the other 2 properties will be left alone. Only the conflicting property gets overwritten/killed. This is the default mode and typically the most intuitive for developers.
  • "concurrent" (3) - when the tween renders for the first time, it kills only the active (in-progress) tweens of the same target regardless of whether or not they contain conflicting properties. Like a mix of "all" and "auto". Good for situations where you only want one tween controling the target at a time.
  • "allOnStart" (4) - Identical to "all" but waits to run the overwrite logic until the tween begins (after any delay). Kills tweens of the same target even if they don't contain conflicting properties or haven't started yet.
  • "preexisting" (5) - when the tween renders for the first time, it kills only the tweens of the same target that existed BEFORE this tween was created regardless of their scheduled start times. So, for example, if you create a tween with a delay of 10 and then a tween with a delay of 1 and then a tween with a delay of 2 (all of the same target), the 2nd tween would overwrite the first but not the second even though scheduling might seem to dictate otherwise. "preexisting" only cares about the order in which the instances were actually created. This can be useful when the order in which your code runs plays a critical role.

:)

  • Like 3
Link to post
Share on other sites

Yea, Jonathan. I have looked over that section. That's where I got the idea to set overwrite to all. I had tried auto and some of the other options. I thought the simplest and most complete way was to use 'all' so it would just go ahead and replace the whole thing. The issue here is that the old tweens still exist in the main timeline. Also, I thought that the onOverwrite function was supposed to be called but I'm not seeing that function ever called. 

 

I was able to clean up the timelines by using remove like:

/************************************************************* /\\
 * IN-BUTTON CLICK LISTENER
 ************************************************************** */
$('.in-buttons button').on('click', function(event){

  var gp = $(activeSVG.gp);
  var funcStr = $(this).data("in-func");

  var dur = 1;
  var startTime = 0;
  var firstTime = (activeSVG.twIn == null) ? true : false;
  var newTween = eval(funcStr)(activeSVG,dur,gp,startTime);
  
  if(!firstTime) {
    masterTL.remove(activeSVG.tlIn);
    activeSVG.tlIn.remove(activeSVG.twIn);
  }
  
  activeSVG.twIn = newTween;
  activeSVG.tlIn.add(activeSVG.twIn);
  masterTL.add(activeSVG.tlIn);
  masterTL.play();

  var theTweens = masterTL.getChildren();
  console.log("theTweens",theTweens);
});

Fork is here... 

See the Pen xOWzwa by swampthang (@swampthang) on CodePen

 

I was just trying to figure out if overwrite:all was supposed to handle cleaning up Timelines on its own. Like I said, I'm still trying to parse through the docs (which are great, btw) to see if there's a definitive explanation for what exactly happens when a tween is overwritten. 

 

Still puzzled about how to pass a new ease variable into an existing tween.

Link to post
Share on other sites

When you say "cleaning up timelines on its own", do you just mean killing tweens of that same object on other timelines? Yes, I believe it should (assuming the tweens exist at that time and haven't been released for garbage collection, nor haven't been created yet). Do you have a reduced test case? There's a lot going on in that demo you provided, so it'd be super helpful if you just provided the simplest possible test case showing the issue you're seeing. 

 

As for updating a tween's ease, if you want to do that before the tween starts, you should be able to swap it in directly to the vars object (tween.vars.ease = newEase) and then invalidate() to make sure the tween re-initializes and parses that new data properly. If the tween has already started, you still could do that but beware that when you invalidate() the tween, it'll re-initialize on the next tick and treat the current values as the starting values, so if you want to keep the old starting values, you should call progress(0) on it first to revert the values. And of course if you want to then jump ahead again, just record the old progress first and feed it back in after you've done your invalidate(). 

 

I'd also caution you against trying to swap in a new ease while a tween is running because it'll completely change where the values render, so you'll almost surely see a "jump". That's not a deficiency in GSAP, it's just a logic issue.

 

Does that help at all? 

  • Like 1
Link to post
Share on other sites

You're right, Jack. It's unnecessarily busy. I had paired it down from my actual code but it could be reduced a lot more for this test. Will do that and then post the new pen here. Thanks!

Link to post
Share on other sites

Ok, I've reduced the code to make perusing it much faster. Also, got it working, but I bet I'm reinventing the wheel somehow. Here's the reduced version:

See the Pen xOWzwa by swampthang (@swampthang) on CodePen

Link to post
Share on other sites

Do you have something simple, like "here's a timeline with 1 tween that should be overwritten...and here's another tween that should overwrite it....but it doesn't work...why?" Sorry, I've just got very little time to spare at the moment and there's 91 lines of JS code to mentally parse and 6 buttons to choose from. I may have some time tomorrow evening or next week to dig in further, but this is just too much right now. If you want the best chance of a quick answer, please create a reduced test case that only has the absolutely essential code to reproduce the problem. Thanks!

Link to post
Share on other sites

That's ok, Jack. I've got it working by just overwriting the tweens. For now, that's good enough. 

Link to post
Share on other sites

Hi,

 

I saw your sample and I believe that the best option would be to use invalidate() and clearProps to clear the initialisation data for the GSAP instance and the inline styles added by GSAP, in order to return the object to it's original starting position. When you create an instance GSAP records the start and ending values for the object's properties and then iterates between them, thus avoiding layout trashing (constant and expensive read/write operations on every tick). When you create a new instance on an object that's already being animated and that affects the same properties, GSAP the overwrite manager comes into play and a new instance is created, using as starting values the current ones. If you don't remove the values already applied the new starting values will seem odd, as you're experiencing. When you use clearProps, the only values are the ones given by the original CSS styles or attributes and not those applied by GSAP.

 

Here's how I'd do it:

  1. Pause the current instance and record it's progress.
  2. Create a new instance. This kills the current instance.
  3. Use clearProps on the element.
  4. Create a new instance and set it's progress to the previous one.

Here are some samples using the bezier plugin, but the principle is the same:

 

See the Pen rarBrK by rhernando (@rhernando) on CodePen

 

See the Pen ZYjYjO by rhernando (@rhernando) on CodePen

 

See the Pen xbJKWQ by GreenSock (@GreenSock) on CodePen

  • Like 4
Link to post
Share on other sites

Thanks, Rodrigo! Looking at those samples now.

Link to post
Share on other sites

I think my thick skull is beginning to get the picture. I was not successfully implementing invalidate() and needed to deal with Draggable on the tweened object. Got a clue from Rodrigo when he said:

 

When you create an instance GSAP records the start and ending values for the object's properties and then iterates between them...

 

 

So, I changed the tween from a "from" tween to a "fromTo" tween. I'm able now to handle user changes because there are several variables available at all times.

  1. There's an onRelease callback on a Draggable object that returns an endX and endY variable.
  2. The fromTo Tween contains a vars.startAt object that stores the from x/y vars in an object.

So, if I drag the object to a new position, the endX/endY values are available and I can snag the startAt x/y values from the tween object. 

 

I built a new Codepen to play with all this and learn how things fire - when, what variables are returned, etc. Anyone who is interested in taking a look, it's here. 

 

See the Pen qNrEQq by swampthang (@swampthang) on CodePen

 

For example,

See the Pen mEKomP by swampthang (@swampthang) on CodePen

I figured out that if you set repeat to -1 (infinite repeat) the onComplete callbacks never fire (you can see the commented repeat on line 33). Little stuff like that can make a huge difference once you've built a big project and all of a sudden something isn't working like you think it should.

  • Like 2
Link to post
Share on other sites

Hi,

 

Nice sample, works really well. Glad that you were able to figure it out.

 

By now you're getting into the GSAP way (since today there's a way for absolutely everything, why not GSAP, right? ;)) and how things work under the hood. From now on, things will get simpler and easier for you, trust me.

 

Great job and happy tweening!!

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

×