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

〽️ モーフィング ✖️ モーションパスの合わせ技。




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



角度も付けてゆらゆら。


こんにちは、「ふ」です。
SVGで複数のオブジェクトを、波状に「ゆらゆら」させたい。

これ、オブジェクトを直立させたままでよければ簡単です。
transformでY方向に上下させ、animation-delayで各要素のアニメーションに時間差を設ければよいことです。

しかし、波の各地点の向きに合わせて角度を付けながら、「ゆらゆら」させたい。

これは少しばかり工夫が必要です。今回は、角度を付けながら複数のオブジェクトをゆらゆらさせる、SVGアニメーションについて紹介します。

モーションパス+モーフィング。



SVGのモーションパスという機能。
これは、指定したパスに沿ってオブジェクトを動かしていくものです。そしてパスの向きに応じて角度を付けることもできます。

モーションパスは通常「動きつづける」ものなのですが、キーフレーム内容を調整することで「1箇所に静止」させることもできます。しかも角度を付けたままで。

というわけで。
モーションパスを使った上で、各オブジェクトをパス上に静止させておきます。

そして、基準となっているパスをモーフィング(パスデータを変化)させます。
モーフィングに合わせてそれぞれのオブジェクトは角度を変化させながら、「波状にゆらゆら」します。

画像を準備。


イラレやVectornatorを使って、画像を準備していきましょう。

はじめに、モーションパスの対象となるパスを描いていきます。

このパスはモーフィングさせるため、変化前/変化後の2種類を用意。
パスデータのコマンド内容が一致していないとうまくモーフィングしてくれません。2つのパスはアンカーポイントの数や種類(コーナーポイントorスムーズポイント)を同一のものにしておいてください。
またペンツールで滑らかな曲線を描きたい場合は、⬆︎の点線で示しているように補助用の長方形を配置しておくとうまくいきます。

次に動かしたいオブジェクトを準備。
ただし、位置の調整が必要です。

モーションパスでは、アートボード(=viewBox)の原点がパスに沿って動きます。
オブジェクトの中心をパスに沿わせたいのであれば、アートボードの原点(左上)とポイントを一致させておく必要があります。
バウンディングボックスを表示させながら、すべてのオブジェクトの中心を原点に持っていきましょう。

これで画像の準備はできました。
SVG画像として書き出し、コーディングしていきましょう。

パス上に静止させる。


<svg viewBox = "0 0 841.9 595.3"> <style> 〜略〜 </style> 「「3<!-- モーションパスの基準となるパス -->」」 <path 「「5id = "sen"」」 d = ..../> <path d = ..../> 「「3<!-- 動かすオブジェクト -->」」 <path d = ..../> <path d = ..../> <path d = ..../> <path d = ..../> <path d = ..../> <path d = ..../> </svg>

作成した画像をSVGで書き出したものです(CSSや細かいパスデータは省略しています)。
今回のアニメーション実装において、参照先としたいのはモーションパスの基準として用意した、2種類のパスのうちの1つだけです。
1つ目のパスにid名「sen」を指定しておきました。

動かしたいオブジェクトをパス上に静止させていきます。
今回「o」「b」「j」「e」「c」「t」の6個用意しましたが、ひとまづ「o」のオブジェクト1つで試してみます。

「「3<!-- 「o」のオブジェクト -->」」 「「3<!-- 開始タグと閉じタグに分割 -->」」「「1 ..@1@」」 <path d = "...."> bb「「3<!-- アニメーションの時間指定 -->」」「「1 ..@2@」」 bb<animateMotion bbdur = "4s" bbrepeatCount = "indefinite" bbrotate = "auto"> bbbb「「3<!-- 基準とするパスを指定 -->」」「「1 ..@3@」」 bbbb<mpath href = "「「5#sen」」"/> bb</animateMotion> </path>


@1@ モーションパスを実装するには、path要素の中に<animateMotion>タグを挿入し、さらにその中に<mpath>タグを記述する必要があります。
そのため <path ../> と、開始タグと終了タグが1つにまとめてられているものから、<path> 〜 </path>というように。開始タグと終了タグを分離しておきましょう。

@2@ アニメーションのタイミングに関する指定を行います。

dur(1回再生あたりの時間):4s
repeatCount(繰り返し回数):indefinite(無制限)
rotate(角度をつけるか):auto(パスの傾きに合わせる)

@3@ モーションパスの基準を指定
<mpath>タグで、先ほどid名「sen」を付けておいたパスをモーションパスの基準に指定します。

現在の状態です。
オブジェクトはパスに沿って動き続けていますが、キーフレームを操作して1箇所に静止させましょう。

<animateMotion dur = "4s" repeatCount = "indefinite" rotate = "auto" 「「3<!-- タイミング曲線 -->」」「「1 ..@4@」」 calcMode = "linear" 「「3<!-- キーフレームとなるタイミング -->」」「「1 ..@5@」」 keyTimes = "0;1"> 「「3<!-- キーフレームの値 -->」」「「1 ..@6@」」 keyPoints = "0;0" bb<mpath href = "#sen1"/> </animateMotion>

<animateMotion>タグに、3つの属性を追加します。

