Jump to content
Search Community

I'm stuck managing multiple Tweens and Timelines at once...

SlimMarten 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

Hey there,

 

first things first, I am new to this Forum as well as new to GSAP, so please bear with me. I try to give my best to describe what I am struggling with.

 

In order to animate an SVG file I started diving into GSAP. I created several Tweens for different elements within my SVG file.

Everything worked fine and ist animating as expected.

 

Since I have a lot of elements to animate within my SVG, I started adding TimelineLite to have more control about the whole thing.

 

At this point, my script file looked something like this:

 

 

First I declared all the elements I'd like to animate:

this.phone = document.querySelector('#gsap-phone-svg');
this.body = document.querySelectorAll('.gsap-phone-body');
this.body.shadow = this.phone.querySelectorAll('.gsap-phone-body-shadow');
this.body.mask = this.phone.querySelectorAll('.gsap-phone-body-mask');
this.layer = this.phone.querySelectorAll('.gsap-phone-layer');
this.screen = this.phone.querySelectorAll('.gsap-phone-screen');
this.screen.clipPath = this.phone.querySelectorAll('.gsap-phone-screen-clipPath');
.
.
.
// many more following here

Than I created an Object to save my Tweens in:

const tweens = {};

// creating tweens

tweens.body = TweenMax.to(this.body, this.animDur/2,{
y: this.maxExpand/6*-1,
ease: this.ease
});

.
.
.

// many more following here

At the end I added all my tweens to an temp array which I passed into a new TimelineLite() afterwards like so:

const tl = new TimelineLite();
tl.add(tweensArray, 0, "start", 0.05);

Seems logic so far, I guess... Now here is the crux. You may have noticed or not that I have like more than 20 elements or so to animate. Thats why adding a tween for every element on its own becomes very confusing. Also I want the whole main timeline to be repetitive. The problem here is, that I want different easing for all my tweens on the "in-animation" than on the "out-animation", as well as I want to have no stagger on the "out-animation".

 

All these little cruxes made me think about an alternative solution to manage the creation of my tweens and timelines.

 

The most handy solution that came in my mind was to store all the information about my anim elements and timelines within an object:

const animation = {
   settings : {
      duration: 1.5,
      expansion: 1,
      easeIn: Elastic.easeOut.config(1, 0.5),
      easeOut: Power2.easeInOut
   },
   timelines : {
      main : {
         delay : 0,
         paused : true,
         align : 'start',
         stagger : 0.05,
      },
      test : {
         delay: 0,
         paused : true,
         align : 'start',
         stagger : 0.5
      }
   },
   items : {
      phone : {
         id : '#gsap-phone-svg',
         start : { },
         end : { },
         timeline : 'test',
      },
      body : {
         class : '.gsap-phone-body',
         start : {
            y : 0,
         },
         end : {
            y : -21,
         },
         timeline : 'test',
      },
      layer : {
         class : '.gsap-phone-layer',
         start : {
            y : 0,
         },
         end : {
            y : -62.5,
         },
         timeline : 'main',
      },
      radar : {
         class : '.gsap-phone-radar',
         start : {
            y : 0,
         },
         end : {
            y : -25,
         },
         timeline : 'main',
      },
      radarBase : {
         class : '.gsap-phone-radar-base',
         start: {
            y : 0,
         },
         end : {
            y: -16,
         },
         timeline : 'test',
      },
      ringOne : {
         class : '.gsap-phone-radar-ring-1',
         start : {
            y : 0,
         },
         end : {
            y: -25,
         },
         timeline : 'test',
      },
      ringTwo : {
         class : '.gsap-phone-radar-ring-2',
         start : {
            y : 0,
         },
         end : {
            y: -41,
         },
         timeline : 'main',
      },
      ringThree : {
         class : '.gsap-phone-radar-ring-3',
         start : {
            y : 0,
         },
         end : {
            y: -62.5,
         },
         timeline : 'main',
      },
      cancel : {
         class : '.gsap-phone-cancel',
         start : {
            y : 0,
         },
         end : {
            y: -50,
         },
         timeline : 'main',
      },
      submit : {
         class : '.gsap-phone-submit',
         start : {
            y : 0,
         },
         end : {
            y: -100,
         },
         timeline : 'main',
      }
   }
};

