FramerMotionでクリスマスっぽいものを作る!


はじめに

これはCyberAgent 20新卒 Advent Calendar 2019の7日目の記事です!
クリスマスが待ち遠しいですね🎅今回はWebフロントでクリスマスっぽい何かを作っていきたいと思います💪

前置き

今回はFramerMotionと言うReactのアニメーションライブラリを使ってみたいと思います!

FramerMotionとは

FramerMotionはReactのDesign系のライブラリで、リッチなアニメーションを簡単に作ることが出来ます。

import { motion } from "framer-motion"

export const MyComponent = () => (
  <motion.div
    animate={{ scale: 2 }}
    transition={{ duration: 0.5 }}
  />
)

記法はこのようになっていて、アニメーションの目的地点をanimateに、そこまでの流れをtransitionに記述することで作動します。FramerMotionではmotion.divのようなHTMLの要素に加え、motion.svgでsvgに対しても簡単にアニメーションを付与することが可能です!

指定可能なanimationの参考
https://www.framer.com/api/motion/component/#supported-values

指定可能なtransitionの参考
https://www.framer.com/api/motion/types/#transition

作業内容

概要

今回はFramerMotionのsvgアニメーションに着目して、svgでクリスマスツリーのアニメーションを作ってみたいと思います!それでは順番に解説していきます!

手順

  1. イラストをSVGで書き出す
  2. Reactプロジェクト作成とSVGの埋め込み
  3. FramerMotionでアニメーションをつける

(Option: 雪を降らせる❄️)

1. イラストをSVGで書き出す

SVGは座標指定することで図形を描画できます。

参考
https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Paths

ですが、複雑な図形を作るのは大変なので、Drawingソフトで図形を描き、自動でSVGをエクスポートします。今回は、無料で使えるVectrを使って作成しました!
🚨デザインは一筆書きで作ります。

2. Reactプロジェクト作成とSVGの埋め込み

プロジェクト作成

FramerMotionはReact用のDesignライブラリなので、Reactのプロジェクトを新規で作成します。今回はcreate-react-appを使ってサクッと立ち上げていきます!

// Reactプロジェクト作成
$ yarn create react-app merry-xmas
// framer-motionの追加
$ yarn add framer-motion

今回は

  • ツリーてっぺんの星
  • 木の部分(緑色)
  • 幹の部分(茶色)

でパーツを作って組み合わせます。

SVG埋め込み

1.でエクスポートした.svgのファイルをVSCodeなどで開くと、<path d="M...Z">が見つかると思います。この" "で囲まれた中をFramerMotionの<motion.path>に記述することで、線画のアニメーションが可能となります👍

// 木の部分(緑色)
<motion.path
  className="tree-body-stroke"
  d="M140.93 32.47L154.78 49.39L168.57 66.88L177.28 76.47L147.28 76.47L156.16 90.01L167.44 103.9L183.23 123.85L199.78 140.21L213.13 150.93L177.28 150.93L184.78 164.46L197.9 182.65L217.08 205.15L234 222L0.48 222L19.78 202.26L42.28 174.05L58.57 150.93L21.35 150.93L32.63 141.9L46.73 127.8L63.09 108.62L76.06 92.65L87.28 75.91L57.28 75.91L73.8 57.29L88.47 38.11L117.28 -0.24L140.93 32.47Z"
  variants={body}
  initial="hidden"
  animate={isVisible ? "visible" : "hidden"}
/>

上記のvariantsはより柔軟なアニメーションの指定ができる仕組みだと思います。

const body = {
  hidden: {
    // animateの内容
    opacity: 0,
    pathLength: 0,
    fill: "rgba(2, 135, 96, 0)",
    // transitionの内容
    transition: {
      duration: 3.3,
      ease: "anticipate",
      fill: { duration: 3.5 }
    }
  },
  visible: {
    opacity: 1,
    pathLength: 1,
    fill: "rgba(2, 135, 96, 1)",
    transition: {
      duration: 2,
      ease: "easeInOut",
      fill: { duration: 3 }
    }
  }
};

こんな感じでanimateとtransitionを個別の条件ごとに定義できます。

3. FramerMotionでアニメーションをつける

今回は

  • Springによるアニメーション
  • ドローのアニメーション

の2つを作っていきます。

Springによるアニメーション

Springとは、バネのような物理的な挙動を模したアニメーションです。他のライブラリだとreact-springが有名です。

今回はこれで、左右にバウンドする星を作ってみたいと思います!

<motion.svg
  xmlns="https://www.w3.org/2000/svg"
  viewBox="0 0 50 50"
  initial={{ rotate: 0 }}
  animate={{
    rotate: [-45, 40, -35, 30, -25, 20, -15, 10, -5, 3, -2, 1, 0]
  }}
  transition={{
    delay: 1.5,
    type: "spring",
    loop: Infinity,
    repeatDelay: 2,
    duration: 1.3
  }}
>

徐々に減衰していく運動を、今回は簡単にrotateを減少させる形で実現しました。これでプルプル揺れるお星様の完成です⭐️

ドローのアニメーション

SVGは座標をつなぎ合わせて図形を描画しており、このつなぎ合わせる部分をアニメーションにすることが出来ます!今回はこれで、ツリーの外形が徐々に作られていく様子をアニメーションにしたいと思います。

const body = {
  hidden: {
    pathLength: 0,
    fill: "rgba(2, 135, 96, 0)",
    ...
  },
  visible: {
    pathLength: 1,
    fill: "rgba(2, 135, 96, 1)",
    ....
  }
};

pathLengthが1で全ての点が結合された(図形が描画された)状態になります。
fillで枠の内側の着色を指定できます。

完成

最終的に出来上がったものがこちらになります🎄

メリークリスマスイブ×18日

まとめ

今回初めてAdventCalendarに投稿させていただきましたが、固すぎず緩すぎず、ちょうど良い温度感で取り組めたのが良かったなと思っています!お誘いいただきありがとうございました👍

自分はデザインの方面にも興味があるので、今後もこうしたデザイン系の情報をキャッチアップしていければなと思います!

最後に

☃️雪はparticle.jsで描画しています❄️