Jump to content
Search Community

Can we use matchMedia() for timelines outside the scrollTrigger?

jaden test
Moderator Tag

Recommended Posts

I visited scrollTrigger.matchMedia() docs and it's very useful feature

I have timeline animation outside of scrollTrigger. 
I animate 3 elements on mobile and 6 on desktop, and on mobile view there is gap for elements that were set  to display: none; with CSS media query

whats way around this? 
PS i'm using interesction observer to run the timeline

Link to comment
Share on other sites

Hey jaden.

 

Quote

Can we use matchMedia() for timelines outside the scrollTrigger?

Try it and see :) 

See the Pen OJNWaGz by GreenSock (@GreenSock) on CodePen

 

If you resize the window, you'll see that it will create the animations once the media breakpoint is entered into. However, old effects are never destroyed because there's not a way for GSAP to track what has been created inside of the function.

 

To do this sort of thing, just use the regular JS matchMedia:

See the Pen oNxBJXB?editors=0010 by GreenSock (@GreenSock) on CodePen

  • Like 3
Link to comment
Share on other sites

On 8/24/2020 at 5:13 PM, Visual-Q said:

This is a really good pen from @OSUblake

 

Uses matchmedia and has a solution for updating animation as well.

 

Observe how the animation progress is recorded on resize then the animation is cleared out and rebuilt back to the progress that was recorded.

 

 

 

 

 

 

That looks neat. Thanks for demo.

Link to comment
Share on other sites

On 8/24/2020 at 4:34 PM, ZachSaucier said:

To do this sort of thing, just use the regular JS matchMedia:

 

 

Hi Zack, I been using this and works really well. I have a follow up question tho if you dont mind.
I want one tween only to run at mobile and not at all at bigger screens,  so I what I did was :
if (matches){ gsap.to....) else { return; }
Should I use return; or oldAnim.kill(); ?
I tried both, and both work just fine, but was wondering what's considered correct way. Actually it works with empty {} aswell.

Link to comment
Share on other sites

2 hours ago, ZachSaucier said:

In general you should kill off an animation if you're done with it so that it can be garbage collected.

Just to clarify a little, you do NOT need to worry about killing off every animation you create in order for it to be garbage collected - GSAP automatically releases each animation for GC when it finishes. I think Zach just meant that if your goal is to get rid of animations that haven't finished yet, yes, it'd be good to kill() them. 👍

  • Thanks 1
Link to comment
Share on other sites

One more thing...

 

In 3.5.0, we added the ability to return a function from any of the media queries and that function will get called when the media query no longer matches, so that's the perfect place to put your cleanup code. That also allows you to use ScrollTrigger.matchMedia() for things that aren't ScrollTrigger-related. For example, you could create a bunch of animations in there, assign them to variables, and then in your cleanup function kill() them. 

 

Example: 

ScrollTrigger.matchMedia({
	
  // desktop
  "(min-width: 800px)": function() {

    // a timeline that isn't ScrollTrigger-related...
    let tl = gsap.timeline();
    tl.to(".box", {rotation: 360})
      .to(".box", {y: 100});

    // THIS IS THE KEY! Return a function which will get called when the media query no longer matches so we can kill() the animation (or whatever)
    return function() {
      tl.kill(); 
      // other cleanup code can go here...
    };
  }

});

https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.matchMedia()#teardown

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

  • 1 year later...

This return function is very helpful. I got it working perfectly:

See the Pen powKYEM by wildeweg (@wildeweg) on CodePen

 

But when a timeline is defined within a function, I can't get it to work (sorry, this has probably to do with my limited knowledge of javascript.). Probably somebody can give me some pointers, though?

 

I am doing this:
 

gsap.utils.toArray(".book").forEach((book) => {

      var bookImageSRC = book.querySelector("img").src;
      var bookImageNaturalHeight = book.querySelector("img").naturalHeight;
      var bookImageNaturalWidth = book.querySelector("img").naturalWidth;
      var bookImageProportion = bookImageNaturalWidth / bookImageNaturalHeight;
      var bookImageTargetWidth = 200;
      var bookImageTargetHeight = bookImageTargetWidth / bookImageProportion;


      function bookHover(e) {
        if (e.type === "mouseenter") {
          var tl_bookIn = gsap.timeline();
          tl_bookIn.set(bookImageWrapper, {backgroundImage: "url('" + bookImageSRC + "'", backgroundSize: bookImageTargetWidth + "px " + bookImageTargetHeight + "px", width: bookImageTargetWidth*0.9, height: bookImageTargetHeight*0.9});
          tl_bookIn.set(book, {backgroundColor: "#FF89E4"});
          tl_bookIn.to(bookImageWrapper, {autoAlpha: 1, rotate: 10, backgroundSize: bookImageTargetWidth + "px " + bookImageTargetHeight + "px", width: bookImageTargetWidth, height: bookImageTargetHeight, duration: 1.6});
        } else if (e.type === "mouseleave") {
          var tl_bookOut = gsap.timeline();
          tl_bookOut.set(book, {backgroundColor: "#F2FF74"});
          tl_bookOut.to(bookImageWrapper, {autoAlpha: 0, rotate: 0, backgroundSize: bookImageTargetWidth * 1.2 + "px " + bookImageTargetHeight * 1.2 + "px", width: bookImageTargetWidth*0.6, height: bookImageTargetHeight*0.6, duration: 1});
        }
      }

      book.addEventListener("mouseenter", bookHover);
      book.addEventListener("mouseleave", bookHover);
      book.addEventListener("mousemove", moveBookImage);
    });


Then I try to kill the timeline like this:

 

return function() {   
      // other cleanup code can go here. 
      tl_bookIn.kill();
      tl_bookOut.kill();
    };


But it says 'Can't find variable: tl_bookIn'. This probably has to do with scope?

 

Codepen example here:

See the Pen rNwogyM?editors=1010 by wildeweg (@wildeweg) on CodePen

Link to comment
Share on other sites

Yep, that's just a JavaScript scope thing. Whenever you create a variable with "const" or "let" or "var", that's called a LOCAL variable, meaning it is only accessible from INSIDE that function. So if you need to reference it OUTSIDE that function, you've got a few options: 

// declare the variable OUTSIDE the function
let tl_bookIn;
function whatever() {
  tl_bookIn = gsap.timeline(); // assign it inside the function
  ...
}

-OR-

let tl_bookIn = makeBookIn(); // return the timeline from the function and assign it to your variable here.
function makeBookIn() {
  let tl = gsap.timeline();
  ...
  return tl; // <-- IMPORTANT! Return the timeline
}

Does that help? 

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