SVGアニメーション、
ランダムにキラキラ。

〽️「キラ」が1つあるSVG。 〽️外側のSVGに配置。 〽️ランダムに発生させる。 〽️分布や大きさを工夫しよう。





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

こんにちは、「ふ」です。
ヘッダにあるように、「ランダムに発生するキラキラ」をSVGアニメーションで作っていきましょう。
今回は、「SVG in SVG」でいきたいと思います。



はぁ?

■ inner.svg

内側のSVG画像はこのようなもの。
1つの「キラ」がアニメーションしています。

■ outer.svg

外側のSVGも準備します。
みなさんはキラキラさせたい要素をこの中に配置してください。

JavaScriptを使い、内側のSVG画像を複製。時間差で外側のSVG領域にどんどん追加していきます。
このとき、乱数を使って位置や大きさを毎回変化させます。

尚、追加したままでは外側のSVG領域内に「キラ」が無限増殖してしまいます。
アニメーションの終了イベントを検知したら、その要素は削除するようにしましょう。

〜複雑そうですが、意外と短いコードで実装することができます。
いっしょに作っていきましょう🎵

「キラ」が1つあるSVG。


先づは内側のSVGからです。
アニメーションさせる「キラ」を1つ埋め込みましょう。

ベクターソフトで、正方形を描きます。

その上に円を4つ重ねてグループ化(最初の正方形はグループに入れないでください)。

パスファインダーで切り抜き。
色や線をお好みで指定して、「キラ」が完成です。

ベクターソフトを使えば「秒」で作れますね。これをSVG形式で書き出しましょう。

■ HTML

<body> <svg 「「1id = "inner" 」」viewBox="0 0 841.9 595.3"> <style type="text/css">  〜略〜 </style> <path 「「1id = "kira" 」」class="st3" d="M225.2,298c49.1,7.3,94.5,30,130.3,65.8c35.8,35.8,58.5,81.1,65.8,130.3c7.3-49.1,30-94.5,65.8-130.3 c35.8-35.8,81.1-58.5,130.3-65.8c-49.1-7.3-94.5-30-130.3-65.8s-58.5-81.1-65.8-130.3c-7.3,49.1-30,94.5-65.8,130.3 S274.4,290.7,225.2,298z"/> </svg> </body>

書き出したコードをHTMLの <body> 〜 </body>内にインラインで貼り付けます。
id名をつけておきます。
SVGタグには「inner」、「キラ」のオブジェクトには「kira」としました。

「キラ」をアニメーションさせましょう。
0%から50%にかけて徐々に大きくなり、不透明度も上げていきます。50%以降は縮小・不透明度も下げていきます。
背景が明るい場合には「キラ」が目立たなくなるため、枠線もアニメーションさせました。これについてはお好みで構いません。

■ CSS

#kira { transform-origin:center; animation:kira 1.7s linear 「「3infinite」」; stroke-width:0; } @keyframes kira { from { transform:scale(0); opacity:0; stroke-width:30; } 50% { transform:scale(1); opacity:0.8; stroke-width:14; } to { transform:scale(0); opacity:0; } }

「キラ」のアニメーションができました。
現在は見やすいようにアニメーションの繰り返しは「infinite(無限)」にしています。

外側のSVGに配置。


外側のSVGを準備します。ここでは、<body> 〜 </body> 内にSVG領域を設けて画像を挿入してもいいですし、好きなSVG画像のコードを直接流し込んでもかまいません。

■ outer.svg

「ふ」は最初に紹介した「outer.svg」のコードを流しこむことにしました。

■ HTML

<svg 「「1id = "outer" 」」viewBox="0 0 841.9 595.3">  〜略〜 </svg>

参照できるようにid「outer」としています。


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

positionやz-index指定なし。



SVGに画像をぴったりと配置〜
preserveAspectRatio。

縦横比が違っても安心。


SVG領域に画像を配置する方法やサイズ調整については、これら⬆︎の記事にて詳しく紹介しています。

次に先ほど作成したinnerのコードを、outerのSVGタグ内に流し込んでしまいます。
SVGでは、自身の中に別のSVG領域を設けることが可能なんです。

■ HTML

<svg id = "outer" viewBox="0 0 841.9 595.3">  〜略〜 「「1<svg id = "inner" viewBox="0 0 841.9 595.3">」」  「「3〜略〜」」 「「1</svg> 」」 </svg>

現在のブラウザ表示です。outerのSVG領域内にinnerも追加されました。



・ 注意
illustratorでSVG画像を作成した場合、inner/outerの各要素のクラス名が重複してしまい、その結果CSSが汚染し合う可能性があります。
コードエディタでclass名が被らないように調整が必要です。

今innerのSVGはouterの領域に対して、座標でいうところの(0,0)に位置しています。
いずれ複製してランダムに配置したいのですが、この1つ目の「キラ」は定位置になってしまいます。常に表示されているとあまりよろしくないため、outer領域の外に逃がしてしまいましょう。

「逃す範囲」に関して。
このSVGアニメーション、端のほうに配置された「キラ」が切れてしまわないように、overflowを「visible」にしたい方もいるかと思います。
そうしたときにも表示されてしまわないよう、思い切ってHTML領域の外側まで飛ばしてしまいます。xを「-300%」にしました。

