第13回 JavaScript アニメーションによる拡大・縮小（animate版）

# はじめに
今回は、アニメーションによる要素の拡大・縮小を試したいと思います。
ウェブサイトの広告でよくみかける、広告表示時やクローズ時にアニメーションで拡大・縮小する動作です。


ちょっと動きがあるほうがほんの少しのユーザーの助けになったり、リッチに見えるのかなと思います。
その時間がもったいかなとも思ったり。
気にかけてウェブをみていると、あまり見かけないような気もしました。

Windowsでは、ウィンドウの切り替えでは短い時間ですが動きはあるようです。
あってもいいのかなとも思いましたので、トライしてみたいと思います。

# 今回実施する内容
JavaScriptの`animate`を使用して、要素をクリックした時に拡大・縮小を実施します。
以下の４つのパターンを実施します。
- 拡大
- 縮小（縮小後、クリックしても動作なし）
- 水平方向に拡大（拡大後、すぐに初期のサイズに戻る）
- 垂直方向に縮小
![Scale1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/e041c4cd-ee0c-079c-6996-e803494b3acc.gif)

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

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

# 参考
[Element: animate()メソッド](https://developer.mozilla.org/ja/docs/Web/API/Element/animate)
[キーフレームの形式](https://developer.mozilla.org/ja/docs/Web/API/Web_Animations_API/Keyframe_Formats)
[transform-function](https://developer.mozilla.org/ja/docs/Web/CSS/transform-function)
[animation-fill-mode](https://developer.mozilla.org/ja/docs/Web/CSS/animation-fill-mode)

# 用語

# アニメーションによる拡大・縮小
## 関数の確認
[Element: animate()メソッド](https://developer.mozilla.org/ja/docs/Web/API/Element/animate)を使用して、アニメーションを作成したいと思います。


> ```javascript:構文
> animate(keyframes, options)
> ```
> ## 引数
> `keyframes`
>　キーフレームオブジェクトの配列、またはプロパティが反復処理可能な値の配列である単一のキーフレームオブジェクトのどちらかです。詳しくは [Keyframe の書式](https://developer.mozilla.org/ja/docs/Web/API/Web_Animations_API/Keyframe_Formats)を参照してください。
>
> `options`
> アニメーションの再生時間を表す整数値（ミリ秒単位）、または KeyframeEffect() のオプションの引数 (en-US)や以下のオプションで記述された 1 つ以上のタイミングプロパティを含むオブジェクトのどちらかです。

上記の記載と参考になるJavaScriptも記載されていますので、それを用いて拡大・縮小のアニメーションを作成します。

引数の`keyframes`としては、[キーフレームの形式](https://developer.mozilla.org/ja/docs/Web/API/Web_Animations_API/Keyframe_Formats)に記載があります。

> キーフレームは、animatable CSS propertiesのいずれかのプロパティと値のペアを指定します。プロパティ名はキャメルケースを使用して指定しますので、例えば background-color は backgroundColor となり、background-position-x は backgroundPositionX となります。margin のような一括指定も使用できます。

ということなので、CSSで定義されるプロパティ名を少し変えれば、`animate`の引数`keyframes`で使用できると理解しました。

>`transform-function`データ型は、以下に示した変換関数のうちの一つを使用して指定します。各関数は 2D または 3D の座標操作を適用します。

とありますので、今回は、拡大縮小を実施するため、[transform-function](https://developer.mozilla.org/ja/docs/Web/CSS/transform-function)の、`scale`、`scaleX`、`scaleY`を使用します。
そのほかに`scale3d`や`scaleZ`があるようですが、今回拡大・縮小で使用する`div`要素は平面なため、これらの確認は実施しません。

基本的な構文は、以下の通りです。
```css
transform: scale(1,1);
```

`transform:`の後に変換関数を記載するということです。

`options`については、今回は`duration`と`fill`を使用します。
> `duration` 随意
>アニメーションの各反復が完了するまでにかかるミリ秒数。既定値は 0 です。これは技術的にはオプションですが、この値が 0 の場合、アニメーションは実行されないことに注意してください。

> `fill` 随意
> アニメーションの効果を再生前に要素に反映させるか ()、アニメーションの再生が完了した後も保持するか ()、または を指定します。デフォルトは です。"backwards""forwards"both"none"

MDNが日本語翻訳されており、意味が分かりづらくなってしまっています。

|値|意味|
|:--|:--|
|backwards|再生前の状態に戻す|
|forwards|再生完了後の状態を保持する|

初期値はbackwards。



## ソース
シンプルに最初に示した動作を記載していきます。
<details><summary>transform_scale_js.html</summary>

```html:transform_scale_js.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Transform scale JavaScript</title>
    <link rel="stylesheet" href="transform_scale_js.css" type="text/css">
    <script src="transform_scale_js.js" defer></script>
</head>
<body>
    <div id="scale1">拡大はここをクリック</div>
    <div id="scale2">縮小はここをクリック</div>
    <div id="scale3">水平方向拡大はここをクリック</div>
    <div id="scale4">垂直方向縮小はここをクリック</div>
</body>
</html>
```
</details>

<details><summary>transform_scale_js.css</summary>

```css:transform_scale_js.css
#scale1 {
  background-color:yellow;
  position: absolute;
  width: 300px;
  height: 100px;
}

#scale2 {
  background-color:red;
  position: absolute;
  width: 300px;
  height: 100px;
  top: 150px;
}

#scale3 {
  background-color:blue;
  position: absolute;
  width: 300px;
  height: 100px;
  top: 300px;
}

#scale4 {
  background-color:green;
  position: absolute;
  width: 300px;
  height: 100px;
  top: 450px;
}
```
</details>

<details><summary>transform_scale_js.js</summary>

```javascript:transform_scale_js.js
document.getElementById("scale1").addEventListener("click", () => {
  clickScaleIn("scale1");
});

document.getElementById("scale2").addEventListener("click", () => {
  clickScaleOut("scale2");
});

document.getElementById("scale3").addEventListener("click", () => {
  clickScaleIn2("scale3");
});

document.getElementById("scale4").addEventListener("click", () => {
  clickScaleOut2("scale4");
});

function clickScaleIn(name) {
  const animation = document.getElementById(name).animate(
    [
      //キーフレーム
      {transform: 'scale(1)'},
      {transform: 'scale(2)'}
    ],    
    {
      //タイミングオプション
      duration: 1000,
      fill: "forwards"
    }
  );
}

function clickScaleOut(name) {
  const animation = document.getElementById(name).animate(
    [
      {transform: 'scale(0.5)'}
    ],    
    {
      duration: 1000,
      fill: "forwards"
    }
  );
}

function clickScaleIn2(name) {
  const animation = document.getElementById(name).animate(
    [
      //キーフレーム
      {transform: 'scale(1)'},
      {transform: 'scale(2,1)'}
    ],    
    {
      //タイミングオプション
      duration: 1000,
    }
  );
}

function clickScaleOut2(name) {
  const animation = document.getElementById(name).animate(
    [
      //キーフレーム
      {transform: 'scale(1)'},
      {transform: 'scaleY(0.5)'}
    ],    
    {
      //タイミングオプション
      duration: 1000,
      fill: "forwards"
    }
  );
}
```
</details>

## ４つの動作の違いについて
以下の４つのパターンの動作の違いとソースの違いを説明します。
- 拡大
- 縮小（縮小後、クリックしても動作なし）
- 水平方向に拡大（拡大後、すぐに初期のサイズに戻る）
- 垂直方向に縮小

### 拡大のソースと動作

```javascript:拡大
    [
      //キーフレーム
      {transform: 'scale(1)'},
      {transform: 'scale(2)'}
    ],    
    {
      //タイミングオプション
      duration: 1000,
      fill: "forwards"
    }
```
キーフレームは、「キーフレームの開始」と「キーフレームの終了」の`scale(1)`と`scale(2)` を設定し、「キーフレームの開始」は等倍で、「キーフレームの終了」は、２倍拡大します。

タイミングオプションは、[animation-fill-mode](https://developer.mozilla.org/ja/docs/Web/CSS/animation-fill-mode) を参照して、
`duration: 1000`でアニメーションは１秒間、
`fill: "forwards"`で、最後のアニメーションを保持であり、この例では２倍に拡大した状態が維持されます。
クリックしてアニメーション終了後に再度クリックすると、再度等倍に戻って、２倍まで拡大します。

### 縮小（縮小後、クリックしても動作なし）のソースと動作

```javascript: 縮小（縮小後、クリックしても動作なし）
    [
      {transform: 'scale(0.5)'}
    ],    
    {
      duration: 1000,
      fill: "forwards"
    }
```
キーフレームは、「キーフレームの終了」の`scale(0.5)`を設定し、「キーフレームの開始」は暗黙の等倍で、「キーフレームの終了」は、０．５倍に縮小します。

タイミングオプションは、`duration: 1000`でアニメーションは１秒間、
`fill: "forwards"`で、最後のアニメーションを保持であり、この例では０．５倍に縮小した状態が維持されます。
クリックしてアニメーション終了後に再度クリックすると、何もアニメーションは起こりません。
暗黙の等倍の場合、「キーフレームの終了」である０．５倍になっているとその状態から暗黙の「キーフレームの開始」の等倍に戻って、「キーフレームの終了」の０．５倍に縮小されることはないようです。

### 水平方向に拡大（拡大後、すぐに初期のサイズに戻る）のソースと動作

```javascript:水平方向に拡大（拡大後、すぐに初期のサイズに戻る）
    [
      //キーフレーム
      {transform: 'scale(1)'},
      {transform: 'scale(2,1)'}
    ],    
    {
      //タイミングオプション
      duration: 1000,
    }
```

キーフレームは、「キーフレームの開始」と「キーフレームの終了」の`scale(1)`と`scale(2,1)` を設定し、「キーフレームの開始」は等倍で、「キーフレームの終了」は、X方向（水平方向）を２倍拡大します。
`scale`の引数2つ目は省略可能で、１つのみの場合は、X軸、Y軸とも同じ値で拡大・縮小しますが、２つ記載する場合、X軸とY軸を別々に設定できます。
`scale(2,1)`とするとX軸は２倍、Y軸は等倍となります。

タイミングオプションは、`duration: 1000`でアニメーションは１秒間のみで、
これまで設定していた`fill: "forwards"`を設定しないと、アニメーションの最後で「キーフレームの開始」の等倍に戻ります。
クリックしてアニメーション終了後に再度クリックすると、水平方向に２倍まで拡大し、その後最初の「キーフレームの開始」の等倍に戻ります。

### 垂直方向に縮小のソースと動作

```javascript:垂直方向に縮小
    [
      //キーフレーム
      {transform: 'scale(1)'},
      {transform: 'scaleY(0.5)'}
    ],    
    {
      //タイミングオプション
      duration: 1000,
      fill: "forwards"
    }
```

キーフレームは、「キーフレームの開始」と「キーフレームの終了」の`scale(1)`と`scaleY(0.5)` を設定し、「キーフレームの開始」は等倍で、「キーフレームの終了」は、Y方向（垂直方向）を０．５倍に縮小します。
`scaleY`はY軸方向のみの拡大・縮小します。

タイミングオプションは、`duration: 1000`でアニメーションは１秒間、
`fill: "forwards"`で、最後のアニメーションを保持であり、この例では０．５倍に拡大した状態が維持されます。
クリックしてアニメーション終了後に再度クリックすると、等倍に戻って垂直方向に０．５倍まで縮小します。

# おわりに
`animate`と`transform:scale`を使用して、要素の拡大・縮小を実施しました。
次回は、`animate`ではなく、CSSで実施する方法を試したいと思います。