Jump to content
Search Community

TimelineMax call() result not affecting next tween variable

sigmundsquirrel 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 a series of tweens in a Timeline object. All the x/y values are preset, except the last one which depends on a dynamic location. I have a function to locate that x/y value pair. If I place it at the beginning of my animation function, just before I start the Timeline, it works fine. But that's a problem because the dynamic location could change before the specific tween is reached.

 

What I want to do is call the function to calculate the x/y values just before the Timeline Tween is triggered. I have tried this with the call() method and it calls the function. I even call an alert function to trace out the values to prove that they are correct. But the Timeline tween does not change to the new values.

 

Here's a simplified example. If I do this, it works:

 

var distanceX;
var distanceY;
var mytween = new TimelineMax();
function startAnimation() {
        var element=$("#element");
        distanceX=500;
        distanceY=300;
        mytween.to(element, 2, {left:670});        
        mytween.to(element, 1, {rotation:90});
        mytween.to(element, 2, {top:distanceY});
        mytween.to(element, 1, {rotation:0});
        mytween.to(element, 2, {left:distanceX});
}

 

But if I do this (calling the x/y from a function), it doesn't work. The element animation will just stop:

 

var distanceX;
var distanceY;
var mytween = new TimelineMax();
function startAnimation() {
        var element=$("#element");
        mytween.to(element, 2, {left:670});       
        mytween.to(element, 1, {rotation:90});
        mytween.call(getXY);
        //note: this traces the correct x/y values: 
        mytween.call(function() {alert("distanceX: " + distanceX + " distanceY: " + distanceY);});
        mytween.to(element, 2, {top:distanceY});  //tween breaks here
        mytween.to(element, 1, {rotation:0});
        mytween.to(element, 2, {left:distanceX});
}

function getXY() {
        distanceX=500;
        distanceY=300;
}

 

Am I doing something wrong, or will this not work? The principle of using the dynamic variables distanceX and distanceY in a tween works in the first example, so why does it matter when the value of that variable is set or changes? The alert call shows that the value is accessible from within the Timeline object, so why can't the Tween access it too?

Link to comment
Share on other sites

Hi,

The main thing is that when your first function executes it adds all those tweens to the timeline, therefore when is time to change the top and left positions there are not deifned yet.

