Jump to content
Search Community

How do I use the ScrollTrigger scrub of text animation in observer?

ashura test
Moderator Tag

Go to solution Solved by akapowl,

Recommended Posts

What do I mean by the title is something done like this...
 

but this is different because it doesn't have a scrollbar because it relies in scrollObserver...so I don't understand how can I make work the scrollTrigger alongside inside the scrollObserver. 

https://codesandbox.io/s/nervous-resonance-xpjvdf?file=/src/OshiNoko.jsx

You can check in my code inside...which what I am trying to do is that I'm trying to spread the scale:2 in the text that is closing in the middle so it looks cool...and then once it pass by the middle it will slowly scale:1 or lower the scale...The scale should be dependent if it's closing in the middle of the item...but it doesn't plus it calls many times the markers which kinda sucks and also I don't know why when I'm trying to onUp or onDown it seems the text a bit laggy when transition? what I am missing here? 

This is the codes. 
 

      const gotoSection = (index, isScrollingDown) => {
        let target = isScrollingDown
          ? swipePanels[currentIndex]
          : swipePanels[index];
        let currentYPercent = gsap.getProperty(".list-of-items", "yPercent");

        gsap.to(target, {
          scale: isScrollingDown ? 2 : 1,
          // duration:1.25,
          ease: "power2.inOut",
          scrollTrigger: {
            trigger: target,
            scrub: 1,
            start: "top center",
            end: "bottom center",
            markers: true
          }
        });

        gsap.to(".list-of-items", {
          yPercent: limitYPercent(currentYPercent, isScrollingDown ? +1 : -1),
          duration: 0,
          // overwrite:true,
          ease: "none"
        });

        currentIndex = index;
      };

      // ScrollTrigger.create({
      //     trigger:'.wrapper',
      //     scrub:true,
      //     start: "top center",
      //     end: "bottom center",
      //     markers:true,
      //     onEnter:() => {
      //         let target = swipePanels[currentIndex];
      //         gsap.to(target,{
      //             scale:2,
      //         })
      //     },
      //     onLeave:() => {
      //         let target = swipePanels[currentIndex];
      //         gsap.to(target,{
      //             scale:1,
      //         })
      //     }
      // })

      instanceObserver = ScrollTrigger.observe({
        target: ".wrapper",
        wheelSpeed: -1,
        onUp: () => {
          gotoSection(currentIndex + 1, true);
        },
        onDown: () => {
          gotoSection(currentIndex - 1, false);
        },
        tolerance: 10,
        preventDefault: true,
        allowClicks: true
      });

 

Link to comment
Share on other sites

  • Solution

 

Hello @ashura

 

ScrollTrigger and Observer actually serve different purposes and thus depend on differrent prerequisites. ScrollTrigger for instance relies on native scrolling - so if you're not going to use native scrolling as in your approach, it won't make much sense to use ScrollTrigger (same would go for a smooth-scrolling library like lenis e.g.).

 

I'm not sure I get the whole picture of what it is you're trying to achieve, but if you want something like the example from the thread you linked to work with Obersever only, you could immitate scrolling by translating an element. In the example below, logic-wise I set/tween the progress of a timeline depending on a progress variable I am setting in the onChange of the Observer. The timeline consists of the line-fill for each line and an extra tween on the .text element, moving it up to immitate scrolling, in its duration and position parameter adjusted, so the 'scrolling' will start once the first line is filled, and end before the last line starts filling up.

 

You see Observer is highly versatile, as it gives you just about anything you need, but figuring out the logic for what you want to achieve is in every dev's own hands.


I'm also convinced the logic I implemented here could still be improved, but this is just to give you some idea.

 

I do hope this will help in a way. Happy Observing.

 

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

 

  • Like 4
Link to comment
Share on other sites

Thanks for the help @akapowl because I find fascinating the observer. 
but how did you get this kind of code? I mean how those process of logic thinking derived from you? 

  y: (i,t) => -(t.scrollHeight - window.innerHeight) ,

