Jump to content
Search Community

Stagger Effect with ScrollTrigger Help

cobragtk test
Moderator Tag

Recommended Posts

Hi there,

I'm trying to create an effect where as the user scrolls down the page I animate a series of lines. I've created a minimal pen which is relatively close to what I'm looking for. I'm also attaching some images which show the general pattern of the animation from the start and as the user would scroll further on down the page. (Note: I'm only attaching a few images which show the overall progression but hopefully the wave pattern is discernible)

 

Some of the issues I'm having are:

  1. I'd like to start the lines as I have shown in the first image. I have achieved this but when my animation happens it doesn't tween the lines all the way back to the shortest width, if that makes sense. Essentially each line needs to go from a minimum value which is at the smallest 20% of 170px and then to a maximum of 170px.
  2. I also wasn't sure whether I could achieve what I'm after with stagger or by using the distribute function.

 

Any help or advice would be greatly appreciated!! Thanks in advance.

 

intial-state.png

subsequent-state.png

subsequent-state-2.png

subsequent-state-4.png

See the Pen 5a7ed8fbf7c565a544e7e4d6dcf6c2bb by sattley (@sattley) on CodePen

Link to comment
Share on other sites

Hi @cobragtk welcome to the forum and being a Club Greensock member 🎉

 

I'm blanking on the correct value, but I've split your yoyo tween in to two tweens, one that animates all the bars to a scale of 1 and the second that moves it to 0.2 and then with the position parameter have it start x amount of seconds after the first tween has played. A default tween is 0.5 seconds, but the first item is already at a scale of 1, so it should play when the second line is at one and each stagger takes 0.125, so my thinking was 0.5 + 0.125, but that is not 100% correct, but it is close, so I wanted to share my findings. 

 

See the Pen vYVmZgr?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

 

I've also tried it with GSDevTools and it looks like the second bar is full at 0.44 seconds, but that also doesn't  look 100% right to me, maybe the duration needs to be set based on how large the scale is of the current element, I'm just thinking out loud here. 

 

See the Pen MWPmoOe?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

 

If they all stared from 0.2 it would be much easier 🙃 I'm just posting this here, because maybe someone else has a great idea based on this one

 

See the Pen GRYmEvw?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen

  • Like 2
Link to comment
Share on other sites

 

Hello there @cobragtk - welcome to the GSAP forum.

 

3 hours ago, cobragtk said:

I also wasn't sure whether I could achieve what I'm after with stagger or by using the distribute function.

 

You likely could use the distribute utility, but I think you can also get the effect you are after with staggers just fine - in the end it'll probably boil down to what you are more comfortable with.

 

Especially when it comes to adding in ScrollTrigger, I guess you will have even more options for how to approach this. Depending on where exactly you want to go with this in the end, some might be easier to implement/understand and/or make more sense to use, than others.

 

5 hours ago, cobragtk said:

I'd like to start the lines as I have shown in the first image. I have achieved this but when my animation happens it doesn't tween the lines all the way back to the shortest width, if that makes sense

 

The general idea of what you tried in your pen with regard to GSAP alone, looks great already, but with the initial setup you have it does logically not work, because GSAP will tween the lines from where they started to the full scale and then back to where they started, which is exactly what is happening. Since some of them started with a bigger initial scale than others, that's where your problem originates.

 

One of the many great things about GSAP is, that it can practically tween on any object with properties that have numeric values.

[See: "Any numeric value, color, or complex string containing numbers"  in the Getting Started article]

 

Since GSAP tweens and timelines are objects too, and they have properties with numeric values, to a certain degree that also includes them.

[See: "Tween the progress() and timeScale() of an animation"  in this Learning Center article]

 

Now because calculating the progress of the timeline (as is a mentionin that second article linked) from and to when/where you'd want to have things animate could become a bit tricky, instead you could e.g. tween on the time of the timeline directly.

 

With this approach that I'm going to use in the example below, I would suggest not setting the initial scales for each of your starting elements manually, but instead let GSAP handle that for you which will get rid of that logic problem you ran into. Since I'm going to use a fromTo tween, the initial setting will probably not be neccessary, but I still wanted to mention it as it can be handy on its own.

 

Because you have your timeline set to paused anyway, you can now set the initial time of the timeline after its creation - you know how long it takes for 1 line to completely fill up, and that is exactly the time you want to set it to, because you want the first line to appear filled initially.

 

Careful; in my demos below I set the duration to 1 - in your example the duration is the default of 0.5 as you did not specify it.

 

const tl = gsap.timeline({
  paused: true
})

tl.to('.tick-mark', {...})

tl.time(1);

 

Now that was easy enough, but you probably also want to end the animation in a state where the last line will stay at full width, right?

 

For that, as mentioned above, you can create a new independent tween, that tweens the time of the timeline from that initial set time to the whole timeline's duration minus that amount it takes for one line to fill up - with an ease of 'none' as we're going to add the ScrollTrigger to this tween instead of the timeline itself now, and we want the tween to be scrubbed visually in sync with the scroll-position.

 

gsap.fromTo(tl, 
  { time: 1 },
  {
    time: tl.duration() - 1, //  tl.duration() - duration tick-mark
    ease: 'none',
    scrollTrigger: {
      trigger: "#wrapper",
      start: `top 50%`,
      end: `+=70%`,
      scrub: true,
      markers: true,
    },
  }
)

 

 

 

This should get you where you wanted with the part of the lines scaling up and down on scroll.

 

See the Pen JjmNMyw by akapowl (@akapowl) on CodePen

 

 

 

For the headlines to become animated/highlighted too, just add another tween to the timeline, making use of the position parameter to start it at the same time as the other tween and allow them to be synced.

 

This example uses the same values for the tween on the headlines, as are used for the tween on the lines.

 

See the Pen vYVmJjE by akapowl (@akapowl) on CodePen

 

 

 

The tricky bit here is to get the timing right.

 

I found that this final solution works well with a decent tween on the headline opacity...

 

See the Pen XWxRVOy by akapowl (@akapowl) on CodePen

 

 

... but especially with an ease of steps(1) for if you just want to toggle between different opacity-values of the headlines.

 

See the Pen LYgyzzN by akapowl (@akapowl) on CodePen

 

 

 

I'd suggest, after digesting all this, start playing around with the values and see what they do when changing them.

 

I added a few comments in the the last two examples posted, to try and pinpoint what's important there.

 

I hope this will help. Happy tweening!

 

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

Thank you @mvaneijgen for such quick response. I appreciate you getting the ball rolling! Also I was not aware of GSDevTools, so that was super helpful!

Thank you @akapowl - your response is so helpful in terms of learning and also I think it was crucial how you honed in on exactly what the problem was:

4 hours ago, akapowl said:

because GSAP will tween the lines from where they started to the full scale and then back to where they started, which is exactly what is happening. Since some of them started with a bigger initial scale than others, that's where your problem originates.

Also before going further your solutions are exactly what I needed, so thank you! Also thank you for going above and beyond with the label animation as that was also something I needed to add. Amazing work!

 

After digesting what you wrote and looking over your Codepen it makes perfect sense, however I still have questions :-)

  • So when you console.log the timeline's duration:
    console.log( `Timeline duration: ${tl.duration()}` ); // it logged 6.5
    Why would the duration not be equal to 19 or number of tick marks (19) x tween duration which is 1?
    Apologies if this is a silly question.
  • Regarding the each value in the stagger... I saw that you added a comment of each: 0.25, // keep in sync
    I was wondering what you meant by this. 0.25 seems to give it a nice effect but playing with this number just makes it staccato (larger time between tweens) versus smoother (smaller time between tweens). I guess the question is that, this doesn't have any bearing on the duration of the overall timeline, is that correct?

