Jump to content
Search Community

ashitaaka

Members
  • Posts

    1
  • Joined

  • Last visited

ashitaaka's Achievements

  1. Hi, (stack : Next JS) i'm close to achieve an effect but am stuck! Here is the result of where i am for now : https://youtu.be/tXUPHLRPiDA As you can see, I'd like to make a transition on clicking to a project thumbnail. Problem : I don't want the container to scaleY up, but i want to keep the infos/image inside to a normal ratio. I tied to animate height, instead of scaleY, but then I have to also animation the scrollTo, and it was a bit messy... Here is the ProjectThumb component (I do have a project list with several ProjectThumb) : import React, { useRef, useState } from "react"; import { useGSAP } from "@gsap/react"; import gsap from "gsap"; import { lineAnimation, projectContainerAnimation, scrollAnimation, subtitleAnimation, titleAnimation, } from "../animations/animations"; import { ScrollToPlugin } from "gsap/ScrollToPlugin"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import Image from "next/image"; import { useRouter } from "next/navigation"; gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollToPlugin); const ProjectThumb = ({ project, setClicked, clicked, }: { project: any; setClicked: React.Dispatch<React.SetStateAction<number | null>>; clicked: number | null; }) => { const lineRef = useRef<HTMLDivElement>(null); const thumbContainerRef = useRef<HTMLDivElement>(null); const titleRef = useRef(null); const subTitleRef = useRef(null); const imageRef = useRef(null); const router = useRouter(); const [timeline, setTimeline] = useState<any>(); const [timeline2, setTimeline2] = useState<any>(); // set line animation timeline up useGSAP(() => { if (lineRef.current) { const tl2 = gsap.timeline({ scrollTrigger: { trigger: lineRef.current, start: "top 85%", toggleActions: "play end resume reverse", }, }); tl2.add(lineAnimation(lineRef)); setTimeline2(tl2); } }, [lineRef]); // Set project elements timeline up useGSAP(() => { const tl = gsap.timeline(); setTimeline(tl); // show off all project container but the one clicked if (clicked && clicked !== project.id && thumbContainerRef.current) { timeline.to( thumbContainerRef.current, { opacity: 0, duration: 0.5, }, `<${Math.abs((clicked - project.id) * 0.5) / 3}` ); } }, [clicked, thumbContainerRef]); const handlePlayAnimation = () => { if ( thumbContainerRef.current && subTitleRef.current && titleRef.current && timeline2 && timeline ) { setClicked(project.id); timeline2.clear(); timeline2.to(lineRef.current, { scaleX: 0, duration: 0.5, }); const offset = window.innerHeight * 0.5 - thumbContainerRef.current.getBoundingClientRect().height / 2 - 32; const thumbContainerScale = window.innerHeight / thumbContainerRef.current.getBoundingClientRect().height; timeline .add(scrollAnimation(thumbContainerRef, offset)) .add(titleAnimation(titleRef), "-=0.4") .add(subtitleAnimation(subTitleRef), "-=0.25") .add( projectContainerAnimation(thumbContainerRef, thumbContainerScale), "<=0.3" ); // .then(() => router.push(`/projects/${project.id}`)); } }; return ( <div className={`project_container_${project.id} overflow-hidden min-h-[25vh] relative`} ref={thumbContainerRef} > <div ref={lineRef} className="projectLine scale-x-0 h-2 bg-slate-500 opacity-100" ></div> <div onClick={handlePlayAnimation} className="project_infos button absolute w-full h-full z-10 cursor-pointer" > <div></div> <div className="project_title flex gap-4 p-8 items-end text-white" key={project.id} > <h3 ref={titleRef} className="project_title text-2xl w-full text-slate-800" > {project.title} </h3> <p ref={subTitleRef} className="project_subtitle w-full text-slate-800" > {project.subtitle} </p> </div> </div> <Image ref={imageRef} src={project.images.thumbnail} width={1920} height={1080} alt={project.title} className="h-full object-cover aspect-square opacity-30 absolute" /> </div> ); }; export default ProjectThumb; And here are the animations called by the previous component : import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import { ScrollToPlugin } from "gsap/ScrollToPlugin"; gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(ScrollToPlugin); export const lineAnimation = (ref: any) => { return gsap.to(ref.current, { scaleX: 1, transformOrigin: "left", duration: 0.75, }); }; export const thumbContainerAnimation = (ref: any) => { return gsap.to(ref.current, { height: "100vh", transformOrigin: "top center", duration: 1, ease: "expo.in", }); }; export const scrollAnimation = (ref: any, offset: number) => { return gsap.to(window, { duration: 0.75, scrollTo: { y: ref.current, offsetY: offset }, ease: "expo.inOut", }); }; export const titleAnimation = (ref: any) => { return gsap.to(ref.current, { duration: 0.4, y: -50, opacity: 0, ease: "expo.in", }); }; export const subtitleAnimation = (ref: any) => { return gsap.to(ref.current, { duration: 0.35, y: -50, opacity: 0, ease: "expo.in", }); }; export const projectContainerAnimation = (ref: any, scale: number) => { return gsap.to(ref.current, { scaleY: scale, transformOrigin: "center", duration: 1.2, ease: "power4.inOut", }); };
×
×
  • Create New...