Blog

パスに沿って動くアニメーション

サイトを公開したばかりなので、いくつかはこのサイト絡みのあれこれを書こうと思っているのですが、
今回はお問い合わせの鳥のアニメーションについてです。

問い合わせボタンを送信すると、メールがとび上がり鳥が咥えて飛んでいきますが、
作っている途中に気づきました。

問い合わせする人以外に、この動きを見てもらえない。

なので、動画とってこちらに載せることにしました。

完成形

メールも飛んでいますが、まずは鳥のアニメーションの説明です。

gsapをインストールし、使える状態にする

MotionPathPluginを使えば、任意のパスに沿ってターゲットをアニメーションをさせることができます。

まずgsapをインストール

npm i gsap

読み込みます。

import { gsap } from "gsap/dist/gsap";
import { MotionPathPlugin } from "gsap/MotionPathPlugin";
gsap.registerPlugin(MotionPathPlugin);

鳥とパスをHTMLに用意

<div class="contactBird-wrap">
  <div class="contactBird">
    <span class="contactBird-inner"><img src="img/contact-bird-mailsend.png"></span>
  </div>
  <div class="contactBirdpath">
    <path id="birdpath" d="M0,0S99.454,497.745,607,485C1225.85,469.46,3436,62,3436,62M0,0S99.454,497.745,607,485C1225.85,469.46,3436,62,3436,62" />
  </div>
</div>

パスは直接HTMLに入れていますが、JS側にd属性の値を入れることも可能です。
パスを作るのはなんでも良いですが、IllustratorやPhotoshopでパスを作ってSVG書き出しすれば、テキストエディタで開いてpathを入手できます。

余談ですが、SVGからパスを抽出する場合、カンバスサイズがパスに合ってないと、あとからいろいろ調整が必要になってしまいます。SVGファイルにはviewBoxというカンバスのような概念があり、パスの位置も、その中でのこの座標というように決まってきます。viewBoxがパスの大きさに合ってないと、pathにtransform属性が追加され、そこで位置調整がされるようで、これが後々位置決めを狂わせる原因となります。
書き出しする前にカンバスがパスに合ってるかを確認し、書き出し後にpath要素にtransform属性が入っていないか確認することをお勧めします。

クリックしたら飛ぶように

※jQuery使用してます。

$('.contactBtn input').on('click',function(){
  gsap.set('#birdpath',{xPercent:-50,yPercent:-50,transformOrigin:'50% 50%'});
  gsap.to('.contactBird', {
    duration: 5,
    motionPath:{
      path:'#birdpath',
      autoRotate: true,//先頭方向が自動で動く
    }
  })
})

motionPathのところで、pathプロパティにパスのIDを指定します。基本これだけでOKです。
transformOriginは、ターゲット(鳥)の中心にパスを合わせるにために指定していますが、motionPathの中でalignOrigin:[0.5 ,0.5]を指定しても同じようなことが可能です。
それをgsap.toで動かします。

パスデータではなく、xとyの組み合わせ配列でもOK

実は、上記のようにパスの値を使う方法だと、どうにもレスポンシブ対応しにくい…というのがありました。
場合によるとは思いますが、今回はパスの値を使うことをやめ、xとyの配列でカーブを描くことにしました。

  motionPath:{
    path: [{ x: 500, y: 200 }, { x: 2000, y: -500 }],
    autoRotate: true,//先頭方向が自動で動く
    curviness:1,
    ease: 'power3.in'
  }

pathの値にx、yのオブジェクトの配列を入れます。
curvinessは、「どの程度曲がっているか」です。0が直線を表すので、上記だとx500/y200のところでカクッと折れます。湾曲した動きがほしいので、1を指定しています。

結果的にいろいろやった結果、このアニメーションがスマホで厳しいのは変わらないので、スマホでは鳥は潔く見切れてしまいました。
考えていたこととは違う実装方法になることが本当に多い…何事も経験。

タイムラインを作成

メールがとんで、鳥が飛びます。
二つのタイムラインを作って、あとで同時に走らせます。

flybird(){
  let tl1 = () => {
    // メール
    let tl = gsap.timeline();
    tl
      .to('.contactBtn-mail',{duration:.5,y:-400,ease:'back.out(1.7)'})
      .to('.contactBtn-mail', { duration: 2.9, x: 2000 ,y:-870 })
      .set('.contactBtn-mail', { y: 0, x: 0,scale:0 })
      .to('.contactBtn-mail', { duration: .3, scale:1})
    return tl
  }
  let tl2 = () =>{
    // 鳥
    let tl = gsap.timeline();
    tl.to('.contactBird', {
      duration: 3,
      delay:.3,
      motionPath:{
        path: [{ x: 500, y: 200 }, { x: 2000, y: -500 }],
        autoRotate: true,
        curviness:1,
        ease: 'power3.in'
      }
    })
    .set('.contactBird', { y: -1300, x: 0 })
    .to('.contactBird', {
      duration: .5,
      y: 0
    })
    .to('.contactBird', {
      duration: .5,
      rotate: 0,
      ease: 'power2.out'
    })
    return tl
  }
  return [tl1,tl2]
},

これを、ボタンが押されて送信OKになったあと、実行します。

handleSubmit () {
  //送信してもOK!になったら

  move('#contacthead');
  setTimeout(function () {
    const tl = this.flybird()
    tl[0]()
    tl[1]()
  }.bind(this), 800)
}

(move関数は、鳥のところまで上にスクロールするものを別で書いていますが省略)
800ミリ秒でスクロールが完了した後にメールと鳥が飛びます。

まとめ

MotionPathPluginは、ほかにも、パスのこの位置からスタート、この位置で終わりといった設定など、プロパティがたくさんあります。自由な動かし方ができるので、また使いどころを考えたいと思います。

おすすめの記事 recommend blog

新着 new blog

github