Search code examples
javascriptreactjsanimationsvgframer-motion

pathLength property not working is not animating my path


I'm not accustomed to animating SVG, and I haven't found much on this topic on the internet. That said, I was using framer-motion to animate my SVG in React. The component is extensive, so here is the crucial part:

const animation = {
    initial: {
        pathLength: 0
    },
    animate: {
        pathLength: 1,
        transition: {
            repeat: Infinity,
            duration: 2,
            ease: "easeInOut",
        },
    },
}


return (
        <svg width="100%" height="100%" viewBox="0 0 413 497" fill="none" xmlns="http://www.w3.org/2000/svg">
            <motion.path id="tail" opacity="1" fillRule="evenodd" clipRule="evenodd" variants={animation} initial="initial" animate="animate"

                d="M185.5 -0.5H226.5C304.531 9.93539 360.698 50.6021 395 121.5C404.731 144.678 410.564 168.678 412.5 193.5V216.5C406.132 285.428 374.465 339.261 317.5 378C282.269 399.518 243.936 410.518 202.5 411C199.055 412.388 196.889 414.888 196 418.5C195.5 444.498 195.333 470.498 195.5 496.5H192.5C127.122 471.63 77.2892 428.63 43 367.5C30.8267 345.321 20.9934 322.154 13.5 298C14.1667 297.333 14.8333 297.333 15.5 298C47.042 333.449 86.3753 355.449 133.5 364C194.306 374.132 248.972 360.465 297.5 323C352.866 273.371 368.032 213.538 343 143.5C320.238 94.7722 282.072 66.6056 228.5 59C176.129 53.2301 131.963 69.3968 96 107.5C80.985 125.872 71.6517 146.872 68 170.5C67.8333 218.837 67.3333 267.17 66.5 315.5C29.8186 292.511 7.48524 259.844 -0.5 217.5V191.5C8.65177 107.684 51.6518 48.517 128.5 14C147.035 6.79995 166.035 1.96662 185.5 -0.5Z" fill="#6517ab" />
            </svg>
)

I was expecting it to draw my animation from zero to fully drawn using the pathLength property, but it does not work. I know the const animation is functioning under the #tail because I've used opacity as a property before, and it animated normally. Can someone explain to me why it is not working, and is there a good place to learn SVG animation? Thank you.


Solution

  • path {
      fill: none;
      stroke: DimGray;
      stroke-width: 0.03;
      stroke-opacity: 0.5;
      animation: 2s ease-in-out infinite anim-path-length;
      stroke-dasharray: 1;
      stroke-linejoin: round;
      stroke-linecap: miter;
    }
    
    @keyframes anim-path-length {
      0% {
        stroke-dashoffset: 1;
      }
      100% {
        stroke-dashoffset: 0;
      }
    }
    <svg
      viewBox="0 0 1 1"
      preserveAspectRatio="none"
    >
      <path pathLength="1"
        d="M 0.5,0.2 h -0.3 l -0.1,0.27 l -0.1,0"
      ></path>
      <path pathLength="1"
        d="M 0.5,0.2 h -0.3 l -0.1,0.27 l -0.1,0"
        transform="scale(1 -1) translate(0 -1)"
      ></path>
      <path pathLength="1"
        d="M 0.5,0.2 h -0.3 l -0.1,0.27 l -0.1,0"
        transform="scale(-1 1) translate(-1 0)"
      ></path>
      <path pathLength="1"
        d="M 0.5,0.2 h -0.3 l -0.1,0.27 l -0.1,0"
        transform="scale(-1 -1) translate(-1 -1)"
      ></path>
    </svg>

    The pathLength attribute doesn't do what you think it does. It let's you, the user define an arbitrary number and tell the browser "hey the total length of this path is X units, but in my world it is Y". The advantage is when you define other attributes such as stroke-dash-array or stroke-dash-offset, they are calibrated based on the pathLength you specified.

    Internally and traditionally, one would use getTotalLength and pointAtLength methods to generate and array of points of a path and animate the array, but with frameworks and other libraries, you can use dashoffset like below and pathLength prevents the guesswork of specifying the right value for animation.

    So after you set pathLength, you need to tell framer motion, or whatever you are working with to animate dash-offset or something similar to achieve what you want. See the example below:

    https://jsfiddle.net/ibowankenobi/xL3cdw04/37/