Jump to content
Search Community

LuLUE7775

Members
  • Posts

    3
  • Joined

  • Last visited

LuLUE7775's Achievements

  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 https://codepen.io/andrei-savu/pen/BaPqzvX 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 }
  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
×
×
  • Create New...