본 글에서는 Framer Motion을 활용하여 애니메이션이 들어간 지도를 만들어 보겠습니다.

Framer Motion ?

간단히 말해서 Framer Motion은 애니메이션 라이브러리입니다.

애니메이션 라이브러리로 유명한 GSAP과 다운로드 수를 비교했을 때 압도적인 차이를 보여주네요..! Framer Motion이 어떻게 좋은지 직접 예제를 만들며 알아보겠습니다.

🔗 Framer Motion_ 공식 사이트
🔗 GSAP_ 공식 사이트

시작하기

npm install motion 

📚 참고 영상
Making a Realistic Folding Animation With Framer Motion - Frontend FYI – by Jeroen


구조


gird를 사용하여 3개의 영역을 만들어줍니다.

지도 이미지 넣기


각 영역에 지도 이미지를 넣고 background-position를 조절하여 하나의 지도처럼 보일 수 있도록 위치를 조정합니다.
저는 부산 지도를 넣어봤습니다 ㅎㅎ

그 후 transform: translateX로 세 영역을 중앙으로 모아줍니다.


애니메이션 추가

준비는 다 끝났네요! 본격적으로 framer motion을 써보겠습니다!

오른쪽으로 당기면 지도가 펼쳐집니다 🗺️

useMotionValue(initialValue)

실시간으로 변하는 값을 만들 수 있는 훅입니다.

const xDrag = useMotionValue(0);

xDrag.motionBox가 x축으로 얼마나 움직였는지를 담고있는 값입니다.
reactive한 값이기 때문에 다른 스타일에 연결할 수 있습니다.

useTransform(motionValue, [inputRange], [outputRange])

motionValue의 값에 따라 다른 값을 계산해서 반환하는 훅입니다.

const xLeftSection = useTransform(xDrag, [0, 300], ["100%", "0%"]);
const xRightSection = useTransform(xDrag, [0, 300], ["-100%", "0%"]);

xDrag가 0일 때 → xLeftSection = "100%", xRightSection = "-100%"
xDrag가 300일 때 → xLeftSection = "0%", xRightSection = "0%"

오른쪽으로 슬라이드 시 지도 양 끝 영역이 펼쳐지는 것처럼 이동하는 효과를 줄 수 있습니다.

<motion.div drag="x" />

drag 옵션을 더해주면 x축으로 드래그 가능한 컴포넌트가 됩니다.

<motion.div
  style={{ x: xDrag }}
  drag="x"
  dragConstraints={{ left: 0, right: 300 }}
  className="motionBox"
/>

dragConstraints 옵션을 더해 드래그 영역을 지정합니다.
style={{ x: xDrag }}을 통해 드래그한 거리 값을 xDrag에 실시간으로 저장합니다.
xDrag가 위에 있던 useTransform과 연결되어, 지도 양 끝이 드래그한 거리 값에 따라 움직이는 구조가 됩니다.

지도 중앙 부분의 가로 크기와 밝기를 조절하여 안으로 접혀있다가 펼쳐진 느낌을 주었습니다.
여기까지만 해도 애니메이션은 충분한 것 같지만, 사실적인 디테일을 위해 영상에서는 추가적으로 스타일링을 더 진행합니다.

useMotionValueEvent

motionValue가 변경될 때마다 이벤트를 실행할 수 있게 해주는 훅입니다.

useMotionValueEvent(xDrag, "change", (currentX) => {
  if (currentX > 260) {
    setIsFolded(false);
  } else {
    setIsFolded(true);
  }
});

드래그 거리 값이 260 초과면 folded, 260 미만이면 open으로 상태를 설정해서

<motion.div
  animate={isFolded ? "folded" : "open"}
  variants={{ open: { scale: 1 }, folded: { scale: 0.9 } }}
  initial="folded"
>

열고 닫을 때 scale 애니메이션을 줍니다. 다만 codesandbox에서는 scale 애니메이션이 살짝 튀는 것 같습니다. 지도를 접을 때 지도 크기가 엄청 커졌다가 다시 원상태로 복귀합니다..

dragTransition

드래그 후 "놓았을 때"의 움직임을 제어할 수 있는 설정입니다.

<motion.div
  style={{ x: xDrag }}
  drag="x"
  _dragX={xDrag}
  dragConstraints={{ left: 0, right: 300 }}
  className="motionBox"
  layoutId="motionBox"
  dragTransition={{
    modifyTarget: (target) => {
      return target > 150 ? 300 : 0;
    },
      timeConstant: 45,
  }}
/>

modifyTarget으로 드래그 후 어디로 튕겨나갈지 조절할 수 있습니다.
드래그 거리 값이 150 미만이면 접히고, 이상이면 펼쳐집니다.

timeConstant는 움직이는 속도에 관여하는 물리 기반 애니메이션 파라미터입니다.
숫자가 클수록 좀 더 부드럽게 도달하고 작을 수록 툭 붙는 느낌을 냅니다.

결론

codeSandBox라는 다소 낯선 환경에서 작업하느라 애를 먹었지만,, 그럼에도 불구하고!
framer-motion을 통해 쉽고 간단하게 복잡한 애니메이션을 구현할 수 있다는 점이 매우 흥미롭게 다가왔습니다!
특히 useMotionValue을 활용하여 실시간 변하는 값을 다른 스타일에 연결할 수 있다는 점이 신기하네요 🤩

GSAP도 알아봐야겠습니다 ㅎㅎ

profile
생각에 머물지 않기

0개의 댓글