so woon!

[FRAMER MOTION] svg Animation 본문

Framer Motion/개념정리

[FRAMER MOTION] svg Animation

xowoony 2023. 5. 14. 21:08

학습일 : 2023. 05. 14


 

font awesome  등의 사이트에서
원하는 로고 또는 아이콘을 고르고

 

 svg탭에서 코드를 복사 해서


Wrapper 안에 붙여주고
스타일링을 해준다.

모든 svg는 path를 가지고 있고,

 path는 fill을 가지고 있다.



애니메이션 적용을 위해

path에도
그냥 <path />를 쓰면 안되고
<motion.path /> 로 바꾸어 주어야 한다.

 

 



import { styled } from "styled-components";
import { motion } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Svg = styled.svg`
  width: 300px;
  height: 300px;
`;

function App() {
  return (
    <Wrapper>
      <Svg
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 512 512"
      >
        <motion.path
          //처음상태
          initial={{ fill: "rgba(134, 73, 255, 0)" }}
          // 최종상태
          animate={{
            fill: "rgba(134, 73, 255, 1)",
          }}
          transition={{ duration: 3 }}
          stroke="rgb(134, 73, 255)" // stroke를 작성하면 선이 생김
          strokeWidth="3" // 선굵기
          d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
        />
      </Svg>
    </Wrapper>
  );
}
export default App;




실행결과

 



pathLength

pathLength는 현재 위치까지의 path의 길이를 나타낸다.


pathLength 값을 바꿔서 위치를 조정할 수 있음.

일단은 처음 0위치에서 시작해서 1위치에서 끝나도록 해보면

import { styled } from "styled-components";
import { motion } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Svg = styled.svg`
  width: 300px;
  height: 300px;
`;

function App() {
  return (
    <Wrapper>
      <Svg
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 512 512"
      >
        <motion.path
          //처음상태
          initial={{ pathLength: 0, fill: "rgba(134, 73, 255, 0)" }}
          // 최종상태
          animate={{
            fill: "rgba(134, 73, 255, 0)",
            pathLength: 1,
          }}
          transition={{ duration: 3 }}
          stroke="rgb(134, 73, 255)"
          strokeWidth="3"
          d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
        />
      </Svg>
    </Wrapper>
  );
}
export default App;




실행결과






이 상태에서 animate 의 opacity를 1로 변경해주면


import { styled } from "styled-components";
import { motion } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Svg = styled.svg`
  width: 300px;
  height: 300px;
`;

function App() {
  return (
    <Wrapper>
      <Svg
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 512 512"
      >
        <motion.path
          //처음상태
          initial={{ pathLength: 0, fill: "rgba(134, 73, 255, 0)" }}
          // 최종상태
          animate={{
            fill: "rgba(134, 73, 255, 1)",
            pathLength: 1,
          }}
          transition={{ duration: 3 }}
          stroke="rgb(134, 73, 255)"
          strokeWidth="3"
          d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
        />
      </Svg>
    </Wrapper>
  );
}
export default App;



실행결과



그리고 이 모든 애니메이션들을
variants
를 작성하여 묶어주도록 하겠다.


import { styled } from "styled-components";
import { motion } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Svg = styled.svg`
  width: 300px;
  height: 300px;
  // 여기서 path의 stroke, stroke-width를 작성해 주어도 상관없음.
  path {
    stroke: rgb(134, 73, 255);
    stroke-width: 2;
  }
`;

// variants
const svg = {
  start: { pathLength: 0, fill: "rgba(134, 73, 255, 0)" },
  end: {
    fill: "rgba(134, 73, 255, 1)",
    pathLength: 1,
    transition: { duration: 5 },
  },
};

function App() {
  return (
    <Wrapper>
      <Svg
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 512 512"
      >
        <motion.path
          variants={svg}
          //처음상태
          initial="start"
          // 최종상태
          animate="end"
          d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
        />
      </Svg>
    </Wrapper>
  );
}
export default App;




실행결과는 아까와 똑같음.


default값을 줘서 모든 트랜지션의 default duration을 설정해주기


<motion.path>안에서도 transition을 줄 수 있는데

transition으로 default: { duration: 5 } 를 주면 이전과 같이
총 5초동안 애니메이션이 일어남.

import { styled } from "styled-components";
import { motion } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Svg = styled.svg`
  width: 300px;
  height: 300px;
  path {
    stroke: rgb(134, 73, 255);
    stroke-width: 2;
  }
`;

// variants
const svg = {
  start: { pathLength: 0, fill: "rgba(134, 73, 255, 0)" },
  end: {
    fill: "rgba(134, 73, 255, 1)",
    pathLength: 1,
  },
};

function App() {
  return (
    <Wrapper>
      <Svg
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 512 512"
      >
        <motion.path
          variants={svg}
          //처음상태
          initial="start"
          // 최종상태
          animate="end"
          // transition - default값 (모든 트랜지션의 default duration을 5로 설정)
          transition={{
            default: { duration: 5 },
          }}
          d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
        />
      </Svg>
    </Wrapper>
  );
}
export default App;




실행결과
이전과 같음.

 


특정 property 트랜지션만 따로 변경해주기

 


위에 적어준 것처럼 <motion.path> 안에서 transition으로 
default를 작성하여 
모든 트랜지션의 default duration을 설정해줄 수 있지만,

 


특정 property의 트랜지션을 따로 변경해주고 싶다면


예를 들어 fill의 트랜지션을 따로 변경하고 싶으면
transition 안에 fill을 적어주고 변경할 값들을 적어주면 된다.
아래와 같이 작성해주면 된다.

import { styled } from "styled-components";
import { motion } from "framer-motion";

// style
const Wrapper = styled(motion.div)`
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const Svg = styled.svg`
  width: 300px;
  height: 300px;
  path {
    stroke: rgb(134, 73, 255);
    stroke-width: 2;
  }
`;

// variants
const svg = {
  start: { pathLength: 0, fill: "rgba(134, 73, 255, 0)" },
  end: {
    fill: "rgba(134, 73, 255, 1)",
    pathLength: 1,
  },
};

function App() {
  return (
    <Wrapper>
      <Svg
        focusable="false"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 512 512"
      >
        <motion.path
          variants={svg}
          //처음상태
          initial="start"
          // 최종상태
          animate="end"
          // property의 transition 시간 정하기
          transition={{
            default: { duration: 5 },
            fill: { duration: 2, delay: 4 }, // fill만 duration을 2, delay를 4로 설정
          }}
          d="M391.17,103.47H352.54v109.7h38.63ZM285,103H246.37V212.75H285ZM120.83,0,24.31,91.42V420.58H140.14V512l96.53-91.42h77.25L487.69,256V0ZM449.07,237.75l-77.22,73.12H294.61l-67.6,64v-64H140.14V36.58H449.07Z"
        />
      </Svg>
    </Wrapper>
  );
}
export default App;




실행결과
4초 후에 fill animation이 나오게 됨.

 

 

 

Comments