Jump to content
Search Community

Javascript scope among multiple timelines

jasper test
Moderator Tag

Go to solution Solved by jamiejefferson,

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

Hi all,

 

I'm doing a front page with 5 animations where one fades away in place of another, and so on, and then it loops.

 

Rather than write one enormous hideous looping timeline I thought I'd make each of the animations a separate timeline and use callbacks to trigger subsequent timelines and JQuery to fade the relevant DIVs in and out.

 

A condensed version of my code is below.  The callbacks work great until I get to the last animation (vr_pan5).  It fades in the DIVs required to replay the first animation, but then doesn't restart the first animation (vr_pan1).

 

I tried shuffling the order of the timeline declarations in the code.  The issue seems to be an inability to play a timeline at the top of the code, after having played a timeline further down. I also tried moving code in and out of the window.load function, but that didn't make a difference either.

 

Sorry for asking what is essentially a Javascript question and not a Greensock question!  Also, sorry for not creating a codepen; I figured a glance at my semi-pseudocode would be enough for someone enlightened.

 

Code follows:

var vr_pan1, vr_pan2, vr_pan3, vr_pan4, vr_pan5;

vr_pan5 = new TimelineMax({paused:true,repeat:0, onComplete:nextAnim, onCompleteParams:["#fg5", "#bg5", "#fg1", "#bg1", vr_pan1]});

vr_pan5
.add("start")
//tween some stuff
;

vr_pan4 = new TimelineMax({paused:true,repeat:0, onComplete:nextAnim, onCompleteParams:["#fg4", "#bg4", "#fg5", "#bg5", vr_pan5]});

vr_pan4
.add("start")
//tween some stuff
;

vr_pan3 = new TimelineMax({paused:true,repeat:0, onComplete:nextAnim, onCompleteParams:["#fg3", "#bg3", "#fg4", "#bg4", vr_pan4]});

vr_pan3
.add("start")
//tween some stuff
;

vr_pan2 = new TimelineMax({paused:true, repeat:0, onComplete:nextAnim, onCompleteParams:["#fg2", "#bg2", "#fg3", "#bg3", vr_pan3]});

vr_pan2
.add("start")
//tween some stuff
;

vr_pan1 = new TimelineMax({paused:true, repeat:0, onComplete:nextAnim, onCompleteParams:["#fg1", "#bg1", "#fg2", "#bg2", vr_pan2]});

vr_pan1
.add("start")
//tween some stuff
;

function nextAnim(fadeout_div1, fadeout_div2, fadein_div1, fadein_div2, new_anim) {
	$(fadeout_div1).fadeOut();
	$(fadeout_div2).fadeOut();
	$(fadein_div1).fadeIn();
	$(fadein_div2).fadeIn();
	var o = new_anim;
	o.restart();
}

$( window ).load(function() {
	vr_pan1.play();
});

Thanks, eh.

 

Link to comment
Share on other sites

  • Solution

Yes the error is in this line:

vr_pan5 = new TimelineMax({... onCompleteParams:["#fg5", "#bg5", "#fg1", "#bg1", vr_pan1]});
At this time vr_pan1 hasn't been defined yet, so your onCompleteParams look more like

["#fg5", "#bg5", "#fg1", "#bg1", undefined].

 

Are you aware that timelines can be nested to handle this sort of sequencing? I think something like this should remove the reliance on onComplete chaining (and replaces jQuery with GSAP opacity fades)

vr_pan1 = new TimelineMax(); // no need to pause a nested timeline. repeat 0 isn't required as it's the default
// add tweens...
vr_pan2 = new TimelineMax();
vr_pan3 = new TimelineMax();
vr_pan4 = new TimelineMax();
vr_pan5 = new TimelineMax();

var master = new TimelineMax({paused:true, repeat:-1}); // infinite repeats

master.add(vr_pan1, "vr_pan1")
      .to("#fg5, #bg5", .4, { autoAlpha: 0 }, "vr_pan1") // use labels to attach fades to the start of vr_pan1
      .to("#fg1, #bg1", .4, { autoAlpha: 1 }, "vr_pan1")

      .add(vr_pan2, "vr_pan2")
      .to("#fg1, #bg1", .4, { autoAlpha: 0 }, "vr_pan2")
      .to("#fg2, #bg2", .4, { autoAlpha: 1 }, "vr_pan2")

      // etc
      .add(vr_pan3, "vr_pan3")
      .add(vr_pan4, "vr_pan4")
      .add(vr_pan5, "vr_pan5");


$( window ).load(function() {
  master.play();
});
  • Like 2
Link to comment
Share on other sites

Thanks jamie for the all-greensock answer to my problems!! It's working now, with a few slight tweaks.

 

Yes, generally I was aware that timelines can be nested but (and sorry to sound critical here) the documentation is still lacking in this area.  I know I can use .add() to add a timeline to another, but the dynamics of that are not spelled out very well in the documentation (at least anywhere I could find). Your "no need to pause a nested timeline" was very instructive; thank you!

 

I'm still mystified as to why my javascript is screwed though.  My (albeit incomplete) understanding of javascript is that everything in the block of code that is NOT in the window.load() function is loaded before the window.load() event fires.  Additionally, because the function nextAnim() that I had defined is at the bottom of that block, it should be aware of all of the vr_panx declarations above it.  So, why do the vr_panx animations need to be aware of each other?  They were declared globally and are being called in sequence by nextAnim().... a concern for another day I suppose.

 

to bed with a fuzzy head but an animation that worksss......

 

thanks, eh

Link to comment
Share on other sites

vr_pan1 is not defined when you attempt to pass it to the vr_pan5 onCompleteParams so it's not available for nextAnim to read. It doesn't matter whether vr_pan1 is global or not; when vr_pan1 is undefined and you call

vr_pan5 = new TimelineMax({... onCompleteParams:["#fg5", "#bg5", "#fg1", "#bg1", vr_pan1]});
you have setup the following to be called onComplete

nextAnim("#fg5", "#bg5", "#fg1", "#bg1", undefined);
Changing vr_pan1 to be a TimelineMax after the fact doesn't change the undefined value that was already passed to the onCompleteParams.

 

Javascript only uses pass by reference for objects (vr_pan1 hasn't been defined as an object at that point), and even then the reference itself is just passed by value. e.g.

var vr_pan1 = new TimelineMax(); // vr_pan1 is defined

vr_pan5 = new TimelineMax({onComplete:nextAnim, onCompleteParams:["#fg5", "#bg5", "#fg1", "#bg1", vr_pan1]});
// onCompleteParams has vr_pan1 as an empty timeline

vr_pan1.to(foo, 1, {...});
// adds a tween to vr_pan1 - will show up onComplete since a reference was passed

vr_pan1 = new TimelineMax(...);
// severs the reference to vr_pan1 inside vr_pan5's onComplete. vr_pan5 will still play the timeline with the
// foo tween, but we can no longer modify that timeline (without getting a reference to it), and vr_pan1 as a
// global variable is referring to this new TimelineMax

Technically another solution to your original problem would have been to remove the onComplete from the vr_pan5 definition and add it once vr_pan1 was defined

vr_pan5 = new TimelineMax({paused:true,repeat:0}); // no onComplete yet since vr_pan1 is required
...
vr_pan1 = new TimelineMax({...});
...
vr_pan5.eventCallback("onComplete", nextAnim, ["#fg5", "#bg5", "#fg1", "#bg1", vr_pan1]);
  • 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...