Lastly, I'm blown away by how elegant this solution is, so thank you! The link to the video Tween the progress() and timeScale() of an animation was very helpful.

 

  • Like 2
Link to comment
Share on other sites

 

I'm glad, it helps :) 

 

3 hours ago, cobragtk said:

Why would the duration not be equal to 19 or number of tick marks (19) x tween duration which is 1?
Apologies if this is a silly question.

 

Not silly at all - the concept is a bit rough to wrap your head around, if you don't think about it too much.

 

If I am not totally mistaken, the calculation leading to the 6.5 seconds would be as follows.

 

The only part we'll have a look at for now is the tween(s) for the tick-mark, because the tween(s) for the headlines don't have an effect on the timeline's total duration the way they are timed and positioned on the timeline.

 

So; the duration for a line to scale from the initial 0.2 to 1 is 1 second. Each onel starts 0.25 seconds after the one before has started, so we need to take into account 18 lines that start later and multiply that number by the time each one starts later than the one before it does. Then we also have 1 more second to take into account for them to go back to their initial state again.

 

2 × 1s = 2s

18 × 0.25s = 4.5s

------------------

2s + 4.5s = 6.5s

 

 

 

Try picturing it something like this (although it might not be 100% accurate as I think I slightly messed up the spacing) - for me that makes it easier:

 

