Jump to content
Search Community

LuLUE7775

Members
  • Posts

    3
  • Joined

  • Last visited

Posts posted by LuLUE7775

  1. Hi,

    I am using Next.js with GSAP.

    I discovered that the horizontal length does not expand according to the width of the images when users redirect from other pages.

    Somehow, it works if the home page is refreshed.

    In the horizontal helper function, I noticed that items[length - 1].offsetLeft is not the total width that should be added up.

    Any help would be greatly appreciated!

    https://codesandbox.io/p/devbox/gsap-horizontal-infinite-carousel-lzn99z?file=%2Fapp%2Fcomponents%2FSlider.jsx%3A41%2C16

     

  2. Hi, 

    I am building a slider based on this example 

    It works when it's alone on a page, https://yaojuilan.art/gsap 

    While it isn't working when there is something else https://yaojuilan.art/system_of_conductors/field-walk#kinmen  (the slider works sometime. it is unstable. )

    I tried logging out the observer onChange, the event does trigger, but the items just would not do the horizontal transition. 

     

    I am wondering if observer has some sort of limitation, or maybe observer listener is interfering with something?

    Sorry i did not create a codepen, because this component does works standalone. Here is the slider component 

     

     
    export default async function Page() {
      const data= await getPageContent()
     
      return (
        <div id='intro' className='relative h-auto w-full overflow-x-hidden'>
          <div className='h-[50vh] w-full'> some content </div>
          <Slider items={data?.carousel_img?.images}  />
          <div className='h-[200vh] w-full bg-red-100'> some content </div>
        </div>
      )
    }


    export default function Slider({ items, section }) {
      useGSAP(() => {
        let loop = horizontalLoop(`.carousel-${section} li`, { repeat: -1 })
        let slow = gsap.to(loop, { timeScale: 0, duration: 0.5 })
        loop?.timeScale(0)
     
        Observer.create({
          target: `.carousel-${section}`,
          type: 'pointer,touch,wheel',
          wheelSpeed: -1,
          preventDefault: true,
          onChange: (self) => {
            loop.timeScale(Math.abs(self.deltaX) > Math.abs(self.deltaY) ? -self.deltaX : -self.deltaY) // whichever direction is bigger
            slow.invalidate().restart() // now decelerate
          },
        })
      })
     
      return (
        <div className='absolute bottom-12 w-full cursor-grab overflow-hidden'>
          <ul className={`carousel-${section} carousel flex flex-nowrap pl-0`}>
            {items?.map((item, i) => (
              <li key={i}>
                <Image
                  alt={'collective of images'}
                  src={item}
                  width={150}
                  height={150}
                  sizes='100vw'
                  className='pointer-events-none touch-none select-none '
                />
              </li>
            ))}
          </ul>
        </div>
      )
    }
     
    function horizontalLoop(items, config) {
      items = gsap.utils.toArray(items)
      if (!items.length) return
     
      config = config || {}
      let tl = gsap.timeline({
          repeat: config.repeat,
          paused: config.paused,
          defaults: { ease: 'none' },
          onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100),
        }),
        length = items.length,
        startX = items[0].offsetLeft,
        times = [],
        widths = [],
        xPercents = [],
        curIndex = 0,
        pixelsPerSecond = (config.speed || 1) * 100,
        snap = config.snap === false ? (v) => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural
        totalWidth,
        curX,
        distanceToStart,
        distanceToLoop,
        item,
        i
      gsap.set(items, {
        // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster.
        xPercent: (i, el) => {
          let w = (widths[i] = parseFloat(gsap.getProperty(el, 'width', 'px')))
          xPercents[i] = snap((parseFloat(gsap.getProperty(el, 'x', 'px')) / w) * 100 + gsap.getProperty(el, 'xPercent'))
          return xPercents[i]
        },
      })
      gsap.set(items, { x: 0 })
      totalWidth =
        items[length - 1].offsetLeft +
        (xPercents[length - 1] / 100) * widths[length - 1] -
        startX +
        items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], 'scaleX') +
        (parseFloat(config.paddingRight) || 0)
      for (i = 0; i < length; i++) {
        item = items[i]
        curX = (xPercents[i] / 100) * widths[i]
        distanceToStart = item.offsetLeft + curX - startX
        distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, 'scaleX')
        tl.to(
          item,
          { xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100), duration: distanceToLoop / pixelsPerSecond },
          0,
        )
          .fromTo(
            item,
            { xPercent: snap(((curX - distanceToLoop + totalWidth) / widths[i]) * 100) },
            {
              xPercent: xPercents[i],
              duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond,
              immediateRender: false,
            },
            distanceToLoop / pixelsPerSecond,
          )
          .add('label' + i, distanceToStart / pixelsPerSecond)
        times[i] = distanceToStart / pixelsPerSecond
      }
      function toIndex(index, vars) {
        vars = vars || {}
        Math.abs(index - curIndex) > length / 2 && (index += index > curIndex ? -length : length) // always go in the shortest direction
        let newIndex = gsap.utils.wrap(0, length, index),
          time = times[newIndex]
        if (time > tl.time() !== index > curIndex) {
          // if we're wrapping the timeline's playhead, make the proper adjustments
          vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) }
          time += tl.duration() * (index > curIndex ? 1 : -1)
        }
        curIndex = newIndex
        vars.overwrite = true
        return tl.tweenTo(time, vars)
      }
      tl.next = (vars) => toIndex(curIndex + 1, vars)
      tl.previous = (vars) => toIndex(curIndex - 1, vars)
      tl.current = () => curIndex
      tl.toIndex = (index, vars) => toIndex(index, vars)
      tl.times = times
      tl.progress(1, true).progress(0, true) // pre-render for performance
      if (config.reversed) {
        tl.vars.onReverseComplete()
        tl.reverse()
      }
      return tl
    }

    See the Pen BaPqzvX by andrei-savu (@andrei-savu) on CodePen

  3. Hi, thank you all gsap team for the wonderful lib and resources.

     

    I'm trying to get a slider works as below example in React. The problem is, when the user click fast, the slider x position will be off.  So I'll need to get it snap back to the right position. 

    However, I can't get it snap. I assume I'll need to get a updated progress value, so I do it in onUpdate to manually update animation timeline progress value (which is animationRef.current here). If anyone can point out the right direction I'll be really grateful.

     

    here's my minimal demo

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

    • Like 1
×
×
  • Create New...