@4@ calcMode属性は、アニメーションの進捗具合を指定します。
値を「linear(直線的に)」と明記しないと、以降のキーフレーム指定が機能しません。この属性指定自体には意味がないのですが、SVGコード内でキーフレームを指定したい場合には記述が必須となっています。

@5@ keytimes。0〜1の範囲でキーフレームとなるタイミングをセミコロン「;」で区切って指定します。
ここは「 0 ; 1 」。CSSアニメーションでいうところの「0%から100%」にしておきましょう。

@6@ @5@で指定したキーフレームの場所に対応する値をkeyPoints属性で記述。
基準となるパスの始点を0、終点を1として、オブジェクトの位置を指定します。これを「 0 ; 0 」としました。
@5@@6@で指定した内容は、

・進捗0%:0(パスの始点)
・進捗100%:0(パスの始点)

アニメーションのはじめから終わりまでパスの始点に位置している→つまり「角度を付けて、パスの始点に静止している」状態となります。

同じ要領でkeyPointsの値のみ変化を付けて、他のオブジェクトをパス上に配置していきましょう。

パス上に「角度を付けてオブジェクトを静止」させることができました。

元のパスをモーフィング。


それでは仕上げです。
モーションパスの基準となっているパスをアニメーションさせましょう。

「「3<!-- モーションパスの基準となるパス -->」」 <path 「「5id="sen"」」 d="M109.5,297.6c0,0,149.7,180.4,310.2,0s311.2,0,311.2,0"/> 「「3<!-- もう1つのパス -->」」 <path d="M109.5,297.6c0,0,150.4-173,309.5,0s310.5,0,310.5,0"/>

現在基準のパスは「#sen」のほうです。画像作成時はもう1つパスを作っていました。
「#sen」のパスデータからもう1つのパスデータへと往復させる、モーフィングアニメーションを実装します。

「「3<!-- 開始タグと閉じタグに分割 -->」」「「1 ..@1@」」 <path id="sen" d="「「1M109.5,297.6c0,0,149.7,180.4,310.2,0s311.2,0,311.2,0」」"> 「「3<!-- パスデータを変化させる -->」」「「1 ..@2@」」 <animate attributeName = "d" dur = "4s" repeatCount = "indefinite" values = "「「1M109.5,297.6c0,0,149.7,180.4,310.2,0s311.2,0,311.2,0」」; 「「4M109.5,297.6c0,0,150.4-173,309.5,0s310.5,0,310.5,0」」; 「「1M109.5,297.6c0,0,149.7,180.4,310.2,0s311.2,0,311.2,0」」" /> </path> 「「3<!-- もう1つのパス -->」」 <path d="「「4M109.5,297.6c0,0,150.4-173,309.5,0s310.5,0,310.5,0」」"/>


@1@ 今度は<path>タグの中に<animate>タグを挿入します。
モーションパスのときと同じように、<path/>となっているものを開始タグと閉じタグに分割しておきましょう。

@2@ アニメーションの内容を記述します。

attributeName(変化させる属性):d(パスデータ)
dur(1回再生あたりの時間):4s
repeatCount(繰り返し回数):indefinite(無制限)

valuesには、変化の内容を「 ; 」で区切って記述します。
「基準のパスデータ」→「もう1つのパスデータ」→「基準のパスデータ」と、1度変化して元の状態に戻るようにします。

パスの変化に合わせて、オブジェクトが角度を付けながら「ゆらゆら」していますね。
あとは基準となるパスを非表示にしましょう。

#sen { opacity:0; }

「もう1つのパス」はコメントアウトでOKです。
基準となるパスである「#sen」は削除するわけにはいかないので、CSSで不透明度を「0」にしました。

これで完成です。お疲れ様でした!

safari対策。


ここで1つ、注意点をお伝えします。

今回のSVGコードの内容は「モーフィング」の部分と「モーションパス」の部分に分かれています。
アニメーションを試行中に発覚したのですが、safariでは「モーフィング」の内容を先に記述しないと、うまく動いてくれませんでした。
Chromeやedgeでは順序を問わずに動いたのですが..

う〜ん。
safari君の機嫌をそこねないために、コードの記述順には配慮しておきましょう。

<svg viewBox = "0 0 841.9 595.3"> <style> 〜略〜 </style> 「「3<!-- モーフィングの内容 「「4*先に記述」」-->」」 <path id = "sen" d = ....> <animate ...> </path> 「「3<!-- モーションパスの内容 -->」」 <path d = ....> <animateMotion...> </path> .... </svg>

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

SVGアニメーションを実装するにおいて、いつも悩まされるのはsafari対応💧 
しかしおかげさまで、最近では当サイトの内容を実際のweb制作に利用しているとの声もいただき、とてもありがたく感謝しています。
safariに負けず(笑)これからも役に立つコンテンツ作りに励んでいきますので、よろしくです。

ではまた〜 ♩





SVGをcreateElementするには「NS」が必要。

2022.04.13
名前空間とは?なぜ必要なのか?


JavaScriptのドルマーク$に中括弧{ }、テンプレートリテラルについて。

2022.02.09
クオテーション祭り、さようなら。











「ふ」です。

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