------------ 1st tick-mark in
   ------------ 2nd tick-mark in
      ------------ 3rd tick-mark in
         ------------ 4th tick-mark in
            ------------ 5th tick-mark in
               ------------ 6th tick-mark in
                  ------------ 7th tick-mark in
                     ------------ 8th tick-mark in
                        ------------ 9th tick-mark in
                           ------------ 10th tick-mark in
                              ------------ 11th tick-mark in
                                 ------------ 12th tick-mark in
                                    ------------ 13th tick-mark in
                                       ------------ 14th tick-mark in
                                          ------------ 15th tick-mark in
                                             ------------ 16th tick-mark in
                                                ------------ 17th tick-mark in
                                                   ------------ 18th tick-mark in
                                                      ------------ 19th tick-mark in

            ------------ 1st tick-mark out
               ------------ 2nd tick-mark out
                  ------------ 3rd tick-mark out
                     ------------ 4th tick-mark out
                        ------------ 5th tick-mark out
                           ------------ 6th tick-mark out
                              ------------ 7th tick-mark out
                                 ------------ 8th tick-mark out
                                    ------------ 9th tick-mark out
                                       ------------ 10th tick-mark out
                                          ------------ 11th tick-mark out
                                             ------------ 12th tick-mark out
                                                ------------ 13th tick-mark out
                                                   ------------ 14th tick-mark out
                                                      ------------ 15th tick-mark out
                                                         ------------ 16th tick-mark out
                                                            ------------ 17th tick-mark out
                                                               ------------ 18th tick-mark out
                                                                  ------------ 19th tick-mark out
                                                                              |	
                                                                              | 
                                                                              v
|-----------|-----------|-----------|-----------|-----------|-----------|-----------|------
0           1           2           3           4           5           6           7

 

 

 

3 hours ago, cobragtk said:

I saw that you added a comment of each: 0.25, // keep in sync
I was wondering what you meant by this

 

With 'keep in sync' I meant to keep the value in all lines that have that value equal across those lines. You can change that value, but if you do, change it everywhere that value is used - to properly keep both parts of the timeline in sync so to say.

 

If any of those deviated from the others having that value, the highlighted headline wouldn't match the longest line anymore, so to say.

 

Also worth mentioning, that the value should probably not be bigger than the duration value of the tick-mark tween(s) as that would cause the position of the headline tween() on the timeline to become negative, and that might technically lead to problems - and of course it looks a bit odd.

 

Does that make sense to you?

 

 

 

This way you can change the 'spread' width of the curve (if that makes sense).

 

A rather low value in those places (and thus a rather high position parameter) would result in a visually wider spread of 'active' lines...

 

See the Pen rNqmqba by akapowl (@akapowl) on CodePen

 

 

 

...while a rather high value in those places (and thus a rather low position parameter) would result in a 'narrower curve'.

 

See the Pen abRWRRv by akapowl (@akapowl) on CodePen

 

 

 

And since I mentioned it in the comments, too, changing the ease of the tick-mark tween(s) would result in different 'shapes of the curve formed' by the lines. The examples above all use .in eases, so their curvature is bound inwards - changing that to .out or .inOut would result in an outward bound curvature (of different degrees between .in and .inOut). [ease: 'none' would probably just form the outline of a straight triangle 🤔]

 

See the Pen mdzmaVZ by akapowl (@akapowl) on CodePen

 

See the Pen ExdmGaQ by akapowl (@akapowl) on CodePen

 

 

 

By changing the base-type of the ease you can change the appearance of the distribution curve even further to achieve some really 'special' effects.

 

Not that it will be helpful or you might want it for this specific scenario - but for different setups it might be somewhat useful maybe.

 

See the Pen ExdmGKE by akapowl (@akapowl) 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.
×
×
  • Create New...