SVGアニメーション、
複数のボタンを一括制御。

〽️画像とstyleの整備。 〽️基本Js。 〽️on/offを配列で管理。 〽️押されたボタンを判別。 〽️ボタンの基本色を取得。 〽️アニメ〜ション。 〽️苦労した甲斐あり。





⬆︎SVGついてのまとめページはこちら。

こんにちは、「ふ」です。
前回はWeb Animations APIを使ったボタンアニメーションの実装に挑戦しました。その中で、将来的に「複数のボタンを制御するための準備」もいくつか仕込んでいましたね。

いよいよ今回は最終目標、複数ボタンアニメーションの一括制御を実装していきたいと思います。



SVGでボタンアニメーション【Web Animations API】。

2020.12.19
event.targetからオブジェクトを動かす。

当記事は前回の続編となっていますので、まだお読みでない方はこちら⬆︎からどうぞ。

アニメーションの内容については前回と同様、「一瞬大きくなって枠とテキストの色を反転させる」ものとします。

複数ボタンの制御にあたり、追加すべき実装は次のとおり。

・ それぞれのon/off状態が判別できるように、フラグを配列化して管理する。

・クリック時、どのボタンが押されたのかを判別。

・ event.targetからボタンの基本色を獲得 → keyframeの値に使用。



〜やることが結構ありますね。
1つ1つ確認しながら、進めていきましょう。

画像とstyleの整備。


枠と中身のテキストで構成されたボタンを3つ準備しました。
SVGで書き出し、HTMLの <body> 〜 </body> 内にインラインで貼り付けます。

◼︎ HTML

「「5 - ①」」 「「4 - ③」」 「「1 - ②」」 「「3//ボタン枠」」「「2 - ④」」 <path class="st0"「「4 - ③」」   d="・・"/> 「「3//中身のテキスト」」 「「1 - ②」」 <path class="st1"「「4 - ③」」   d="・・"/> <path class="st1"「「4 - ③」」   d="・・"/> <path class="st1"「「4 - ③」」   d="・・"/> 「「1 - ②」」 「「1 - ②」」

ボタン1枚分をそのまま貼り付けたのがこちらです。
前回と同じく、SVGコードを整備しましょう。

① 全てのボタンに同じclass名をつけます。「btn」でいきます。

② イラスト作成過程において、各所でオブジェクトがグループ化されてしまっています。
これを解除し、全てのオブジェクトを< svg >直下の子要素にしましょう。

③ 複数の書き出しファイルをインラインで埋め込むと、重複するclassやid名に指定されたstyleが互いに汚染し合います。
各オブジェクトのclass名を改めて付けなおし、cssをhead内に移動させましょう。

④ ボタン枠のオブジェクトを1つ目の子要素に配置しておきます。親要素の「children[ 0 ]」で呼び出せるようにするためです。

◼︎ HTML

<svg class = 「「5"btn" 」」viewBox="0 0 315.7 153.2"> 「「3//ボタン枠」」 <path class="st0" class = 「「4 "waku1"」」  d="・・"/> 「「3//中身のテキスト」」 <path class="st1" class = 「「4"text1"」」  d="・・"/> <path class="st1" class = 「「4"text1"」」  d="・・"/> <path class="st1" class = 「「4"text1"」」  d="・・"/> </svg>

◼︎ <head>内CSS

「「5.btn」」 { width:50%; display:block; margin:0 auto; 「「1transform-origin:center;」」 } 「「3//赤btnの子要素」」 「「4.waku1」」 {・・・・} 「「4.text1」」 {・・・・} 「「3//青btnの子要素」」 「「4.waku2」」 {・・・・} 「「4.text2」」 {・・・・} 「「3//緑btnの子要素」」 「「4.waku3」」 {・・・・} 「「4.text3」」 {・・・・}

親要素である「btn」には、transform-originで変形の基準を中心に指定します。その他のプロパティについては配置に関するものなので、お好みでどうぞ。

下に続く「waku1〜3」「text1〜3」は、赤 青 緑 ボタンのそれぞれの子要素にそれぞれclass名をつけて参照させています。
内容については、SVGで書き出された時のものをそのまま移植しています。