Than I wrote this "createTweens" method to return the GSAP Tweens

/* create tweens */
function createTweens(anim){
   const el = anim.items;
   const settings = anim.settings;
   const duration = settings.duration;
   const easeIn = settings.easeIn;
   const easeOut = settings.easeOut;
   const tweensIn = [];
   const tweensOut = [];
   let tempTween = null;

   for (const key in el){
      const curEl = el[key];
      const selector = curEl.class || el[key].id;
      const startPoint = curEl.start || '';
      const endPoint = curEl.end || '';
      const timeline = curEl.timeline || '';
      const nodes = document.querySelectorAll(selector);

      nodes.forEach(object => {
         tweensIn.push(getTween(object, endPoint, duration, easeIn, `${timeline}-in`));
         tweensOut.push(getTween(object, startPoint, duration, easeOut, `${timeline}-out`));
      });
   }

   function getTween(tw, twValues, twDur, twEase, tl){
      const vars = twValues;
      vars.paused = false;
      vars.ease = twEase;
      tempTween = TweenMax.to(tw, twDur/2, vars);
      tempTween.data = {
         timelineName : tl
      };
      return tempTween;
   }

   return tweensIn.concat(tweensOut);
}

and another function to return the timelines:

/* create timelines */
function createTimelines(anim, tweens){
   const el = anim.timelines;
   const timelines = {};
   // timelines.mainIn = new TimelineLite();
   // timelines.mainOut = new TimelineLite();
   const tweensForTimelines = {};

   for(const key in el){
      const delay = el[key].delay;
      const paused = el[key].paused;
      const align = el[key].align;
      const stagger = el[key].stagger;
      const vars = {};
      vars.paused = paused;

      timelines[`${key}-in`] = new TimelineLite(vars);
      timelines[`${key}-in`].delay = delay;
      timelines[`${key}-in`].align = align;
      timelines[`${key}-in`].stagger = stagger;

      timelines[`${key}-out`] = new TimelineLite(vars);
      timelines[`${key}-out`].delay = delay;
      timelines[`${key}-out`].align = align;
      timelines[`${key}-out`].stagger = stagger;

      tweensForTimelines[`${key}-in`] = [];
      tweensForTimelines[`${key}-out`] = [];
   }

   if(Object.keys(tweensForTimelines).length !== 0){
      for(let i = 0; i < tweens.length; i++){
         const curTween = tweens[i];
         const tlTarget = curTween.data.timelineName;
         tweensForTimelines[tlTarget].push(curTween);
      }
   }


   for(const key in timelines){
      try{
         timelines[key].add(tweensForTimelines[key], timelines[key].delay, timelines[key].align, timelines[key].stagger);
         console.log(TweenMax.getTweensOf(timelines[key]));
         timelines[key].data = tweensForTimelines[key];
      } catch(e){

      }
   }

   return timelines;
}

If I execute the following code than, it would play my "main-in" timeline.

const tweens = createTweens(animation);
const timelines = createTimelines(animation, tweens);
timelines['main-in'].play();

So far, this is actually working. But if I try to add the "main-in" timeline to a new timeline, its not working anymore.

const anotherTimeline = new TimelineLite();
anotherTimeline.add(timelines['main-in']);
anotherTimeline.play();

In order to debug this, I tried 

TweenMax.getTweensOf(anotherTimeline);

but all this returns is an empty Array. Then I logged the same for my "main-in" timeline:

console.log(TweenMax.getTweensOf(timelines['main-in'])); 

also returning an empty Arraywhich is very confusing to me, since even though this timeline seems to be empty, it plays my !in-animation" on:

timelines['main-in'] 

I am really stuck here and would really appreciate some help from the more advanced users or simply anyone who has an idea for this. I hope you guys were able to follow me ... in case not, I will attach my script to this post, so if you are interested, you can have a look on it.

 

UPDATE: Click for Codepen DEMO

 

Thanks in advance!

AppDevController.js.zip

See the Pen vyEvbJ by anon (@anon) on CodePen

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