第5回 SVG 円弧の基本

# はじめに
今回は、円弧の基本について記載しようと思います。
円弧の動作がよくわからず、説明をみてもよくわからなかったので、試して理解することにしました。

# 今回実施する内容
今回は、円弧の基本について記載しようと思います。

# ソースコード(Git Hub)
https://github.com/Build-Mount/SVG_05_arc

# 環境
OS: Windows 11 JP (64bit)
Edge: バージョン 136.0.3240.50 (公式ビルド) (64 ビット)

# 参考
[SVG2 Chapter9: Paths](https://www.w3.org/TR/SVG2/paths.html#PathDataEllipticalArcCommands)

# 用語

# 円弧とは
「円弧」とは、円の円周の一部。
図では、円の一部の赤色の円周部分が円弧です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/7617ecc3-0b60-445a-91cc-8ea26a81c403.png)

SVGではこの円弧を表示するために、A、もしくは、aコマンドを使用して円弧を記載します。
SVGでは真円だけでなく、楕円の円弧を記載することができます。

# 2点を通る楕円の組み合わせ
はじめに、円弧に着目すると、円弧は開始点と終了点が存在することがわかります（どちらが開始でどちらが終了でもこの時点では関係ありません）。
下図では、青丸にした部分が該当します。
この開始点と終了点を２つの点と考えたとき、この２つの点を通る**同じ形状の楕円**は、下図の通り２種類存在します。
また、１つの楕円に注目すると、この2点を境に大きい円弧と小さい円弧の２つが存在します。もう一つの楕円も同様に２つの円弧が存在し、合計４つの円弧が存在することがわかります（図では①、②、③、④と番号をつけています）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/9cbbf22f-f809-4267-aef9-20c277955d10.png)


このことを事前に理解しておくことが、円弧をSVGで記載するために有用だということがわかりました。
また、A、もしくは、aコマンドで記載するのは、楕円の円弧ですが、その中に真円の円弧が含まれます。
最初、A、もしくは、aコマンドの説明を調べていた時に、ほとんどが楕円の説明でした。円弧は楕円のものなのかというとそうではないのですが、円弧を説明するうえでは、楕円をベースにしたほうが各パラメータの意味がわかるため、楕円をベースにした説明が多いのだろうと思います。

# 円弧のコマンドとパラメータ

|コマンド|説明|
|---|---|
|A、もしくは、a|Aは絶対値指定で使用し、aは相対値指定で使用する。|

|パラメータ名|説明|
|--|--|
|rx|X軸方向の半径|
|ry|Y軸方向の半径|
|x-axis-rotation|X軸の回転度数|
|large-arc-flag|楕円の大きい方かを示すフラグ。0：小さい方、１：大きい方|
|sweep-flag|楕円を描く方向を示すフラグ。0：反時計回り、１：時計回り|
|x※|X軸方向の終点|
|y※|Y軸方向の終点|

※コマンドをAの絶対値指定の場合、aの相対値指定の場合、dx、dyであり、開始点からの相対値となる。
※円弧のパラメータには開始点はありません。開始点は、SVGで図形を記載するときの現在の位置です。

# 楕円と円弧のパラメータの説明
図をふまえて、円弧のパラメータの説明をします。
図では、説明上、楕円を示し、実際の円弧部分だけに切り取っていません。そのことはご理解ください。

## `rx`と`ry`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/4f99819c-f3ff-49c0-84c3-2250ccbf28aa.png)
図の通り、`rx`、`ry`は楕円の半径の値であり、真円の場合は、`rx`=`ry`です。

## `x-axis-rotation`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/cfa1f81c-16a6-4fac-8b4b-318a92b6b929.png)

X軸からの回転度数を度で入れると楕円が回転して表示されmます。
図では点線で記載されるはずの楕円に対して、`x-axis-rotation`を30に設定すると反時計回りに30度傾けた楕円になります。
-30度の場合は時計回りに傾けた楕円になります。

## `x`と`y`
`large-arc-flag`と`sweep-flag`の前に先に`x`と`y`を説明したほうが、理解しやすいため、先に`x`と`y`の説明をします。
`x`と`y`は円弧の終了点の座標です。
では、開始点はというと、円弧のコマンドを記載する直前の座標です。円の終了点のX軸の位置、および、Y軸の位置を示す。
この位置が、楕円の円弧のどこの場所に位置するのか？ですが、開始点の座標と終了点の座標間の距離に依存して、自動的にブラウザで計算されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/7f1b46a1-fdda-4dc4-bc33-8dddc61c5b1b.png)

### 開始点と終了点が楕円の円周上に配置できる場合
多分こんな感じで位置調整をしていると思います。
![楕円の位置.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/67a69237-52e7-4884-ade7-05e3e8361f79.gif)
開始点と終了点がX軸でそろっていない時はこんな感じの位置調整をしていると思います。
![楕円の位置2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/d9a5cd00-06c4-4b8d-be4c-8106da3073d3.gif)

### 開始点と終了点が楕円の円周上に配置できない場合
具体的には、開始点と終了点の距離が開いており円周上に開始点と終了点を配置できない場合、`rx`と`ry`の比率を維持しつつ楕円の大きさを調整するように動作しているように思います。
実際に試してみたところ、以下のような感じでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/eb6bc72f-8381-42c1-945d-bba0ee432cbd.png)

