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

〽️円周長さの領域。 〽️画像作成。 〽️web上で転がす。 〽️坂道発進。





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

こんにちは、「ふ」です。
今回は「球体が転がる」SVGアニメーションを作っていきましょう。記事執筆時期がちょうど夏休みに入ったところなので、スイカを転がすことにしました。

「転がる」ということは、回転と移動を同時に行っているということに成増。CSSのtransformには「rotate(回転)」と「translate(移動)」がありますが、ただ2つを同時に行っただけではうまくいきません。

回転量と移動距離がリンクしていなければ不自然なアニメーションになってしまいます。
⬆︎の画像がバランスの悪い例です。回転の割には全然前に進めていませんね💧

転がしアニメーション最大のポイントは、「回転量と移動量を同じにする」ことです。
やり方は色々考えられますが。SVGならではの利点を使いましょう。
なるべく簡単に、ブラウザへの負荷も少なく実装する方法を見つけたので紹介します。

円周長さの領域。


SVGの可視領域(viewBox)の左端に円オブジェクト( id = "sample" )を配置。これをCSSのtransformで移動させてみます。

■ CSS

#sample { tranform:translateX(100%); }

移動距離を100%とすると、ちょうど端から端まで移動しました。

SVG画像は、領域(viewBox)を自由に変更することができます。
今、領域の幅を少し短くしました。

領域を少し短くした状態で、円オブジェクトに対して先程と同じ「translateX(100%)」を指定したものがこちら⬆︎。
さっきよりも移動距離が短くなっていますが・・

translateの「%」は、viewBoxの大きさをもとに算出されるため、幅が変わったとしても「100%」はあくまで「viewBoxの端から端まで」を意味します。

ところで。
円が転がる時というのは、1回転したときにちょうど円周分の距離(直径*円周率)を移動しているはずです。

ではもしviewBoxの幅(←自由に指定できる)が円周長さと同じであれば、translateX(100%)で1回転分の距離を移動していることに。

そうすると「回転に見合った移動」の記述はとても単純なもので表せます。

transform:translateX(100%) rotate(1turn);

円周分の距離を進んだので、回転もちょうど1周させれば良いというわけです。

これで1回転と1回転分の移動が表現できました。
あとはこの比率を保ったまま、動かしたい距離に指定すれば回転と移動のバランスがとれます。例えば距離を半分にしたい場合は、

trasform:translateX(50%) rotate(0.5turn);

とすれば良いですね。

画像作成。


それでは画像を作成していきましょう。今回はイラレやVectornatorなどのCGソフトを使います。
コード編集が楽になるよう、⬇︎のようなアートボードと円オブジェクトの関係を作ります。

① アートボードの高さと幅の比率を「1:3.1416」に。

画像をSVGファイルに書き出したとき、アートボードの大きさがそのままviewBoxの大きさとして反映されます。高さを円の直径、幅を円周の長さにしましょう。
比率が合っていればサイズはご自由に(web表示の際はCSSでいくらでも調整できます)。

また円周率の精度ですが、解像度の大きい4Kデバイスでの表示まで考慮しました。
4Kの解像度は3840x2160です。「3.1416」と小数点以下4桁まで掘り下げておけば、px単位でのずれも発生しません。


② アートボード高さの直径で円を描き、中心を左端に。

web表示の際に余分な余白ができないよう、「円の直径 = アートボード高さ」とします。

円の中心を左端中央に揃えておくことで、transform-origin(変形の基準)の指定を「0% 50%」と、簡単な数値で行うことができます。



■ illustrator ■ Vectornator CGソフトのアートボードサイズを調整します。
Vectornatorでもイラレでも、新規イラスト立ち上げ時または作業中にアートボードの調整を行うことができます。先ほど述べた比率、「1:3.14146」に指定しましょう。

いまいち分からない。

アートボードのサイズ調整がいまいち分からない方は、SVG書き出し後にコードで指定することができます。それについては次のセクションでお伝えしますので、そのまま次の手順へと進んでください。

アートボードの高さと同じ直径の円オブジェクトを描き、中心を左端に合わせておきます。

ブラシなどで模様を付けました。

スイカの模様って、難しいですね💧 「ふ」は1度画像をiPadに落とし、タッチペンで描きました。
絵心の豊かな皆さんであれば、もっと上手に描けるはずです。

web上で転がす。


画像が完成したらSVG形式で書き出し、HTMLの<body> 〜 </body>内に流し込みましょう。

■ HTML