基本Js。


前回の内容をもとに、骨組みとなるJavaScriptを書いていきます。

◼︎ JavaScript

「「3// ①btnクラスの要素を取得」」 consr btn = document.getElementByClassName("btn"); 「「3// ②全てのオブジェクトにonclick属性を付与」」 for(i=0; i<btn.length; i++) { for(j=0; j<btn[i].childElementCount; j++) { btn[i].children[j].setAttribute("onclick","onoff()"); } } 「「3//③ アニメーションのtiming。」」 let timing = { duration:290, iterations:1, fill:"forwards" }; 「「3//④ btn全体のkeyframe。」」 let sizeChange = [ bb{transform:"scale(1)"}, bb{transform:"scale(1.1)"}, bb{transform:"scale(1)"}, ]; 「「3// ⑤呼び出される関数」」 function onoff() { }

① getElementByClassName( )で、「btn」クラスの要素を取得。HTMLCollectionという、要素の集合が返されます。

② 2重のfor文を用いて、全てのオブジェクト(子要素)にonclick属性を指定。

③ アニメーションのタイミングプロパティ。時間的変化を指定するものなので、全てのアニメーション共通で使い回します。

④ btn全体のkeyframe。一瞬大きくなってすぐに元に戻るもの。
targetの親である<svg>要素に共通で施します。

⑤ onclickで呼び出される関数、「onoff( )」です。現在はまだ内容は記述していません。

on/offを配列で管理。


個々のボタンが現在onなのかoffなのか、今回は1つの変数では管理できません。
空の配列を作成し、そこにボタンの数だけフラグを入れましょう。

「「3//⑥ フラグ用の配列を作成」」 let flag = []; 「「3//⑦ ボタンの数だけ"0"を追加」」 for(i=0; i<btn.length; i++) { flag.push("0"); }

⑥ いったん空の配列「flag」を作成。

⑦ offの状態を「0」、onの状態を「1」として管理します。
初期状態では全てのボタンがoffなので、for文で「0」をpushしました。



console.log(flag);  「「1▶︎ {"0","0","0"}」」

試しに出力してみます。
ボタンは3つあるので、"0"が3つ入りました。

押されたボタンを判別。


ボタンが押されたときに作成したフラグ配列の内容を書き換えます。そのためには、event.targetの親要素を取得し、それが「btn」クラスの何番目の要素かを確かめる必要があります。

配列のindexを調べる場合にはindexOfメソッドを使用するのですが、先ほどgetElements〜で返されたのはHTMLCollectionです。
HTMLCollectionは配列に似た性質を持ったものではあるのですが、indexOfメソッドは使えません。

先づはHTMLCollectionから配列「hairetu」を作りましょう。

「「3//⑧ 取得したclass要素から配列を生成」」 const hairetu = Array.from(btn);

⑧ Array.from( )を使い配列ができました。

クリック時に呼び出されるonoff関数内で、何番目の要素がクリックされたかを判別させます。



「「3// ⑤呼び出される関数」」 function onoff() { 「「3//Ⓐ targetの親を取得」」 let oya = event.target.parentElement; 「「3//Ⓑ 何番目のbtnが押されたか判別」」 let index = hairetu.indexOf(oya); }

呼び出される関数、「onoff」内での処理。

Ⓐ targetを施しているのは子要素のオブジェクト群なので、一旦親要素「btn」を呼び出します。

Ⓑ indexOfメソッドで、何番目の「btn」が対象になっているか判別。

indexOfを使うと、「0」「1」「2」などの添字が返ってきます。
この添字を使うことで、「flag」配列の要素と照合させることができます。

ボタンの基本色を取得。


前回は単一のボタンだったので、色指定には具体的なhex値を記述していました。
しかし今回は複数のボタン。それぞれ色が異なります。

クリックされたときのevent.targetからボタンの色を取得してkeyframeで参照させます。

on/offいずれの状態でも変わらないのは、wakuの線の色、「stroke」です。クリックされたときに、strokeの色をgetComputedStyleを使って取得します。



