こんにちは、「ふ」です。
今回はSVGを使い、webページの画面に桜の花びらを散りばめるアニメーションを作っていきたいと思います。
仕組みはお決まりのランダム発生です。「回転しながら横移動する、花びらアニメーション」をSVG領域にランダムに発生させるというもの。
今回ランダムにするパラメータは、花びらの大きさ(width属性)とSVGに追加する際の位置(Y属性)です。
春を思わせるようなサイトの演出に利用してください。
では作成していきます。
はじめに最小単位である、「回転する花びら」を作りましょう。
Vectornatorやイラレを使い、画像を作成。
この花びらには、回転アニメーションを施します。
したがって回転時にオブジェクトがはみ出さないよう、アートボードの大きさを調整しておきましょう。
あとからCSSで「overflow:visible」としてもいいのですが、画像作成の段階で調整しておくに越したことはありません。
SVGファイルとして書き出し、HTMLの<body> 〜 </body>内にインラインで流し込みます。
<svg viewBox="0 0 128.7 130.2"> <style type="text/css"> .st0 {fill:url(#SVGID_1_);} </style> <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="63.9972" y1="122.1978" x2="63.9972" y2="7.1978"> <stop offset="0" style="stop-color:#FFFFFF"/> <stop offset="1" style="stop-color:#FF9EC8"/> </linearGradient> <path class="st0 「「1hitohana」」" d="M103.9,57.9c0,30.6-39.9,64.3-39.9,64.3S24.1,88.5,24.1,57.9S64,7.2,64,7.2S103.9,27.3,103.9,57.9z"/> </svg>
流し込んだSVGのコードです(このままコピペで使えます)。
花びらオブジェクトにはCSSで呼び出せるようclass名「hitohana」をつけておきました。
.hitohana { 「「3/* 回転の基準をオブジェクトの中央に */」」 transform-box:fill-box; transform-origin:center; animation:hitohana 2s linear infinite; } @keyframes hitohana { to { transform:rotateZ(1turn) rotateY(0.5turn); } }
花びらオブジェクトに対して、CSSアニメーションを指定します。
・transform-box、transform-originで基準点を中央に指定。
・キーフレーム。Y軸を中心に半回転しつつ、Z軸中心に1回転させる、というものにしました。
結果⬆︎です。
最小単位の花びらオブジェクトはこれで完成。
transform基準点の取り方、グラデーションについては⬇︎の記事で詳しく紹介しています。
SVG、要素を基準にtransform。
2021.12.18
これまでの苦労は何?(笑)。
SVGのグラデーションについて。
2021.10.23
カラーストップ/オフセットとは?
<svg viewBox = viewBox="0 0 841.9 595.3"> </svg>
HTML上に別のSVG領域を作り、作成した花びらアニメーションを取り込みます。
〜のですが、今回は花びらオブジェクトの大きさをランダムに変化させるのでした。それにはsetAttributeを使ってwidth属性を操作するのが便利です。それにあたり、
<path class="st0 「「1hitohana」」" d="...."/>
もし花びらのpath要素のみを取り込んだ場合。
これでも表示・アニメーションは可能です。しかしpath要素自体はwidthやheight属性を持っていないので、大きさを容易に変化させることができません。
<svg viewBox="0 0 128.7 130.2"> <path class="st0 hitohana" d="...."/> </svg>
したがってwidth属性が使える<svg>要素ごと、外側のSVG領域に挿入するようにしましょう。
<svg viewBox="0 0 841.9 595.3"> <g 「「1id = "kaze"」」> bb<svg viewBox="0 0 128.7 130.2" 「「1width = "20%"」」> bb<path class="st0 hitohana" d="...."/> bb</svg> </g> </svg>
挿入するにあたり、外側のSVG内にグループ要素「#kaze」を用意し、その中に花びらSVGを記述します。外側SVGの領域内で、花びらSVGを横移動させるためのグループ要素です。
また試しに花びらSVGのwidthを「20%」にしてみました。
現在の状態⬆︎です。
<svg>要素ごと挿入しているため、width属性を使って大きさのコントロールを簡単に行うことができます。
そして先ほど付与したid「kaze」で内側のSVGを呼び出し、回転花びらを風に乗せましょう。
#kaze { animation:kaze 4s linear infinite; } @keyframes kaze { from { transform:translate(「「1-20%,-20%」」); } to { transform:translate(「「1100%,20%」」); } }
「風に乗りながら散っていく」ように、真横ではなくY方向に+-20%、上下させました。
花びらSVGのwidthは「20%」にしているため、ちょうど画面の外から外へ移動するよう、translateXの値を指定します。
風に乗って散っていく花びらができました。
次はこれをランダムに発生させます。
ここからはJavaScriptを使い、ランダム発生を実装していきます。
今回ランダムにさせたいものは、
・Y方向の位置
・花びらオブジェクトの大きさ
の2つです。
これらは花びらSVGのY属性、width属性に対して指定します。
「風に流される回転花びら」を、外側のSVG領域にまんべんなく出現させたい。そのためのY属性を、+-80%の範囲のランダム値に指定します。数値を-80から+80に振り分けるには、
Math.random( )*160-80
ですね。
また花びらSVGのwidthですが、キーフレーム開始時のtransformXの値は「-20%」です。
widthが20%より大きいと、「画面の外から外へ移動するアニメーション」にはなりません。
ということはMAX値が20%。
加えて、あまり小さくなりすぎてもどうか....最小でも5%くらいにしたい。
なので、5%〜20%の範囲としました。振り分けは、
Math.random()*15+5
ということに成増。
JavaScriptを書いていく前に、下準備が2つほどあります。
#kaze { 「「3/* infiniteを外しておく */」」 animation:kaze 4s linear; }
花びらSVGの親である「#kaze」に施していた横移動のアニメーションですが、先ほどはプレビューしやすいように繰り返しを「infinite」にしていました。
このままランダム発生させると無限増殖してしまうので、「infinite」の指定を外すことで再生回数を初期値の「1」にしておきます。
<g id = "kaze"> <svg viewBox="0 0 128.7 130.2" width = "20%" 「「1y = "-100%"」」> ....
オリジナルの花びらSVGはアニメーション終了後、規定の位置に静止したまま表示されてしまいます。
仕方がないのでy属性を「-100%」とし、viewBoxの外側に逃しておきましょう。これで表示されなくなります。
それではJavaScriptを書いていきましょう。
「「3//#kazeを取得」」「「1 ..①」」 const kaze = document.getElementById("kaze"); 「「3//複製・追加関数」」「「1 ..②」」 function hukusei() { 「「3//#kazeを複製」」「「1 ..③」」 let clone = kaze.cloneNode(true); 「「3//アニメーション終了後に削除」」「「1 ..④」」 clone.addEventListener("animationend",function() { bbclone.remove(); }); 「「3//cloneの中の花びらSVGを取得」」「「1 ..⑤」」 let hanabira = clone.children[0]; 「「3//大きさをランダムに」」「「1 ..⑥」」 hanabira.setAttribute("width",`${Math.random()*10+5}%`); 「「3//Y座標をランダムに」」「「1 ..⑦」」 hanabira.setAttribute("y",`${Math.random()*160-80}%`); 「「3//外側SVGに追加」」「「1 ..⑧」」 kaze.parentNode.appendChild(clone); } 「「3//0.5秒ごとに発生させる」」「「1 ..⑨」」 setInterval(hukusei,500);
① 花びらSVGの親要素である「#kaze」を取得。
② #kazeを複製し、外側SVGに追加する関数「hukusei」を定義します。
③ cloneNode( )メソッドで、#kazeを複製。
④ 複製したものが無限増殖しないよう、アニメーション終了後は自身を削除するようにイベントリスナを仕掛けておきます。
⑤ 花びらSVGは#kazeの直下の子要素でした。children[0]で取得します。
⑥⑦ さっき計画した通り、setAttributeで、花びらSVGのwidthとy属性をランダムにします。
⑧ ここまで加工したものを外側SVGに追加。
外側SVGは#kazeの親要素なので、parentNodeで参照しています。
⑨ setIntervalで500msごとに定義した関数を実行。
できました!
お好みの「散りばめ具合」になるよう、パラメータを色々と調整してみてください。
最後までお読みくださり、ありがとうございます。
今回は春用のランダムアニメーション、桜の花びらを作ってみました。うまく出来ましたでしょうか?
記事内では決められたSVG領域内に花びらを発生させましたが、もし「画面全体に散りばめたい」場合にはこちら⬇︎、ランダム冬バージョンを参考にしてください。
SVG、画面全体に雪を降らせるアニメーション。
2021.11.25
これからの季節に必要(笑)。
記事執筆時。
世界情勢はまだまだ不安定です。
なんの変哲もない、ごく普通の平和な「春」が、世界中の人たちの元に訪れるように。「ふ」は願っています。
誰もがグラフィックやコーディング、好きなことを楽しめる日常がまた戻ってくるはず!早く来いよな!
ではまた〜 ♪
JavaScriptのドルマーク$に中括弧{ }、テンプレートリテラルについて。
2022.02.09
クオテーション祭り、さようなら。
JavaScript、乱数の範囲や重複を指定〜Math.random使い方。
2021.11.17
整数/範囲/重複の有無を自在にあやつろう。
SVGでWeb Animations API。
2020.11.12
〽️ ネイティブJavaScriptでのアニメーション。
swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。