第16回 JavaScript transform-originとrotate、scaleを試す

# はじめに
今回は、`transform-origin`を設定して、`rotate`や`scale`の動作を確認したいと思います。

# 今回実施する内容
今回は、とJavaScript＋CSSで、`transform-origin`を設定しつつ、`rotate`や`scale`の動作を見ていきたいと思います。

- rotate
![transform-origin.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/3f0cf3e1-d964-c95a-a7f7-f2cabe687619.gif)

- scale
![transform-origin2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/74e6c1ab-9caf-cbcc-e821-34c3f8916add.gif)

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

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

# 参考
[transform-origin](https://developer.mozilla.org/ja/docs/Web/CSS/transform-origin)

# 用語

# `transform-orgin`の説明
`transform-orgin`は、アニメーションの起点となるポイントを指定することができるCSSのプロパティです。

[transform-origin](https://developer.mozilla.org/ja/docs/Web/CSS/transform-origin)には以下の通り記載されています。

> transform-origin は CSS のプロパティで、要素の座標変換 (transform) における原点を設定します。
>
> 座標変換の原点とは、それを中心に座標変換が適用される点です。例えば、 rotate() 関数における座標変換の原点は、回転の中心です。

構文については、記載が長いため、簡潔に記載します。

```css:css
transform-origin: X軸指定 [Y軸指定] [Z軸指定]
/**[]でくくった部分はオプションのため設定しなくても構いません。*/
```
です。

X軸指定、Y軸指定、および、Z軸指定は、キーワード、もしくは、値を設定します。

|軸|キーワード|
|:--|:--|
|X軸指定|`left`、`right`、`center`|
|Y軸指定|`top`、`bottom`、`center`|
|Z軸指定|なし|

キーワードの意味（具体的な値）は、以下の通りです。

|キーワード|意味（具体的な値）|
|:--|:--|
|`left`|0%|
|`right`|100%|
|`top`|0%|
|`bottom`|100%|
|`center`|50%|

値は、100pxや100emや100%など、具体的な値を設定します。

デフォルト値は、50%、50%、0ということであり、
X軸：50%
Y軸：50%
Z軸：0
です。

Z軸については、今回は調査しません。

# `rotate`を試す
<details><summary>transform-origin.html</summary>

```html:transform-origin.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>transform-origin(rotate)</title>
    <link rel="stylesheet" href="transform-origin.css" type="text/css">
    <script src="transform-origin.js" defer></script>
</head>
<body>
    <div id="base1">ベース位置</div>
    <div id="transform-origin1">transform-origin1</div>

    <div id="base2">ベース位置</div>
    <div id="transform-origin2">transform-origin2</div>

    <div id="base3">ベース位置</div>
    <div id="transform-origin3">transform-origin3</div>

    <div id="base4">ベース位置</div>
    <div id="transform-origin4">transform-origin4</div>

    <div id="base5">ベース位置</div>
    <div id="transform-origin5">transform-origin5</div>
</body>
</html>
```
</details>

<details>
<summary>transform-origin.js</summary>

```javascript:transform-origin.js
document.getElementById("transform-origin1").addEventListener("click", () => {
  document.getElementById("transform-origin1").classList.add("rotate1");
});

document.getElementById("transform-origin2").addEventListener("click", () => {
  document.getElementById("transform-origin2").classList.add("rotate2");
});

document.getElementById("transform-origin3").addEventListener("click", () => {
  document.getElementById("transform-origin3").classList.add("rotate3");
});

document.getElementById("transform-origin4").addEventListener("click", () => {
  document.getElementById("transform-origin4").classList.add("rotate4");
});

document.getElementById("transform-origin5").addEventListener("click", () => {
  document.getElementById("transform-origin5").classList.add("rotate5");
});
```
</details>

<details>
<summary>transform-origin.css</summary>

```css:transform-origin.css
#base1 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

#transform-origin1 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

.rotate1 {
  transform: rotate(45deg);
}

#base2 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 400px;
}

#transform-origin2 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 400px;
}

.rotate2 {
  transform: rotate(45deg);
  transform-origin: 0%;
}

#base3 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 700px;
}

#transform-origin3 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 700px;
}

.rotate3 {
  transform: rotate(45deg);
  transform-origin: 0% 0%;
}

#base4 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 100px;
}

#transform-origin4 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 100px;
}

.rotate4 {
  transform: rotate(45deg);
  transform-origin: 100% 100%;
}

#base5 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 700px;
}

#transform-origin5 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 700px;
}

.rotate5 {
  transform: rotate(45deg);
  transform-origin: 0% -50%;
}
```
</details>

## `transform-origin.html`の説明
「今回実施する内容」の`transform-origin`の５つの設定を試しますので、そのための要素を作成します。

```html
    <div id="base1">ベース位置</div>
    <div id="transform-origin1">transform-origin1</div>
```
`base1`と`transform-origin1`の要素を作成します。
`base1`要素は、`transform-origin`を適用しないで、適用しない場合のもとの場所を示すための要素です。
`transform-origin1`は、`transform-origin`を適用して、`base1`からの動作の差を比較します。
同様にして、`base2`～`base5`まで、および、`transform-origin2`～`transform-origin5`までを作成します。

## `transform-origin.js`の説明

```javascript
document.getElementById("transform-origin1").addEventListener("click", () => {
  document.getElementById("transform-origin1").classList.add("rotate1");
});
```
`transform-origin1`の要素をクリックした時に、`rotate1`を実行するリスナーを追加します。
同様にして、`transform-origin2`～`transform-origin5`までリスナーを作成します。

## `transform-origin.css`の説明

```css
#base1 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

#transform-origin1 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

.rotate1 {
  transform: rotate(45deg);
}
```

`#base1`は`base1`要素用のIDセレクタで、背景色は黄色にします。あとは要素のサイズと位置だけを設定しました。
`#base2`～`#base5`も同様に設定します。

`#transform-origin1`は`transform-origin1`要素用のIDセレクタで、背景色は赤色にします。あとは要素のサイズと位置だけを指定します。サイズと位置は`base1`用途と同じです。
`$transform-origin2`～`transform-origin5`も同様に設定します。

`.rotate1`は、要素を45度回転します。
`.rotate1`は`transform-origin`を設定しないデフォルト状態です。
デフォルトでは、X軸、Y軸とも50%のため、要素の真ん中で45度に回転します。
基本はこれとして、`.rotate2`～`.rotate5`は、transform-origin`の設定を変更しながら動作を確認します。

|クラスセレクタ|`transform-origin`設定|
|:--|:--|
|.rotate1|なし|
|.rotate2|`transform-origin: 0%;`|
|.rotate3|`transform-origin: 0% 0%;`|
|.rotate4|`transform-origin: 100% 100%;`|
|.rotate5|`transform-origin: 0% -50%;`|

`transform-origin`の設定で、回転ポイントの原点を図の通り設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/3c62f980-8531-a9bd-8637-a332f20542cd.png)

`.rotate5`では`transform-origin: 0% -50%;`を設定しました。原点のポイントはマイナスの値も設定でき、回転もその原点から回転します。

# `scale`を試す

<details>
<summary>transform-origin2.html</summary>

```html:transform-origin2.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Click Animation</title>
    <link rel="stylesheet" href="transform-origin2.css" type="text/css">
    <script src="transform-origin2.js" defer></script>
</head>
<body>
    <div id="base1">ベース位置</div>
    <div id="transform-origin1">transform-origin1</div>

    <div id="base2">ベース位置</div>
    <div id="transform-origin2">transform-origin2</div>

    <div id="base3">ベース位置</div>
    <div id="transform-origin3">transform-origin3</div>

    <div id="base4">ベース位置</div>
    <div id="transform-origin4">transform-origin4</div>

    <div id="base5">ベース位置</div>
    <div id="transform-origin5">transform-origin5</div>
</body>
</html>
```
</details>

<details>
<summary>transform-origin2.js</summary>

```javascript:transform-origin2.js
document.getElementById("transform-origin1").addEventListener("click", () => {
  document.getElementById("transform-origin1").classList.add("scale1");
});

document.getElementById("transform-origin2").addEventListener("click", () => {
  document.getElementById("transform-origin2").classList.add("scale2");
});

document.getElementById("transform-origin3").addEventListener("click", () => {
  document.getElementById("transform-origin3").classList.add("scale3");
});

document.getElementById("transform-origin4").addEventListener("click", () => {
  document.getElementById("transform-origin4").classList.add("scale4");
});

document.getElementById("transform-origin5").addEventListener("click", () => {
  document.getElementById("transform-origin5").classList.add("scale5");
});
```
</details>

<details>
<summary>transform-origin2.css</summary>

```css:transform-origin2.css
#base1 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

#transform-origin1 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

.scale1 {
  transform: scale(0.5);
}

#base2 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 400px;
}

#transform-origin2 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 400px;
}