「「3// ⑤呼び出される関数」」 function onoff() { 「「3//Ⓐ 〜略」」 「「3//Ⓑ 〜略」」 「「3//Ⓒ 枠のスタイル → 線の色を取得」」 let style = window.getComputedStyle(oya.children[0]); let stroke = style.stroke; }

Ⓒ SVGコードを整理したときに、枠オブジェクトを1つ目の要素にしていました。なので「oya.children[ 0 ]」で参照することができます。
変数「stroke」を宣言し、線の色を代入します。

アニメ〜ション。


準備が整いました。
アニメーションさせていきましょう。

「「3// ⑤呼び出される関数」」 function onoff() { bb「「3//Ⓐ〜Ⓒ、略」」 bb「「3//Ⓓ onとoffのkeyframe」」 bblet tofill = [ bbbb{fill:"#fff"}, bbbb{fill:"#fff"}, bbbb{fill:stroke}, bb]; bblet tosiro = [ bbbb{fill:stroke}, bbbb{fill:stroke}, bbbb{fill:"#fff"}, bb]; bb「「3//Ⓔ 親要素、アニメーション」」 bboya.children[0].animate(tofill,timing); bb「「3//Ⓕ 枠と中身もアニメーション」」 bbif(flag[index] == 0) { bboya.children[0].animate(tofill,timing); bbfor(i=1; i<oya.children.length; i++) { bboya.children[i].animate(tosiro,timing); bb} bbflag[index] = "1"; bb} else { bboya.children[0].animate(tosiro,timing); bbfor(i=1; i<oya.children.length; i++) { bbbboya.children[i].animate(tofill,timing); bb} bbflag[index] = "0"; bb} }

Ⓓ 先ほど取得した枠の色「stroke」を使って、on/off切り替え時のkeyframeを作成します。

「tofill」はoff→onの動き。オブジェクトの塗りが白から枠色に変わります。
「tosiro」はoff→on。枠色から白に戻ります。

Ⓔ 親要素の<svg>をアニメーションさせます。これは前回と同じですね。

Ⓕ フラグの状態に応じて、枠と中身をアニメーション。
枠は「oya.children[0]」で参照、中身はテキストなど複数の要素が含まれている場合もあるので、for文を使い全ての要素に命令しています。
同時に、配列「flag」の添字「index」に対応した要素を0←→1に切り替え。

扨(さて)これでコーディングは完了です。結果をみてみましょう。





⬆︎実際にクリックしてみてください。

それぞれのボタンのon/offがアニメーションを伴って切り替わります。
お疲れ様でした!

苦労した甲斐あり。


最後までお読み下さり、ありがとうございました。
とても長い作業となりましたが、これでボタンを追加するごとに自動的にアニメーションおよびon/offの管理ができるように成増。

例えば⬇︎のようなもの。クリックしてみてください。



◼︎ HTML

<svg 「「1class = "btn"」」 viewBox="0 0 595.3 595.3" > <path 「「4class="waku4"」」 d="M501,200.8c-44.7-118.3-189.9-65.2-203.3-6.1c-18.5-63-160.1-110-203.3,6.2C46.2,330.3,280.8,446.5,297.6,465.5 C314.4,450.4,549.1,328.1,501,200.8z"/> </svg>

◼︎ CSS

「「4.waku4」」 { fill:#fff; stroke:#FF5A79; stroke-width:4; stroke-linejoin:round; stroke-miterlimit:10;}

SVG画像をインライン表記で追加し、タグを整理するだけでアニメーション付きのボタンを量産することができます。

苦労した甲斐がありましたね!

Web Animations APIを使ったSVGアニメーション、まだまだ色んなことができそうです。引き続き実験をしていきたいと思います。ではまた〜 ♬



関連記事

SVG、線を描くアニメーション。

2020.09.23
〽️ 破線のプロパティをつかいます。


SVG、use要素を使ったモーションパス。

2020.09.07
〽️ ポイントは‥「マイナスの遅れ」。


SVG、モーションパスで複数の要素を動かす。

2020.08.29
〽️ 小技を集結させて実装します。


SVGアニメーション05、アニメーションしている部分をクリッピング(マスク)する。

2020.07.06
〽️ テキストの内部だけアニメーション。












「ふ」です。

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