Jump to content
Search Community

Inertia Effect after drag content without InertiaPlugin

mumtazded
Moderator Tag

Recommended Posts

Posted

here's my React.js component:

 

 React, { useRef, useState, useEffect, useCallback } from "react";
import { Avatar, Card, CardBody, Typography } from "@material-tailwind/react";
import gsap from "gsap";
import { Draggable } from "gsap/all";
import { Quote } from "lucide-react";
import InertiaPlugin from "gsap-trial/InertiaPlugin";

// Register GSAP plugins
if (typeof window !== "undefined") {
  gsap.registerPlugin(Draggable, InertiaPlugin);
}

interface ReviewsProps {
  data: CommentCardProps[];
}

const Reviews: React.FC<ReviewsProps> = ({ data }: ReviewsProps) => {
  const wrapperRef = useRef<HTMLDivElement | null>(null);
  const itemsRef = useRef<HTMLDivElement[]>([]);

  // Initialize carouselData as an empty array to avoid null checks

  const [itemHeight, setItemHeight] = useState<number>(0);

  // Initialize windowWidth with a default value (e.g., 0) and update it in useEffect
  const [windowWidth, setWindowWidth] = useState<number>(0);

  // Measure the height of the carousel display after it mounts
  const measuredRef = useCallback((node: HTMLDivElement | null) => {
    if (node !== null) {
      setItemHeight(node.getBoundingClientRect().height);
    }
  }, []);

  // Add references to carousel items
  const addToRefs = useCallback((el: HTMLDivElement | null) => {
    if (el && !itemsRef.current.includes(el)) {
      itemsRef.current.push(el);
    }
  }, []);

  // Create GSAP animation timeline
  const createAnimation = (
    carouselItems: HTMLDivElement[],
    width: number
  ): gsap.core.Timeline | undefined => {
    if (carouselItems.length > 0) {
      const timeline = gsap.timeline({ repeat: -1, paused: true });
      timeline.to(carouselItems, {
        duration: 1,
        x: `+=${width}`,
        ease: "linear",
        overwrite: "auto",
        // repeat: -1,
        modifiers: {
          x: (x) => {
            const parsedX = parseFloat(x) % width;
            return `${parsedX}px`;
          },
        },
      });
      return timeline.progress(1 / carouselItems.length);
    }
    return undefined;
  };

  // Initialize carousel animation
  const carouselAnimation = useCallback(() => {
    const carouselItems = itemsRef.current;
    if (!carouselItems.length) return;

    const itemWidth = carouselItems[0].clientWidth;
    const carouselWidth = itemWidth * carouselItems.length;
    const snapBox = gsap.utils.snap(itemWidth);

    // Set initial positions of carousel items
    carouselItems.forEach((elm, i) => {
      gsap.set(elm, { x: i * itemWidth, left: -itemWidth });
    });

    // Set the height of the wrapper
    if (wrapperRef.current) {
      gsap.set(wrapperRef.current, { height: itemHeight });
    }

    const wrapProgress = gsap.utils.wrap(0, 1);
    const proxy = document.createElement("div");
    const timeline = createAnimation(carouselItems, carouselWidth);

    if (timeline) {
      Draggable.create(proxy, {
        trigger: "#elm",
        throwProps: true,
        inertia: true,
        dragResistance: 0.55,
        onDrag: updateProgress,
        onThrowUpdate: updateProgress,
        dragClickables: true,
        snap: {
          x: snapBox, // Ensure correct type
        },
      });
    }

    function updateProgress() {
      if (timeline) {
        const progress = gsap.getProperty(proxy, "x") as number;
        timeline.progress(wrapProgress(progress / carouselWidth));
      }
    }
  }, [createAnimation, itemHeight]);

  // Set initial carousel data

  // Handle window resize and initialize carousel animation
  useEffect(() => {
    // Define a function to update window width
    const handleWindowResize = () => setWindowWidth(window.innerWidth);

    // Set initial window width
    handleWindowResize();

    // Add resize event listener
    window.addEventListener("resize", handleWindowResize);

    // Initialize carousel animation
    carouselAnimation();

    // Cleanup event listener on unmount
    return () => {
      window.removeEventListener("resize", handleWindowResize);
    };
  }, [carouselAnimation]);

  return (
    <div className="carousel-container-try" id="wrapper" ref={wrapperRef}>
      <div className="carousel-display-try  h-96" ref={measuredRef}>
        {data.map((_, i) => (
          <div
            key={i}
            id="elm"
            className="carousel-display-try__item"
            ref={addToRefs}
          >
            <CommentCard
              key={i}
              name={_.name}
              comment={_.comment}
              position={_.position}
              profile={_.profile}
            />
          </div>
        ))}
      </div>
    </div>
  );
};
// {carouselData.map((item) => (
//   <div
//     key={item}
//     id="elm"
//     className="carousel-display-try__item"
//     ref={addToRefs}
//   >
//     {item}
//   </div>
// ))}

type CommentCardProps = {
  name: string;
  position: string;
  comment: string;
  profile: string;
};

function CommentCard({ comment, name, position, profile }: CommentCardProps) {
  return (
    <>
      <Card className="py-2 px-4 w-96 bg-tertiary dark:bg-primary mx-2">
        <CardBody className="flex flex-col justify-between gap-4">
          <div className="flex items-start">
            <Quote className="w-6 h-6 text-secondary" />
          </div>

          <Typography className="text-lg text-secondary">{comment}</Typography>

          <div className="flex items-end">
            <Quote className="w-6 h-6 text-secondary" />
          </div>
          <hr className="my-2 h-[1px] border-t-0 bg-secondary" />
          <div className="flex gap-4 items-center">
            <Avatar src={profile} alt="astronout" />
            <div className="flex flex-col gap-q">
              <Typography className="text-lg font-bold text-secondary">
                {name}
              </Typography>
              <Typography className="text-base text-secondary/50">
                {position}
              </Typography>
            </div>
          </div>
        </CardBody>
      </Card>
    </>
  );
}

export default Reviews;

I want to use that inertia effect when I drag my content without InertiaPlugin, anyone maybe even tried that?

 

Screenshot 2024-12-31 at 11.40.43.png

Posted

Not actually, that's the sole purpose of having the Inertia Plugin 😅, makes no sense to try to re-create it from scratch (as fun as the challenge is). Basically is like you going to the chicken place and asking for the secret recipe and if someone has tried to make the recipe from scratch after they already have it. Doesn't make a lot of sense to use a lot of time and effort in trying to do something that has already been done.

 

Also keep in mind that the Inertia Plugin is just one of the many bonus Plugins you get when you sign up for the GSAP Club and a full year membership pays itself in one or two projects, after that is all profits for the rest of that year.

 

Finally when working with React, we recommend using our useGSAP hook, you can learn more about it here:

https://gsap.com/resources/React

 

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