Jump to content
Search Community

Recommended Posts

Posted

Hiii, 
I am trying create a reel like web application. In which I am trying to create a reel component in which I will use Observer for listening user's swipe up and swipe down action and scrollTo to animate slide to next page.
 
But, the issue is when user swipes, onUp/onDown is being called even after user stops swiping.

Here paginated api response will come also so we have to update slides as user scrolls the reels.

Here is a code for that component:

 

import gsap from 'gsap'
import { ScrollToPlugin, Observer, ScrollTrigger } from 'gsap/all'
import { useGSAP } from '@gsap/react'
import { type VideoSizeBoxType } from '@/lib/stores/genuin-options'
import { useEffect, useRef } from 'react'

gsap.registerPlugin(ScrollToPlugin, Observer, ScrollTrigger)

const customColors = [
  '#E74C3C',
  '#1ABC9C',
  '#8E44AD',
  '#3498DB',
  '#F1C40F',
  '#2ECC71',
  '#D35400',
  '#9B59B6',
  '#27AE60',
  '#34495E',
]

export function CustomSwiper({ sizeBox }: { sizeBox: VideoSizeBoxType }) {
  const scopeRef = useRef<HTMLDivElement | null>(null)
  useGSAP(
    () => {
      let isAnimating = false
      let currentIndex = 0

      const obs = Observer.create({
        debounce: true,
        type: 'wheel,touch,pointer,scroll',
        wheelSpeed: 0,
        target: '#swiper-test',
        lockAxis: true,
        tolerance: 0,
        preventDefault: true,
        onDown: (self) => {
          console.log('self::', isAnimating)
          if (!isAnimating) {
            swipeNext(currentIndex + 1)
          }
        },
        onUp: () => {
          if (!isAnimating) {
            swipePrev(currentIndex - 1)
          }
        },
      })

      function swipeNext(newIndex: number) {
        isAnimating = true
        gsap.to('#swiper-test', {
          duration: 0.5,
          ease: 'power3.inOut',
          scrollTo: { y: `+=${document.getElementById('swiper-test')!.clientHeight}px` },
          onComplete: () => {
              isAnimating = false
            currentIndex = newIndex
          },
        })
      }

      function swipePrev(newIndex: number) {
        isAnimating = true
        gsap.to('#swiper-test', {
          duration: 1,
          scrollTo: { y: `-=${document.getElementById('swiper-test')!.clientHeight}px` },
          onComplete: () => {
               isAnimating = false
            currentIndex = newIndex
          },
        })
      }

    },
    { scope: scopeRef }
  )

  return (
    <div ref={scopeRef}>
      <div id="swiper-test" className="overflow-hidden" style={{ ...sizeBox }}>
        {customColors.map((item, index) => {
          return (
            <div key={index} className="flex h-full w-full" style={{ backgroundColor: item }}>
              {index}
            </div>
          )
        })}
      </div>
    </div>
  )
}

 

See the Pen PoMbMOj by Himanshu-Mendapara (@Himanshu-Mendapara) on CodePen.

Posted

Hi @Himanshu63 welcome to the forum!

 

What exactly is the issue here? It is not clear from your description and your pen seems to work fine. 

 

13 minutes ago, Himanshu63 said:

But, the issue is when user swipes, onUp/onDown is being called even after user stops swiping.

 

This is correct, the Observer plugin is a tool to observe actions, and it doesn't know what you're going to do with it, so it is just happily logs what is happening and it is up to you to to than catch that and do the logic you want when you want. But I'm a bit confused, because you're already doing this. You already check isAnimating and then do some logic, so what are you missing here?

 

I think it is good to remember that the Observer plugin is not specially build to create this specific effect, it is build to make anything you can ever think of, so the tools are more general and it is up to you to tell them what you want from them. 

 

Hope it helps and happy tweening! 

Posted

Thank you, for the response.

I got your point. But I just want to know if we can limit firing of onDown/onUp events through Observer which can help me reduce repetition of firing multiple swipeNext

Fo example:
I am triggering animation with duration 500ms but Observer's scroll is being persisted for more than 500ms. How can I handle that?

Is there any parameters I can leverage?

Posted

I assume you're using a phone or trackpad which fires scroll events for the whole duration while the momentum scroll is happening? 

There isn't a setting in Observer but this thread might help

 

Posted

Can we control momentum here?

Posted

Hi,

 

I'm afraid that is not possible as far as I know. Momentum scrolling on touch devices is a native feature, so you would have to find a way to manage that and my first guess is that is either not possible or quite complex.

 

What you can do is restart a timer when the scroll event is fired and when that timer is completed that means the scroll event is no longer firing, something like this:

const myTimer = gsap.delayedCall(0.5, () => {
  // Execute this code once the timer is done
}).pause();

const myObserver = () => {
  onUp: () => myTimer.restart(true),
  onDown: () => myTimer.restart(true),
};

The idea of this approach is to execute the code on the callback when you're sure the event's have stop getting triggered. The duration of the DelayedCall instance is something that you can change to fit your needs:

https://gsap.com/docs/v3/GSAP/gsap.delayedCall()

 

Hopefully this helps

Happy Tweening!

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