Share Posted March 12 Hey Guys, This is my first foray into using gsap and i'm really enjoying it so far. One of the questions that I can't seem to find through the forums is cancelling a queue of a timeline. I'll give an example with what I'm trying to do. I have a trigger to to hide my navigation and display a menu when a user scrolls down a page. I'm using the onEnter & onLeaveBack methods to trigger animation events. I noticed if I scroll up and down quickly enough (many times) - the animation queue will play through all the events - as expected. I was wondering whats the best way to prevent the entire queue of animations to play through multiple times and just play the last item in the animation event stack. I'm assuming its using the kill() method, but I haven't found the best place to put it. For context, i'm using react (hence the refs) inside a useEffect, here's just the actual timeline. navTimelineRef.current = gsap.timeline({ scrollTrigger: { trigger: document.body, start: `${window.innerHeight / 2} top`, end: 'max', markers: true, fastScrollEnd: true, invalidateOnRefresh: true, onEnter: () => { // Nav items stagger away navTimelineRef.current.to(navRef?.current?.children, { autoAlpha: 0, stagger: 0.2 }); // hamburger nav comes into view navTimelineRef.current.to(hamburgerRef.current, { autoAlpha: 1 }); // logo icon scales up navTimelineRef.current.to(hamburgerLogoRef.current, { scale: 2 }); }, onLeaveBack: () => { // logo icon scales back down navTimelineRef.current.to(hamburgerLogoRef.current, { scale: 1 }); // hide the hamburger menu navTimelineRef.current.to(hamburgerRef.current, { autoAlpha: 0 }); // reverse stagger back in the menu items navTimelineRef.current.to(navRef.current.children, { autoAlpha: 1, stagger: 0.2, reversed: true }); } } }); Appreciate any feedback, thanks! Link to comment Share on other sites More sharing options...
Author Share Posted March 12 (edited) For anyone looking for an answer to this, i've added the `clear()` method at the start of both the onEnter & onLeaveBack methods. Did not give expected results. Edited March 12 by BrandonI Link to comment Share on other sites More sharing options...
Solution Solution Share Posted March 12 Welcome to GSAP, @BrandonI! It looks like you're reusing the same timeline over and over, continuing to add animations to it so it keeps getting longer and longer. That's actually pretty wasteful because not only do you end up with a super long timeline eventually, but those animations aren't released for garbage collection because you're telling GSAP that you want to keep them in that timeline and it has no idea if you might want to call reverse() at some point and play EVERYTHING backwards. It also looks like you're using React. It's always best to provide a minimal demo so that we can see the issue in context (like a Stackblitz or CodeSandbox), but I'd highly recommend reading this article: gsap.context() is your new best friend in React because it makes cleanup so simple, plus it gives you selector scoping (saves you from having to create a ref for every element you want to animate). You could just create a fresh timeline in your onEnter/onLeave. Kill() the old one to avoid conflicts (like if the user scrolled up/down/up/down really fast over the start point, you don't want to end up with 4 timelines all animating the same properties of the same elements). So your code might look something like this: useLayoutEffect(() => { let ctx = gsap.context(() => { let navTL; // keep track of the most recent animation so we can easily kill() it ScrollTrigger.create({ trigger: document.body, start: `${window.innerHeight / 2} top`, end: 'max', markers: true, onEnter: () => { navTL && navTL.kill(); // if there's an animation, kill it so we don't create conflicts navTL = gsap.timeline(); // Nav items stagger away navTL.to(navRef?.current?.children, { autoAlpha: 0, stagger: 0.2 }); // hamburger nav comes into view navTL.to(hamburgerRef.current, { autoAlpha: 1 }); // logo icon scales up navTL.to(hamburgerLogoRef.current, { scale: 2 }); }, onLeaveBack: () => { navTL && navTL.kill(); // if there's an animation, kill it so we don't create conflicts // logo icon scales back down navTL.to(hamburgerLogoRef.current, { scale: 1 }); // hide the hamburger menu navTL.to(hamburgerRef.current, { autoAlpha: 0 }); // reverse stagger back in the menu items navTL.to(navRef.current.children, { autoAlpha: 1, stagger: 0.2 }); } }); }); return () => ctx.revert(); // <-- CLEANUP! }); I hope that helps! If you need more assistance, please make sure you provide a minimal demo. Here is a React starter template you can fork. Link to comment Share on other sites More sharing options...
Author Share Posted March 12 Wow fantastic reply, thank you! Works like a charm. Link to comment Share on other sites More sharing options...
Author Share Posted March 12 I just want to update, instead of the kill() method, I swapped it out with clear() to allow the previous animation to finish instead of stopping it in its tracks. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now