.scale2 {
  transform: scale(0.5);
  transform-origin: 0%;
}

#base3 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 700px;
}

#transform-origin3 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 700px;
}

.scale3 {
  transform: scale(0.5);
  transform-origin: 0% 0%;
}

#base4 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 100px;
}

#transform-origin4 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 100px;
}

.scale4 {
  transform: scale(0.5);
  transform-origin: 100% 100%;
}

#base5 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 700px;
}

#transform-origin5 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 500px;
  left: 700px;
}

.scale5 {
  transform: scale(0.5);
  transform-origin: 0% -50%;
}
```
</details>

## `transform-origin2.html`の説明
「今回実施する内容」の`transform-origin`の５つの設定を試しますので、そのための要素を作成します。
内容は、`transform-origin2.html`と同じです。

```html
    <div id="base1">ベース位置</div>
    <div id="transform-origin1">transform-origin1</div>
```
`base1`と`transform-origin1`の要素を作成します。
`base1`要素は、`transform-origin`を適用しないで、適用しない場合のもとの場所を示すための要素です。
`transform-origin1`は、`transform-origin`を適用して、`base1`からの動作の差を比較します。
同様にして、`base2`～`base5`まで、および、`transform-origin2`～`transform-origin5`までを作成します。

## `transform-origin2.js`の説明
内容は、`transform-origin2.js`とほとんど同じです。

```javascript
document.getElementById("transform-origin1").addEventListener("click", () => {
  document.getElementById("transform-origin1").classList.add("scale1");
});
```
`transform-origin1`の要素をクリックした時に、`scale1`を実行するリスナーを追加します。
同様にして、`transform-origin2`～`transform-origin5`までリスナーを作成します。

## `transform-origin.css`の説明
内容は、`transform-origin2.css`とほとんど同じです。

```css
#base1 {
  background-color:yellow;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

