Jump to content
GreenSock

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

Help updating position on resize with multiple scrollTriggers? + f() question

Recommended Posts

Thanks GS team for providing the Keeping ScrollTrigger same progress on resize codepen.

How can I adapt this part of the code for multiple ScrollTriggers?

ScrollTrigger.addEventListener("refreshInit", () => progress = ST.progress);
ScrollTrigger.addEventListener("refresh", () => ST.scroll(progress * ScrollTrigger.maxScroll(window)));

I have 12 ScrollTriggers set up, and they are all set up anonymously, like this:

gsap.timeline({
          scrollTrigger: {...

How can I reference and update the progress for each one?

 

I'm hesitant to rewrite them with separate, named timelines, because I noticed that when I crated the scrollTrigger separately for one of my animations using the create method:

ScrollTrigger.create({...

...and passed in my timeline, the start/end triggers were in the wrong spot. (Even though it was written in DOM order, and ST.sort() was applied, the triggers were still appearing far too early). 

 

 

I'll also be using matchMedia.

 

And, is there any advantage to using a function like:

end: () => innerHeight * 4,

instead of:

end: innerHeight * 4,

Many thanks!

See the Pen xxVWJGe?editors=1010 by GreenSock (@GreenSock) on CodePen

Link to comment
Share on other sites

26 minutes ago, sashaikevich said:

How can I adapt this part of the code for multiple ScrollTriggers?


ScrollTrigger.addEventListener("refreshInit", () => progress = ST.progress);
ScrollTrigger.addEventListener("refresh", () => ST.scroll(progress * ScrollTrigger.maxScroll(window)));

First save all of your ScrollTriggers to an array using the .getAll() method. Then inside of the refreshInit listener, loop through your ScrollTriggers and save their progress values to an array. Then inside of the refresh listener update their progress to the one saved.

 

25 minutes ago, sashaikevich said:

is there any advantage to using a function like:


end: () => innerHeight * 4,

instead of:


end: innerHeight * 4,

Absolutely! The first one will be updated on refresh. The second one won't.

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

Sweet! I knew GS must have a clever way! Praise be GS creators, praise be.

 

Quote

The first one will be updated on refresh. The second one won't.

Cool. That would explain why some of my animations work on resize automatically, while others do not. Time to refactor :)

Link to comment
Share on other sites

Just now, sashaikevich said:

That would explain why some of my animations work on resize automatically, while others do not. Time to refactor :)

Keep in mind also that this will not update tween values by default. If you need to update those on refresh then you should also make them functions (prepend () =>and set invalidateOnRefresh: true for the tween.

  • Thanks 1
Link to comment
Share on other sites

Thank you. That explains why there's  tl.invalidate(); in the demos I came across. 

Link to comment
Share on other sites

@ZachSaucier, thank you very much for all your help, every time I get something working I get so excited (and come up with 10 more animation ideas)! I have just a small thing left (hopefully), and this page that's been 1 year in the making will be perfect!
 

I still cannot get the elements to recalculate their animations in relation to the new innerWidth/Height after a window resize. 

 

When I added invalidateOnRefresh: true property to all my ST objects that seemed to do the trick, BUT as a side effect many of my elements lost their correct positions.

 

I did a quick check, and I think its everything with the .from() method that's been affected, because my few remaining fromTo animations are still correct (but it might be others as well (.to() maybe, or .set()?).

 

If I understood your animation guide correctly, the fewer .fromTo() methods - the better, but is that still the case here?

 

Should I go back to using .fromTo() animations and add invalidateOnRefresh OR, should I keep my .from() and my .to() animations and do something else instead of invalidateOnRefresh? 

 

I've included a simplified version of my code below if it helps. (Maybe it's some other rookie mistake that's interfering)

 

function customCode() {

  gsap.registerPlugin(ScrollTrigger);

  ScrollTrigger.matchMedia({

    // all 
    "all": function () {
      gsap.set(...);
    },

    // desktop
    "(min-width: 1024px)": function () {

      let instWrapperHeight = Math.floor(document.querySelector(".instructions-items-wrapper").getBoundingClientRect().height);

      function distFromBottom(el) {
        return instWrapperHeight - (Math.floor(el.offsetTop)) + el.offsetHeight * 1.5;
      };

      gsap.timeline({
          scrollTrigger: {
            ...
            end: () => innerHeight * 4,
          }
        })
        .to(".welcome-splash", {
          y: () => -innerHeight * 0.5,
        })
        .fromTo(".text-bold", {
          y: (i, el) => distFromBottom(el),
        }, {
          y: 0,
        })

      // SCENE show options

      gsap.timeline({
          scrollTrigger: {
            end: () => "+=" + innerHeight * 6,
          }
        })
        .fromTo(".option-3", {
          x: () => innerWidth * .1,
          y: "-100%",
        }, {
          y: () => innerHeight
        })
    }
  });

  ScrollTrigger.sort();

  let allST = ScrollTrigger.getAll();
  let allSTProgress;

  ScrollTrigger.addEventListener("refreshInit", function () {
    allSTProgress = allST.map((st) => st.progress)
  })
  ScrollTrigger.addEventListener("refresh", function () {
    allST.forEach((st, i) => st.progress = allSTProgress[i])
  })

}


window.addEventListener("load", (e) => customCode());

 

What do you recommend I do? 

Link to comment
Share on other sites

It's hard to say what the exact issue is without a minimal demo. A few comments:

  • Avoid putting functions within functions, especially when the outer functions could be called multiple times. Put distFromBottom outside of the matchMedia stuff if you need it as a standalone function.
  • Code inside of a matchMedia function but not within a tween or ScrollTrigger that is invalidated on resize will not run on resize unless the breakpoint is reached for the first time. So your instWrapperHeight variable will not update on every resize. If you need it to, run a function that happens on refresh or something along those lines.
  • I don't see any invalidateOnResizes in your code. Make sure those are where they should be.
  • Use yPercent instead of y: "-100%". More about that in the common GSAP mistakes article.
  • You may or may not need to reset the value of certain properties of certain elements that you're animating on resize since you're using relative tweens. It's possible that using a .fromTo instead could fix that issue if you'd prefer to do it that way. But again it's hard to give firm advice here since we can't see a demo ourselves.
  • I'm not sure if you need the ScrollTrigger.sort(); line.
Link to comment
Share on other sites

  • 6 months later...
On 9/24/2020 at 2:56 PM, ZachSaucier said:

invalidateOnResizes

I think you mean 'invalidateOnRefresh' 🙃

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