Jump to content
Search Community

HaCa

Members
  • Posts

    2
  • Joined

  • Last visited

HaCa's Achievements

  1. Hello again, It's been very helpful. After I replaced useEffect with useGSAP, I realized it's also not working on local properly, it was a visual illusion. I cleaned the code and solved the issue. Thanks for your help 🙏
  2. Hello, I created an infinite vertical scroll like effect for my cards, it took a while but with the helps of forums and some demos, it worked perfectly for me on local. However, when I check production, I see that it's not working properly, cards are appearing small and origin seems like below, some cards get bigger some are not, and most ambiguous one is if i scroll up, animation works properly for like 4-5 cards, but when i scroll down card disappears immediately. I deploy with vercel and there is no club plugin as you can see. Can you please enlighten me about the issue? I suspected with some css conflict but couldn't find a way to solve it. It took my whole day and decided to ask some help here. Purpose of animation ( in case there is a much more basic or consistent way to do this ) -Avoid page scroll over container and avoid animation work when page is scrolled outside card container. -Give a seamless vertical scroll effect without showing any scroll bar. Stack: - Next14, Typescript, Vercel for deployment Thank you for your help. local.mov ``` import React, { useEffect } from "react"; import { gsap } from "gsap"; import { IWorkOption, workOptions } from "../../utilities"; import styles from "./card-container.module.css"; const scrollSpeedMultiplier = 0.0001; const CardContainer = ({ setItemSelected }: { setItemSelected: React.Dispatch<React.SetStateAction<IWorkOption>> }) => { useEffect(() => { const cards = Array.from(document.querySelectorAll(".single-one-pair")); const spacing = 0.1; const seamlessLoop = buildSeamlessLoop(cards, spacing, animateCard); const playhead = { offset: 0 }; const scrub = gsap.to(playhead, { offset: 0, onUpdate: () => { seamlessLoop.time(wrapTime(-playhead.offset)); }, duration: 0.5, ease: "power3", paused: true, }); function animateCard(element: Element) { const tl = gsap.timeline(); tl.fromTo(element, { scaleX: 0.8, scaleY: 0.1 }, { scaleX: 1, scaleY: 0.9, opacity: 1, duration: 0.5, yoyo: true, repeat: 1, ease: "power1.in", immediateRender: false }).fromTo( element, { yPercent: -400 }, { yPercent: 400, duration: 1, ease: "none", immediateRender: false }, 0 ); return tl; } function buildSeamlessLoop(items: Element[], spacing: number, animateFunc: (element: Element) => gsap.core.Timeline) { let rawSequence = gsap.timeline({ paused: true }), seamlessLoop = gsap.timeline({ paused: true }); items .concat(items) .concat(items) .concat(items) .forEach((item, i) => { let anim = animateFunc(items[i % items.length]); rawSequence.add(anim, i * spacing); }); seamlessLoop.fromTo(rawSequence, { time: spacing * items.length }, { time: `+=${spacing * items.length}`, duration: spacing * items.length, ease: "none" }); return seamlessLoop; } function wrapTime(offset: number) { return gsap.utils.wrap(0, seamlessLoop.duration())(offset); } const ulElement = document.querySelector(".pair-container"); function handleMouseEnter() { ulElement?.addEventListener("wheel", handleWheel as EventListener); ulElement?.addEventListener("touchstart", handleTouchStart as EventListener); ulElement?.addEventListener("touchmove", handleTouchMove as EventListener); ulElement?.addEventListener("touchend", handleTouchEnd as EventListener); scrub.play(); // Start the animation when the mouse enters } function handleMouseLeave() { ulElement?.removeEventListener("wheel", handleWheel as EventListener); ulElement?.removeEventListener("touchstart", handleTouchStart as EventListener); ulElement?.removeEventListener("touchmove", handleTouchMove as EventListener); ulElement?.removeEventListener("touchend", handleTouchEnd as EventListener); scrub.pause(); // Pause the animation when the mouse leaves } function handleWheel(event: WheelEvent) { event.stopPropagation(); event.preventDefault(); console.log("Wheel event deltaY:", event.deltaY); // Log deltaY for debugging scrub.vars.offset += event.deltaY * scrollSpeedMultiplier; // Adjust scroll speed as necessary scrub.invalidate().restart(false); } let touchStartY = 0; function handleTouchStart(event: TouchEvent) { touchStartY = event.touches[0].clientY; } function handleTouchMove(event: TouchEvent) { const touchEndY = event.touches[0].clientY; const deltaY = touchStartY - touchEndY; touchStartY = touchEndY; // Update the start position for the next move console.log("Touch move deltaY:", deltaY); // Log deltaY for debugging scrub.vars.offset += deltaY * scrollSpeedMultiplier; // Adjust scroll speed as necessary scrub.invalidate().restart(); event.preventDefault(); } function handleTouchEnd(event: TouchEvent) { touchStartY = 0; // Reset the touch start position } ulElement?.addEventListener("mouseenter", handleMouseEnter); ulElement?.addEventListener("mouseleave", handleMouseLeave); return () => { ulElement?.removeEventListener("mouseenter", handleMouseEnter); ulElement?.removeEventListener("mouseleave", handleMouseLeave); ulElement?.removeEventListener("wheel", handleWheel as EventListener); ulElement?.removeEventListener("touchstart", handleTouchStart as EventListener); ulElement?.removeEventListener("touchmove", handleTouchMove as EventListener); ulElement?.removeEventListener("touchend", handleTouchEnd as EventListener); gsap.killTweensOf(playhead); }; }, []); return ( <div className={styles.body}> <ul className="pair-container" style={{ width: "100%", height: "100%", display: "flex", alignItems: "center" }}> {workOptions.map((card, i) => ( <li key={i} className="single-one-pair" style={{ listStyle: "none", padding: 0, margin: 0, width: "100%", height: "80%", position: "absolute", display: "flex", justifyContent: "center", alignItems: "center" }} > <div key={i} className={styles.pairItem} style={{ backgroundColor: "red" }} onClick={() => setItemSelected(card)}> <div className={styles.overlay}> <h2 className={styles.overlayText}>{i}</h2> </div> </div> </li> ))} </ul> </div> ); }; export default CardContainer; ``` prod.mov
×
×
  • Create New...