or maybe this one too...

history.scrollRestoration = "manual"

I never know that y could return as function(or attributes as well) and also I don't know about history.scrollRestoration = manual does do. 

Link to comment
Share on other sites

 

Happy to help :) 
 

8 hours ago, ashura said:

but how did you get this kind of code? I mean how those process of logic thinking derived from you? 

 

To be honest, a lot of it will come with experience - e.g. this is a scenario that I have often enough managed in fake-horizontal scrolling, so for this fake-vertical scrolling I could just flip the axis of what I usually use in those horizontal scenarios.

But whenever I can not fall back to previous experience, it usually helps me a lot to visualize things.

 

Often times it is a good approach to get the animation done without thinking about the interaction-logic; we can always tweak things later.

For this scenario it would look something like this e.g.:

What we do know, is where we are starting out, and where we want things to go.
1.thumb.png.b6f666387659a6dc47b2f1ef1e02c929.png
So to get there, it looks like we need to move the element up on the y-axis.

And we want it to work no matter how tall the text-section is, so we need to look for a value we can get - so we could e.g. use the element's scrollHeight.

So in the first step, let's just move it upwards by that amount and see where it ends up. For that we'll take that value and make it negative, so it moves upwards as it should, e.g. like this.
 

y: (index, target) => -(target.scrollHeight)

// instead of using function-based values, you could e.g. also do this

y: -(document.querySelector('.text').scrollHeight)


Now we will see, that it doesn't end up where we want it to be, but instead with its bottom edge against the top edge of the viewport.

So in the next step, we'll need to think about how we can adjust our value, so it ends up with its bottom edge against the bottom edge of the viewport.

What's the difference between where it ended up now and where we want it to end up? We can see, it's exactly the window's height.

So now we can adjust our value for the y-tween by subtracting the window.innerHeight from our element.scrollHeight.
 

y: (index, target) => -(target.scrollHeight - window.innerHeight)

// instead of using function-based values, you could e.g. also do this

y: -(document.querySelector('.text').scrollHeight - window.innerHeight)

2.thumb.png.3cfd49eedfb9627aaf6d00476b647bee.png

 

That's the basic the thinking process behind that - and it always comes hand in hand with tinkering, and testing testing testing. 

Often, when e.g. I run into problems and I am absolutely convinced that the values I use should work for what I have in mind but they do not actually work, I console.log() them out at an appropriate point and measure things visually (with some tool like maybe a graphics editor or a browser extension). This way I try to find out what the difference is between what I use and what I need value-wise; and at some point I can deduce from that, what might be missing in my calculations - like maybe a margin or padding of an element I did not think about including.
 

8 hours ago, ashura said:

or maybe this one too...

history.scrollRestoration = "manual"


The above is a step by step process, where you may run into different issues along the way.

While working on that demo above, at some point I noticed, that when I re-load the page mid-animation, it can happen that the page reloads with the .text element not in its starting position, but moved up instead. That can happen from time to time, as (at least some) browsers appear to be moving things in the background although overflow is set to hidden on the body (and also even if I had set the body's height to 100vh specifically) and then start off on re-load with that 'wrong' scroll-position.

So basically what I did there is just tell the browser that I don't want it to restore the last scroll-position I was at when re-loading, to work around that.


https://developer.mozilla.org/en-US/docs/Web/API/History/scrollRestoration

As I mentioned in the beginning, a lot of things just come with experience - and often times you'll find that you didn't even know some really helpful things existed before you find any need for them - like function-based values e.g. - you can btw read more about those here.
 

Hopefully all this will help clear things up a bit for you.

 




Edit:
Oh, and although it is in a bit of a different scenario (fake-horizontal scrolling using ScrollTrigger), fellow @Carl tackles the concepts mentioned above (specifically the value-calculation part and function-based values) in a recent Video of his over on YouTube - so maybe this can help clear things out even further.

 

 

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