SVGの一部分をSVGだけで回転させたい

## はじめに

この記事はHRBrain Advent Calendar 2022カレンダー3の17日目の記事です。

https://qiita.com/advent-calendar/2022/hrbrain


下記のようなデザインでloadingのところクルクルしたいという話になりました。

<img width="480" alt="loading_svg.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37940/41f36460-6208-f92b-a649-1a9ee2027acc.png">


下記のクルクルしたい場所と留めておきたいところを別のsvgとして書き出して、それぞれposition指定してクルクルしたいところにCSSを当てれば動かせるというのはわかっていたんですが、なんとかsvgだけでできないかと試行錯誤しました。


## 元のsvgについて

figmaでデザインが作られていてこんな感じのSVGファイルでした。

グレーの丸のところがpathで表現されていました。

```xml
<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg" style="padding: 2em;">
  <rect width="400" height="300" transform="translate(0.5 0.5)" fill="none"/>
  ...
  <path opacity="0.36" d="M256.044 126.725C259.038 126.725 261.465 124.298 261.465 121.305C261.465 118.311 259.038 115.884 256.044 115.884C253.05 115.884 250.623 118.311 250.623 121.305C250.623 124.298 253.05 126.725 256.044 126.725Z" fill="#A5A5A5"/>
  <path opacity="0.16" d="M283.449 126.725C286.443 126.725 288.87 124.298 288.87 121.305C288.87 118.311 286.443 115.884 283.449 115.884C280.455 115.884 278.028 118.311 278.028 121.305C278.028 124.298 280.455 126.725 283.449 126.725Z" fill="#A5A5A5"/>
  <path opacity="0.84" d="M256.044 99.3205C259.038 99.3205 261.465 96.8936 261.465 93.8998C261.465 90.906 259.038 88.479 256.044 88.479C253.05 88.479 250.623 90.906 250.623 93.8998C250.623 96.8936 253.05 99.3205 256.044 99.3205Z" fill="#A5A5A5"/>
  <path opacity="0.23" d="M269.566 133.11C272.56 133.11 274.987 130.683 274.987 127.689C274.987 124.696 272.56 122.269 269.566 122.269C266.572 122.269 264.146 124.696 264.146 127.689C264.146 130.683 266.572 133.11 269.566 133.11Z" fill="#A5A5A5"/>
  <path d="M269.566 94.3415C272.56 94.3415 274.987 91.9146 274.987 88.9208C274.987 85.927 272.56 83.5 269.566 83.5C266.572 83.5 264.146 85.927 264.146 88.9208C264.146 91.9146 266.572 94.3415 269.566 94.3415Z" fill="#A5A5A5"/>
  <path opacity="0.52" d="M249.921 113.465C252.915 113.465 255.342 111.038 255.342 108.044C255.342 105.05 252.915 102.623 249.921 102.623C246.927 102.623 244.5 105.05 244.5 108.044C244.5 111.038 246.927 113.465 249.921 113.465Z" fill="#A5A5A5"/>
  <path opacity="0.09" d="M288.689 113.465C291.683 113.465 294.11 111.038 294.11 108.044C294.11 105.05 291.683 102.623 288.689 102.623C285.696 102.623 283.269 105.05 283.269 108.044C283.269 111.038 285.696 113.465 288.689 113.465Z" fill="#A5A5A5"/>
</svg>
```


## ちょっと調整

ちょっと触るにあたって中身がどこだかもよくわからず、円も本当に円なのか不安になったため、pathをやめてcircleを使うように変更しました。

```xml
<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg" style="padding: 2em;">
  <rect width="400" height="300" transform="translate(0.5 0.5)" fill="none"/>
  ...
  <circle cx="269.4" cy="89" r="5.42" fill="#A5A5A5"/>
  <circle opacity="0.84" cx="255.964971135" cy="94.5649711349" r="5.42" fill="#A5A5A5"/>
  <circle opacity="0.52" cx="250.4" cy="108" r="5.42" fill="#A5A5A5"/>
  <circle opacity="0.36" cx="255.964971135" cy="121.435028865" r="5.42" fill="#A5A5A5"/>
  <circle opacity="0.23" cx="269.4" cy="127" r="5.42" fill="#A5A5A5"/>
  <circle opacity="0.16" cx="282.835028865" cy="121.435028865" r="5.42" fill="#A5A5A5"/>
  <circle opacity="0.09" cx="288.4" cy="108" r="5.42" fill="#A5A5A5"/>
</svg>
```

ちなみにcx,cyを出すためにはデザイン上のディスプレイの中心から三平方の定理を使ってそれぞれの角度のcx,cyを出し直しました。(1.41421356を思い出し算出しました。算数大事)


## クルクルさせる

[animateTransform](https://www.w3.org/TR/SVG11/animate.html#AnimateTransformElement)というタグを利用しました。

animateTransformは、SVGで要素を変形するためのアニメーションを定義するために使用されます。animateTransformタグは、次のようなに要素を変形することができます。

- scale：要素を拡大または縮小する
- translate：要素を平行移動する
- rotate：要素を回転する
- skewX：要素を水平方向に歪める
- skewY：要素を垂直方向に歪める

今回はクルクルさせるためにrotateを利用します。

クルクルさせる対象を指定するためgタグを利用して対象にしたい要素をグループ化しました。

このようなSVGになりました。

```xml

<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg" style="padding: 2em;">
  <rect width="400" height="300" transform="translate(0.5 0.5)" fill="none"/>
  ...
  <g>
    <circle cx="269.4" cy="89" r="5.42" fill="#A5A5A5"/>
    <circle opacity="0.84" cx="255.964971135" cy="94.5649711349" r="5.42" fill="#A5A5A5"/>
    <circle opacity="0.52" cx="250.4" cy="108" r="5.42" fill="#A5A5A5"/>
    <circle opacity="0.36" cx="255.964971135" cy="121.435028865" r="5.42" fill="#A5A5A5"/>
    <circle opacity="0.23" cx="269.4" cy="127" r="5.42" fill="#A5A5A5"/>
    <circle opacity="0.16" cx="282.835028865" cy="121.435028865" r="5.42" fill="#A5A5A5"/>
    <circle opacity="0.09" cx="288.4" cy="108" r="5.42" fill="#A5A5A5"/>
    <animateTransform attributeName="transform" type="rotate" from="0 269.4 108" to="360 269.4 108" dur="1.8s" repeatCount="indefinite" />
  </g>
</svg>
```

<img width="480" alt="loading_svg.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37940/dbed1d41-f46d-f0ec-a6e1-1933a3035821.gif">


無事loadingのところクルクルできました。(gifなので荒め)