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

〽️仕組み。 〽️「羽根」を作成。 〽️回転アニメーションごと複製。 〽️残り2枚の処理。 〽️お疲れ様でした。





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

こんにちは、「ふ」です。
今回のSVGアニメーションは、ヘッダ画像のような「物理カメラのシャッター(絞り)の動き」を表現してみたいと思います。

使う要素はただのrectangle(長方形)です。ですから今回はベクターソフトを使わずとも、コーディング環境だけで実装することができます。ぜひ作ってみてください。

仕組み。


このシャッターの動き、どのような仕組みになっているのでしょうか?

長方形が、1つの頂点を軸に回転。

これを複製 → 角度を付けて重ねていくと、シャッターが開閉するような動きに成増。
「長方形」を重ねるのではなく、「長方形が回転している状況」ごと、重ねていきます。

web上のviewport(可視領域)は、こんな感じです。
余計な隙間ができないように、可視領域に対して長方形は十分な大きさにしておきましょう。

そして。
「この部分はどうなっているのだろう・・」と思った方もいるでしょう。
最後の1枚の先端が、1枚目の根元を隠してしまっています。
ここの処理が今回のポイント。記事の後半で説明しています♫

「羽根」を作成。


回転する長方形を「羽根」と呼ぶことにします。
先づはhtml内にSVG領域を設けましょう。

■HTML

<body> 「「1<svg viewBox = "0 0 841.9 595.3> </svg>」」 </body>

大きさはご自由に。「ふ」はA4比率としました。
わかりやすいよう、CSSで枠線を付けておきます。

■CSS

svg { 「「1border:solid 1px;」」 }

SVG領域⬆︎が確保できました。
コードで羽根を作ります。回転している時に可視領域に隙間ができないように、幅を100%、高さを200%としました。
羽根にはclass名「hane」と、お好みで塗りと線の色を付けておきましょう。

■body→svg

<svg viewBox = "0 0 841.9 595.3> <rect class = 「「5"hane"」」 x = "50%" y = "-50%" width = "100%" height = "200%"/> </svg>

■CSS

「「5.hane」」 { fill:#00aeef; stroke:#222; stroke-width:4; }

web上ではあくまで可視領域のみ表示されるので、こんな⬆︎感じ。

ですが実際のSVG空間では、可視領域に対して長方形がこのように配置されています。
タグ内で指定したxyの座標、幅や高さも反映されています。

SVG領域の作り方については、コチラ⬇︎の記事で詳しく紹介しています。


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

2021.01.20
positionやz-index指定なし。


ではこの長方形を、左上の頂点を中心に回転させましょう。

■CSS

.hane { fill:#00aeef; stroke:#222; stroke-width:4; transform-origin:50% -50%; 「「1・・ ①」」 animation:hane 4s linear alternate infinite; 「「1・・ ②」」 } @keyframes hane { bbto { transform:rotate(-60deg); 「「1・・ ③」」 } }

① transform-originで回転の中心を指定。<rect>要素のxとy属性は、長方形の左上の座標を示しています。回転軸と一致するため、そのまま使えますね。

② アニメーションは一括指定で記述していますが、animation-direction(アニメーションの方向)で「alternate」を指定しています。繰り返した時に、アニメーションの内容が往復するように成増。

③ transform : rotateで半時計まわりに回転。羽根が全開のときに可視領域から完全に消えるように、プレビューしながら角度を調整しました。

現在このような状態になっています。
これを複製していきましょう。

回転アニメーションごと複製。


今回は羽根6枚バージョンで作っていきます。
先ほど作ったものを複製。viewportの中心を基準に、角度を変えて重ねていきます。

角度を付けるためには、transform-originやtransform : rotateを使うのですが、これらのプロパティは長方形自体のアニメーションにおいて、すでに使用してしまっています。

例えば、

■CSS

#element { background-color:red; background-color:green; }

1つの要素に同じプロパティを2重に施す、ということはできません。後に指定した値が採用されるだけです。

ここは長方形をグループ化し、「アニメーションしている長方形」ごと複製・回転させましょう。

「「1<g id = "soto1" class = "soto">」」 <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> 「「1</g>」」

1枚目なのでidを「soto1」、classを「soto」としました。
class名を付けたのは、transform-originを一括で指定したかったからです。これを複製して前面に重ねていきます。

<g id = "soto1" class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> </g> <g id = 「「5"soto2"」」 class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> </g> <g id = 「「5"soto3"」」 class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> </g> ・・・・・・・・ <g id = 「「5"soto6"」」 class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> </g>

id名を順に「soto2〜6」として重ねました。

現在の状態。
まだ同じ位置に重なっているので、見た目の羽根は1枚です。
「#soto2」以降に60°ずつ角度を付けていきます。

■CSS

.soto { transform-origin:center; } #hane2 { transform:rotate(「「160deg」」); } #hane3 { transform:rotate(「「1120deg」」); } ・・・・・・・・

これは4枚目までを複製→角度を付けたところです(5、6枚目は紛らわしいので非表示にしています)。

ここまでは、いい感じ。

問題は残りの2枚です。

残り2枚の処理。


その後、同じようにして5、6枚目を重ねた結果がコチラ⬇︎。

何かがおかしい。

〜ですよね。

「アニメーションしている羽根」を順に前面に重ねていくと、最後のほうの羽根の先端が1枚目の前面に被ってしまいます。
6枚目に隠れて見えませんが、5枚目も同じく最初の1枚に被ってしまっています。

羽根の付け根はそのままで良いのですが。
本来羽根の先端は1枚目の背後に回っていなければいけません。

どうする?

〜ここはclipPathで乗り切りましょう。

1枚目に被っている部分が非表示になれば、羽根先が1枚目の背後に回っているように見せることができます。

ということは、「見せてもいい」部分でクリップしてしまえば良いということですね!

クリップパスに使う長方形を描きましょう。

<clipPath id = "clip"> <rect width = "50%" height = "100%"/> </clipPath>

クリップパスのidは「clip」としました。
この長方形で#soto5と#soto6をクリップするのですが、それぞれのsotoグループは事前にtransform : rotateで回転させてしまっています。
直接クリップを施すと、「クリップしたものが回転」してしまいます。
これではうまくいきません。

#soto5と#soto6をさらにグループで囲み( idを「oosoto」)、そのグループに対してclipPathを掛けます。

■SVG

「「1<g id = "oosoto">」」 <g id = "soto5" class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> </g> <g id = "soto6" class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/> </g> 「「1</g>」」

■CSS

#oosoto { 「「1clip-path:url(#clip);」」 }

クリップできました。あとは、6枚目の羽根先が非表示になってしまっているので、複製して最背面に配置します。

■SVG

<!--複製した#soto6を#soto1の背面にペースト。--> 「「1<g id = "soto6" class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/>」」 </g> <g id = "soto1" class = "soto"> <rect class = "hane" x = "50%" y = "-50%" width = "100%" height = "200%"/>

これで完成です。お疲れ様でした!
羽根の向こう側には好きな画像を入れてください、ふふふ。

お疲れ様でした。


最後までお読みいただき、ありがとうございました。
今回の物理カメラのシャッターを作るにあたっては、「どういう動きをしているのか?」というところから入りました。実物のカメラの画像や動画などをあれこれ調べて、それからSVGアニメーションに落とし込んだ形です💧

時間は掛かったけど、やり甲斐がありました。工業技術のすごさにも感心した次第です。
みなさんもリアル世界にあるものをSVGアニメーションに変換してみては?ふふふ。
苦労しますが、すごく勉強になるかもですよ。ではまた〜 ♫



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

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


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

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












「ふ」です。

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