## `large-arc-flag`
「2点を通る楕円の組み合わせ」で説明した、円弧は１つの円の中に円弧が大きい方と小さい方の２つが存在します。
これのどちらの円弧を記載するかを示すフラグです。
0：円弧の小さい方、1：円弧の大きい方
`sweep-flag`と合わせて設定することで、「2点を通る楕円の組み合わせ」で説明した４つの円弧のどれを描くか選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/0aa1736b-f0d0-4fb2-beb7-346185142490.png)

## `sweep-flag`
「2点を通る楕円の組み合わせ」で説明した円弧で、開始点から時計回りに描かれる円弧か、反時計回りに描かれる円弧かを示すフラグです。
0：反時計回り、１：時計回り
`large-arc-flag`と合わせて設定することで、「2点を通る楕円の組み合わせ」で説明した４つの円弧のどれを描くか選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/871ac373-f9e8-47e8-bd1c-a8e0f76e3d24.png)

# 実際にコードを書いて確認
## 半円の場合
<details>
<summary>menu.html</summary>

```html:menul.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="arc.css" type="text/css">
    <title>menu</title>
</head>
<body>
    <div></div>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>1(大きい方)</td><td>1(時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
       <use xlink:href="arcIcon.svg#arcSymbol1"></use>
    </svg>
    <br>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>0(小さい方)</td><td>1(時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
      <use xlink:href="arcIcon.svg#arcSymbol2"></use>
    </svg>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>1(大きい方)</td><td>0(反時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
      <use xlink:href="arcIcon.svg#arcSymbol3"></use>
    </svg>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>0(小さい方)</td><td>0(反時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
      <use xlink:href="arcIcon.svg#arcSymbol4"></use>
    </svg>
</body>
</html>
```
</details>

<details>
<summary>arcIcon.svg</summary>

```html:arcIcon.svg
<?xml version="1.0" standalone="no"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <symbol id="arcSymbol1" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 1 1 140 0 z"/>
  </symbol>
  <symbol id="arcSymbol2" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 0 1 140 0 z"/>
  </symbol>
  <symbol id="arcSymbol3" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 1 0 140 0 z"/>
  </symbol>
  <symbol id="arcSymbol4" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 0 0 140 0 z"/>
  </symbol>
</svg>
```
</details>

<details>
<summary>arc.css</summary>

```css:arc.css
.fill {
    fill:red;
    stroke: black;
    background-color: yellow;
}

.fill:hover {
    fill: blue;
}
```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/c9530c73-beb4-467a-b814-5fa4bcc777e4.png)

半円の場合、当たり前ですが、`large-arc-flag`は1(大きい方)、0(小さい方)のどちらを選んでも形は変わりません。

### 楕円の場合
<details>
<summary>menu2.html</summary>

```html:menul2.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="arc.css" type="text/css">
    <title>menu</title>
</head>
<body>
    <div></div>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>1(大きい方)</td><td>1(時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
       <use xlink:href="arcIcon2.svg#arcSymbol1"></use>
    </svg>
    <br>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>0(小さい方)</td><td>1(時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
      <use xlink:href="arcIcon2.svg#arcSymbol2"></use>
    </svg>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>1(大きい方)</td><td>0(反時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
      <use xlink:href="arcIcon2.svg#arcSymbol3"></use>
    </svg>
    <table border="1">
      <tr><th>rx</th><th>ry</th><th>large-arc-flag</th><th>sweep-flag</th><th>x</th><th>y</th></tr>
      <tr><td>70</td><td>100</td><td>0(小さい方)</td><td>0(反時計回り)</td><td>140</td><td>0</td></tr>
    </table>
    <svg width="300px" height="300px" class="fill">
      <use xlink:href="arcIcon2.svg#arcSymbol4"></use>
    </svg>
</body>
</html>
```
</details>

<details>
<summary>arcIcon.svg</summary>

```html:arcIcon.svg
<?xml version="1.0" standalone="no"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <symbol id="arcSymbol1" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 1 1 130 0 z"/>
  </symbol>
  <symbol id="arcSymbol2" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 0 1 130 0 z"/>
  </symbol>
  <symbol id="arcSymbol3" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 1 0 130 0 z"/>
  </symbol>
  <symbol id="arcSymbol4" viewBox="0 0 300 300">
    <path d="M80 150 a70 100 0 0 0 130 0 z"/>
  </symbol>
</svg>
```
</details>

<details>
<summary>arc.css</summary>

```css:arc.css
.fill {
    fill:red;
    stroke: black;
    background-color: yellow;
}

.fill:hover {
    fill: blue;
}
```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/f83d6afb-140a-4b59-bda9-6e7b081ae173.png)


楕円の場合、`large-arc-flag`は1(大きい方)と0(小さい方)で差が発生しました。


# おわりに
円弧の使用方法について説明しました。
ある程度計算して円弧を作成すれば大丈夫そうな感じはしました。
しかし、円弧の位置を適当に設定してしまうと、楕円の計算がなされて拡大・縮小されることによって、思いもよらない図形になることもありました。
SVGはベクターを数値で設定し、数値の並びが続くため、ぱっと見ではないかわからず、設定を間違えてしまうこともありました。
この辺がSVGの難しさだなと思いました。