SVG、放物線を使った落下アニメーション。




⬆︎SVGついてのまとめページ、CSSアニメーションの基本コーナーはこちら。





syntax。


animation-timing-function:cubic-bezier(0.33,0.66,0.66,1)


放物線から自作しよう。


こんにちは、「ふ」です。
SVGアニメーション、今回は2次関数を使って、リアルな落下アニメーションに挑戦します。

具体的にはボールを投げ上げたとき、地球の重力法則にちゃんと従った加速/減速をしながら上下する、というもの。
そのためには、CSSのanimation-timing-functionプロパティにその法則を反映させる必要があります。

ちなみにanimation-timing-functionには、予め用意されたタイミング関数が5つあります。
実際に試してみたのがこちら⬆︎。

・ease 着地時が不自然です。下から風が出ているのか?
・linear 終始平均的に進捗する←論外。
・ease-in 地上に近づくにつれゆっくりになる。これでは逆。
・ease-out 上昇していくにつれ減速←かなり近い。
・ease-in-out 上昇と着地のピークで減速←ちがう。

比較したところease-outが、かなり近いような気もするのですが..これで妥協?

いや、せっかくやるのであれば、ちゃんとした放物線をタイミング関数に取り入れることにしました。
animation-timing-functionは上で紹介した関数の他に、cubic-bezier(三次ぺジェ曲線)の状態を使って指定することができます。その方法を利用します。

今回はややマニアックな内容ですが(笑)、この方法を知っておくとwebアニメーションの表現幅がググッと広がります。一緒に作っていきましょう。

 

2次関数をぺジェに落とし込む。


ここでは「リアルな落下運動」に必要な関数式を整理→illustratorに描画→それをSVGで書き出すことで、「放物線をぺジェ曲線で表現」するためのデータを取得します。

放物線の式は、

y = ax²

ですが、アニメーションのタイミング関数を考える場合には

y = x²

のカーブが得られれば問題ありません。
「a」の値は合計の移動距離に影響するものなので、キーフレームに反映させれば良いだけのことです。

illustratorで2次曲線を描きました。
animation-timing-functionはxy方向ともに0〜1の状態で指定するため、これを正方形に収まるよう、変形させる必要があります。あと水平方向のマイナス部分は必要ありません。切り取っておきましょう。

正方形を描画し、それに合わせてパスを変形。

なお今回試すのは「ボールの投げ上げ」なので、アニメーションの進捗は徐々に減衰させていく必要があります。
現在は逆になっているので、変形させたものを180°回転。
この状態でSVGとして書き出します。


<path class="st0" d="M0,1 C「「10.33,0.33  0.66,0」」 1,0"/>

放物線のパスデータが得られました。
青の部分がぺジェ曲線の制御点となります。

ease-outとの比較。

はじめに試してみた定番のeasing関数のうち、比較的自然に見えた「ease-out」。今作成した放物線のカーブと比較してみます。
ease-outもかなり近いが、やはり本物の放物線にくらべるとやや直線的ですね。

 

qubic-bezierはYが逆。


それではこのパスデータを使い、アニメーションさせてみましょう。


<circle id = "maru" cx = "50" cy = "95" r = "5" fill = "coral"/>

SVGで描画した円に対し、投げ上げアニーションをつけていきます。CSSのセレクタで呼び出せるよう、円のidを「maru」としました。



Yの値を反転させる。

ここで注意したいのが、SVGとcssのtiming-functionではY軸の向きが反対になっている、という点です。先ほど得たパスデータの制御点情報をそのままCSSのcubic-bezierに移植しても、放物線のカーブにはなりません。制御点のyの値のみ、逆転させる必要があります。

0.33,0.33  0.66,0

「「3⬇︎ 制御点の座標のうち、Y方向を逆転」」
0.33,「「10.66」」 0.66,「「11」」
yを逆転させたパスデータ(before→after)

制御点のY値を反転させました。
これをanimation-timing-functionに指定します。

  #maru {
        animation:maru 1s alternate infinite;
        animation-timing-function:cubic-bezier(0.33,0.66,0.66,1);
        }
    
    @keyframes maru {
        to {
        transform:translateY(-90%);
        }
    }

自然な投げ上げ運動ができました。

 

横移動もしたい。


「真上に投げ上げ」アニメーションは成功したので、横移動もさせてみましょう。

横移動に関しては、放物線のように進捗が減衰することなく等間隔に進行していきます。
したがってtiming-functionは定番関数の「linear」を使いましょう。


「「1」」
    <circle id = "maru" cx = "0" cy = "100" r = "10" fill = "coral"/>
「「1」」

ただし「#maru」に直接linearのアニメーションを指定すると、せっかく放物線の進捗を取り入れた上下運動が台無しになってしまいます。
そこで「#maru」の外側を<g>で囲んでグループ化。idを「yoko」としました。このグループ要素に対して、横移動のアニメーションを施していきます。
また横移動が観察しやすいよう、円の中心を左下に持っていっています。

ここにlinearの横移動をかけていきます。

#yoko {
        animation:yoko 1s linear alternate infinite;
    }
    
    @keyframes yoko {
        to {
        transform:translateX(100%);
        }
    }

投げ上げ + 横移動ができました。でもこれでは「壁打ち」状態です。
現在アニメーションの所要時間であるanimation-durationはともに「1s」となっているので、このうち横移動のdurationを2倍にしてみましょう。

#yoko {
        animation:yoko 「「12s」」 linear alternate infinite;
    }

これでキャッチボール状態になりました。バレーのトス状態か?
なかなかリアルですね。

 

タイミングをずらすと楽しい。


もっと遊んでみましょう。
ここまでは「投げ上げ」と「横移動」の所要時間をきれいな比率にしていましたが、これをずらしていきます。

#maru {
        animation:maru 「「11.1s」」 alternate infinite;
        animation-timing-function:cubic-bezier(0.33,0.66,0.66,1);
        }
    
#yoko {
    animation:yoko 「「10.8s」」 linear alternate infinite;
    }

投げ上げの所要時間を1.1s、横移動の所要時間を0.8sと、中途半端な比率にしてみました。

ピンボールみたいになりました。
これはこれで楽しいものが作れそう、ふふふ。

今回は「関数式をアニメーションの推移に反映させる」という、少しばかりマニアックなことに挑戦してきました。
冒頭に示したsyntax(構文)を、ぜひコピペしてお使いください。みなさんのwebサイトに楽しい演出を取り入れることができるでしょう。

最後までお読みくださり、ありがとうございます。
ではまた〜 ♬

 
 










SVG、角度を付けてゆらゆら。

2022.05.31
モーフィング+モーションパスの合わせ技。


SVG、桜を散りばめるアニメーション。

2022.03.16
サイトを「春」で彩りましょう。


SVGで転がりアニメーション。

2021.07.28
回転量と移動距離を一致させる方法。











「ふ」です。

swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。