<body> 「「1<svg viewBox = ....>」」 <circle cx = .../> <path d = .../> <path d = .../> <path d = .../> ...... 「「1</svg>」」 </body>

※先ほど「アートボードの比率調整」を行わなかった場合は、コード上で行いましょう。
SVG開始タグのviewBox属性に注目。

<svg viewBox = "「「10 0 297 210」」" ....>

viewBox属性は、SVG画像の可視範囲を指定します。
例えば⬆︎のコードは「アートボード:A4サイズ」で書き出したものですが、はじめの2つの「 0 0 」はスタート地点の座標。そして3つ目の「297」がx(水平方向)の終点、4つ目の「210」がy(垂直方向)の終点を示します。

垂直/水平方向の終点比率を「1:3.1416」にしてやれば、問題は解決します。
但しここで、y(垂直方向)を変更すると、よろしくありません。画像作成時に「アートボード高さ = 円の直径」で描画していたため、このあと行うtransform-originの指定などに支障が発生してしまうからです。
x(水平方向)の終点座標を変更しましょう。

y方向固定のまま、比率を調整するには、

210*3.1416 = 「「1659.736... 」」

この計算結果をx方向に指定しましょう。

<svg viewBox = "0 0 「「1659.736」」 210" ....>

これでオッケーです。




現在の状態をwebで表示したもの⬆︎です。
アニメーションを施すための準備として、svgコードを少し修正します。

<svg 「「1class = "soto"」」 viewBox = ....> 「「5<g id = "suika">」」 <circle cx = .../> <path d = .../> <path d = .../> <path d = .../> ...... 「「5</g>」」 </svg>

CSSで参照するための処理です。
外側の<svg>にはclass名「soto」を付けておきます。また描画要素は全て<g> 〜 </g>で囲んでグループ化し、id名「suika」としました。

CSSで参照し、アニメーションをつけましょう。

■ CSS

#suika { transform-origin:「「10% 50%;」」 animation:suika 2s linear alternate infinite; }

svgのtransform-originはデフォルトがviewBoxの左上に位置しているので、#suikaの中心に指定し直します。
画像作成時にオブジェクトを左端中央に配置していたので、「0% 50%」という単純な数値で指定することができました。

@keyframes suika { bbto { transform:「「1translateX(100%) rotate(1turn)」」; } bb}

キーフレームです。
viewBoxがちょうど円周の幅になっているので、100%横移動したときに360°回転(1turn)させれば、回転と移動距離が一致します。

このとき、「translate」と「rotate」の記述順に注意してください。transformプロパティは、後に記述した値を先に記述した値が内包します

「rotate」を後ろにすることで「回転している状態を、移動させる」としましょう。順序を逆にすると「移動している状態を、回転させる」となり、転がりアニメーションになってくれません。




アニメーションの結果がこちら⬆︎。回転と移動が一致していますね ♬
ひとまづお疲れ様でした。

坂道発進。


ここまで作ってきた「直径と円周比率のviewBox」を使えば、いろんな転がりアニメーションを作ることができます。

画面の外から外へと転がしてみましょう。そのためには可視範囲(viewBox)からスイカがはみ出しても表示されるように、外側の<svg>を呼び出します。さっきclass名「soto」を付けておいたのはこのためです。

.soto { 「「1overflow:visible;」」 } #suika { transform-origin:0% 50%; animation:suika 2s linear alternate infinite; } @keyframes suika { bbfrom { 「「1transform:translate(-50%) rotate(-0.5turn);」」 } bbto { 「「1transform:translate(150%) rotate(1.5turn);」」 } bb}




親要素に「overflow:visible」を指定することにより、子要素がはみ出しても表示されるように成増。
移動距離も画面の外から外へと広げましたが、それに合わせて回転も増やしました。

さらに親要素「.soto」の角度や大きさも変えてみます。

.soto { overflow:visible; 「「1transform-origin:center; tranform:rotate(-15deg); width:60%;」」 }




坂道バージョンもできました。

このように「直径:円周」のviewBoxセットを1度作っておけば、さまざまな転がりアニメーションを作り出すことができます。svg領域に複数配置したり、もっと細かなキーフレームにしてみても面白いですね。

最後までお読みくださり、ありがとうございました。
皆さんも楽しい転がりアニメーションを作ってみてください。


ではまた〜 ♪



SVGアニメーション、 回転の中心を指定する。

2021.03.09
座標を取得して%変換。



HTMLで画像を重ねる、便利な方法。

2021.01.20
positionやz-index指定なし。



ページめくりアニメーション 作り方。

2021.02.02
画像を読み込むだけで実装。












「ふ」です。

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