What I can advice (and there's probably a better way) is to remove all the tweens added by the first function and then add new ones with the changed values:

var distanceX = 0,
    distanceY = 0,
    tl1 = new TimelineMax(),
    element = $("div#element"),
    changeValues = false,
    btn1 = $("button#btn1");

function getxy()
{
    distanceX = 300;
    distanceY = 100;
    var delTweens = tl1.getTweensOf(element);
    tl1.remove(delTweens);
    tl1.to(element, 1, {rotation:75})
    tl1.to(element, 1, {top:distanceY});
    tl1.to(element, 1, {left:distanceX});
}

function startAnimation()
{
    tl1.to(element, 1, {left:200});
    tl1.to(element, 1, {top:200});
    tl1.to(element, 1, {rotation:45});
    tl1.call(getxy);
    tl1.to(element, 1, {rotation:0});
    tl1.to(element, 1, {top:distanceY + 'px'});
    tl1.to(element, 1, {left:distanceX});
}

startAnimation();

So like that when you call the getxy function you all the tweens inside the timeline are removed and you add new ones, of course if you don't want this to happen unless the user want the original values of distanceX and distanceY changed, something like this:

var distanceX = 0,
    distanceY = 0,
    tl1 = new TimelineMax(),
    element = $("div#element"),
    changeValues = false,
    btn1 = $("button#btn1");

function getxy()
{
    if(changeValues)
    {
        distanceX = 300;
        distanceY = 100;
        var delTweens = tl1.getTweensOf(element);
        tl1.remove(delTweens);
        tl1.to(element, 1, {rotation:75})
        tl1.to(element, 1, {top:distanceY});
        tl1.to(element, 1, {left:distanceX});
    }
}

function startAnimation()
{
    tl1.to(element, 1, {left:200});
    tl1.to(element, 1, {top:200});
    tl1.to(element, 1, {rotation:45});
    tl1.call(getxy);
    tl1.to(element, 1, {rotation:0});
    tl1.to(element, 1, {top:distanceY + 'px'});
    tl1.to(element, 1, {left:distanceX});
}

btn1.click(function()
{
    if(changeValues)
    {
        changeValues = false;
    }
    else
    {
        changeValues = true;
    }
})

startAnimation();

So like that you can use the whether the original values or the new ones depending on a specific event that changes the the boolean to true, otherwise the timeline goes as planed.

Check this http://jsfiddle.net/rhernando/tBZmA/1/

Maybe using the add method you can get something useful and less cumbersome but unfortunately that's all the time i have right now. Sorry for not coming up with something better :mrgreen:

Hope this helps,
Cheers,
Rodrigo.

Link to comment
Share on other sites

Thanks, it worked perfectly! It is only the last two tweens that were an issue, so transferring them to the second function is no big deal.

 

So, to understand -- even though the Timeline object executes the tweens in sequence, it has already loaded them all at once when first called? So that's why no value can be added or changed once the Timeline object begins to execute? I was thinking that it stepped through the lines of code and executed them as it came to them. That explains why it didn't work.

 

The only thing I don't understand about your code is why the old tweens need to be deleted in the second function.

Link to comment
Share on other sites

Hi SigmundSquirrel,

 

First, Welcome to the GreenSock forums. Glad to see that Rodrigo helped you out.

 

I can totally see why you were perplexed by the behavior you were experiencing. I also want to applaud you for so clearly explaining your situation and providing the alerts in your code.

 

As you saw, calling your getXY function certainly did update the values of distanceX and distanceY but future tweens did not have these updated values.

 

The reason for this (as you now suspect) is that as soon as a tween is created, the end values (that you provide) are immediately recorded internally. When the tween runs for the first time, that is when the starting values are recorded. 

 

So, yes, as soon as you create the tween, destinationX and destinationY were "locked in".

 

I think Rodrigo deleted the original tweens because he wanted to show that you could have some tweens in there "by default" and then optionally replace them with new ones only if the values changed.

 

I think for your scenario you can simply add the tweens you need with the most recent values when the time comes whether or not the values changed from what they were previously.

 

I changed the fiddle to show how it could work this way:

http://jsfiddle.net/Hnfbw/1/

 

if you click the change values button BEFORE the rotation happens, the div will continue down and right after the rotation. If you don't click the button the div will return to x:0 y:0.

  • Like 1
Link to comment
Share on other sites

Hi,

 

You're welcome.

 

The fact is that when you create a timeline and use the convenience to method, the tween is added to the end of the timeline so there's no possible overwrite. You could try doing it with a negative value to generate an overlapping, therefore an overwrite should happen:

var tl1 = new TimelineMax();

tl1.to(element, 1, {left:100});
tl1.to(element, 1, {left:50}, "-=1");//inserted 1 second before the timeline end

For the same reason, as you said, when you create the tweens in the timeline, they keep the original values provided, if you modify your second code to this:

var distanceX = 0;
var distanceY = 0;
var mytween = new TimelineMax();
function startAnimation() {
        var element=$("#element");
        mytween.to(element, 2, {left:670});       
        mytween.to(element, 1, {rotation:90});
        mytween.call(getXY);
        mytween.call(function() {alert("distanceX: " + distanceX + " distanceY: " + distanceY);});
        mytween.to(element, 2, {top:distanceY});
        mytween.to(element, 1, {rotation:0});
        mytween.to(element, 2, {left:distanceX});
}

function getXY() {
        distanceX=500;
        distanceY=300;
}

The element will tween to left:0 and top:0, because even with the values changing before the animation takes place, the tweens were created and putted in the timeline with the original values for distanceX and distanceY, those values never  get to the timeline. In fact you could add this lines to the getXY function, after setting the new values to see it for yourself:

var delTweens = tl1.getTweensOf(element);
console.log(delTweens);

If you go  to the console and see the vars element of the last two tweens you'll see that the values are 0 for both.

 

As for deleting the old tweens, if you don't the new tweens will be added to the end of the timeline, and since distanceX and distanceY are not defined the timeline will break and nothing will happen. Another possibility is to define the values of distanceX and distanceY as 0 in the variable creation, add labels to the timeline where the tweens are going to get the element to those values and then insert the new tweens right in those labels to force an overwrite.

var distanceX = 0;
var distanceY = 0;
var mytween = new TimelineMax();
function startAnimation() {
        var element=$("#element");
        mytween.to(element, 2, {left:670});       
        mytween.to(element, 1, {rotation:90});
        mytween.call(getXY);
        mytween.call(function() {alert("distanceX: " + distanceX + " distanceY: " + distanceY);});
        mytween.to(element, 2, {top:distanceY}, "label1");
        mytween.to(element, 1, {rotation:0});
        mytween.to(element, 2, {left:distanceX}, "label2");
}

function getXY() {
        distanceX=500;
        distanceY=300;
        mytween.to(element, 2, {top:distanceY},"label1");
        mytween.to(element, 2, {left:distanceX}, "label2");
}

So like that when the function executes it'll add the new tweens in the same place where the old ones are but with the new values, forcing the overwrite and tweening the element to the new values.

 

Cheers,

Rodrigo.

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...