■ HTML

<svg id = "outer" viewBox="0 0 841.9 595.3">  「「3〜略〜」」 「「1<!-- innerをHTML領域の外側に飛ばす -->」」 <svg id = "inner" 「「1x = "-300%"」」 viewBox="0 0 841.9 595.3" >  「「3〜略〜」」 </svg> </svg>

さらに「キラ」のアニメーション指定で、繰り返しは1回だけに直しましょう。←これを忘れると無限増殖します。
animation-iteration-countの初期値は「1」なので、最初に記述していた「infinite」を削除するだけで大丈夫です。

■ CSS

「「4/* 「infinite」を削除。*/」」 #kira { transform-origin:center; 「「4animation:kira 1.7s linear         ;」」 stroke-width:0; }

innerは高飛びさせたので見えなくなりました。
これでHTMLの記述は完了です。

ランダムに発生させる。


それではJavaScriptを使ってinnerを複製し、outerの領域内にランダムに発生させます。

■ JavaScript

「「1//① innerとouterを取得」」 const outer = document.getElementById("outer"); const inner = document.getElementById("inner"); 「「5//A 一連の処理を関数化」」 function random() { 「「1//② innerを複製」」 let clone = inner.cloneNode(true); 「「1//③ アニメーション終了後に削除」」 clone.addEventListener("animationend",function() { bbclone.remove(); }); 「「1//④ 位置と大きさをランダムに」」 let horizon = String(Math.random()*100) + "%"; let vertical = String(Math.random()*100) + "%"; let ookisa = String(Math.random()*50) + "%"; clone.setAttribute("x",horizon); clone.setAttribute("y",vertical); clone.setAttribute("width",ookisa); clone.setAttribute("height",ookisa); 「「1//⑤ outerに追加」」 outer.appendChild(clone); } 「「5//B 一定時間おきに実行」」 setInterval(random,280);


① innerとouterの要素を取得。

② cloneNodeメソッドでinnerを複製します。
このときの引数は、「子要素も含めて複製するか」の真偽値を指定します。もちろん内部の「kira」も一緒に複製するため、「true」としておいてください。

③ アニメーション終了後に要素を削除。
最後にsetIntervalで一定時間おきにouterに追加していくのですが、そのままでは無限に「キラ」が増殖してしまいます。
animationendイベントを利用し、終了時に要素を削除するイベントハンドラを仕込みましょう。

④ 位置と大きさをランダムに。
JavaScriptのMath.randomメソッドは、0〜1の乱数を返します。これをその時々のinnerのxy座標及びwidth採用します。
0〜1の返り値を0〜100%に振り分けたいので、100倍にしてから文字列化し、setAttributeで属性に指定します。

大きさに関しては、width/height属性の両方に変数「ookisa」の返り値を指定します。元の「キラ」ではデカ過ぎるので、MAXで50%の大きさとしました。

⑤ outerに追加
appendChildで、複製したinnerをouterに追加しています。

A 一連の処理を関数化
複製→加工→追加までの処理を関数「random( ) 」としてまとめます。

B 一定時間おきに実行
setIntervalで、関数random( )を一定時間おきに実行させます。「ふ」は0.28秒としたのですが、間隔はお好みで調整してください。



ここまでの結果⬆︎です。
しばらく眺めているとわかるのですが、「キラ」の分布が全体的にouterのやや右下に分布してしまっています💧これはどういうことなのでしょうか?

いったんアニメーションは置いといて、静止した状態で考えてみましょう。
innerの大きさは0〜50%の範囲でランダム変化させています。中間値の「25%」としたとき。

SVGのx、y属性は、左上が基準と成増。
xyともに「0%」のときと、「100%」のときのinnerの配置はこの⬆︎ように。

つまりinnerの分布が、outer領域に対して右下に25%ずれてしまっている、ということです。
Math.randomの返り値を、半分の12.5%ずつ左上にずらしましょう。

■ JavaScript

let horizon = String(Math.random()*100「「1-12.5」」) + "%"; let vertical = String(Math.random()*100「「1-12.5」」) + "%"; let ookisa = String(Math.random()*50) + "%";

これで結果をみてみます。

均一に分布するようになりました。
これで完成です。お疲れ様でした!

分布や大きさを工夫しよう。


最後までお読みくださり、ありがとうございました。
今回はSVGの中にSVGをランダムに発生させる、というのをやってみました。うまくできましたでしょうか?

ちなみにMath.randomで返される値をいじると、なかなか楽しい効果が得られます。
例えば、「キラ」をある程度以上の大きさにまとめたい場合。

■ JavaScript

let ookisa = String(Math.random()*「「120+30」」) + "%";



この⬆︎ように、innerの大きさが20〜50%の範囲で振り分けられます。
他にも「中央よりに分布させたい」など挑戦してみると楽しいかとおもいます。


また「キラキラ」以外にもこのランダム発生は使えそうですね。いろんな要素で試してみてください。
ではまた〜 🎵🎵🎵



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

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


SVG アニメーション、カメラのシャッターを再現。

2021.04.11
「アニメーションごと」重ねていく。


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

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












「ふ」です。

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