#transform-origin1 {
  background-color:red;
  position: absolute;
  width: 200px;
  height: 100px;
  top: 100px;
  left: 100px;
}

.scale1 {
  transform: scale(0.5);
}
```

`#base1`は`base1`要素用のIDセレクタで、背景色は黄色にします。あとは要素のサイズと位置だけを設定しました。
`#base2`～`#base5`も同様に設定します。

`#transform-origin1`は`transform-origin1`要素用のIDセレクタで、背景色は赤色にします。あとは要素のサイズと位置だけを指定します。サイズと位置は`base1`用途と同じです。
`$transform-origin2`～`transform-origin5`も同様に設定します。

`.scale1`は、要素を0.5倍に縮小します。
`.scale1`は`transform-origin`を設定しないデフォルト状態です。
デフォルトでは、X軸、Y軸とも50%のため、要素の真ん中で0.5倍に縮小します。
基本はこれとして、`.rotate2`～`.rotate5`は、transform-origin`の設定を変更しながら動作を確認します。

|クラスセレクタ|`transform-origin`設定|
|:--|:--|
|.rotate1|なし|
|.rotate2|`transform-origin: 0%;`|
|.rotate3|`transform-origin: 0% 0%;`|
|.rotate4|`transform-origin: 100% 100%;`|
|.rotate5|`transform-origin: 0% -50%;`|

`transform-origin`の設定で、縮小ポイントの原点を図の通り設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/8083ea95-5caf-85fa-fdef-c2c9f1e7a599.png)

`.rotate5`では`transform-origin: 0% -50%;`を設定しました。原点のポイントはマイナスの値も設定でき、縮小もその原点から縮小します。

# おわりに
`transform-origin`を使用して、設定値の違いで動作がどうかわるかを`rotate`と`scale`で試しました。
動作はつかめましたので、次回以降これを利用したソースを作りたいと思います。