GSAP(基本機能)

アニメーション制作のJavaScriptのライブラリ「GSAP」を試したので、使い方をまとめました。
※この記事では、プラグインはコアプラグインまでしか扱いません。

## 導入

npmでインストールします。

```.terminal
npm i -S gsap
```
webpackなどでバンドルしてください。
※TypeScriptで使う場合に必要な型定義ファイルはgsapモジュールに含まれているので、別途インストールは不要です

CDNも用意されています

```.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.0/gsap.min.js"></script>
```


## Tween
Tweenという小さな単位でアニメーションを作っていきます。

### アニメーションでよく使うCSSプロパティ

|プロパティ|説明|
|---|---|
|opacity|透明度(0～1の間)|
|x|x軸方向に移動(単位はpx) ※translateX()のショートカット|
|y|y軸方向に移動(単位はpx) ※translateY()のショートカット|
|scale|大きさ(単位は倍)|
|width|数値の他に、"auto"に対してもアニメーションできる|
|height|数値の他に、"auto"に対してもアニメーションできる|
|top|上配置|
|left|左配置|
|backgroundColor|背景色|
|margin|マージン|
|padding|パディング|
|rotation|回転|
|skew|傾斜変形|




### トランスフォームの起点の指定

transformOriginプロパティで、トランスフォームの起点の位置を指定できます。

|値の種類|値の例|
|---|---|
|キーワード|"top"、"left"、"right"、"bottom"|
|割合|"100% 100%"|
|ピクセル|100|

デフォルト：`"50% 50%"`(要素の中央)



### Tweenの種類(4種類)

- from
- to
- fromTo
- set






#### to
ゴールの状態を指定します
(現在の状態からのアニメーション)

例：要素を今ある位置から右(ｘ軸方向)へ移動させる

```.js
gsap.to(
  アニメーションさせる要素,
  
  //完了状態
  {
    プロパティ名:値,
    プロパティ名:値,
    ...
    },
  
  アニメーション開始時間(秒単位)
);
```
 





#### from
スタートの状態を指定します
(現在の状態に戻るアニメーション)

例：要素を今ある位置から右(ｘ軸方向)へ移動させる

```.js
gsap.from(
  アニメーションさせる要素,
  
  //初期状態
  {
    プロパティ名:値,
    プロパティ名:値,
    ...
  },
);
```





#### fromTo
fromとtoのあわせ技です
指定した状態(初期状態)から、指定した状態(完了状態)にアニメーションさせます
durationは完了状態の方で指定します


```.js
gsap.fromTo(
  アニメーションさせる要素,
  
  //初期状態
  {
    プロパティ名:値,
    プロパティ名:値,
    ...
  },
   
  //完了状態
  {
    プロパティ名:値,
    プロパティ名:値,
    ...
  },
)
``` 







#### set
状態を指定します
(CSSを使わずに、GSAP内で指定できます)
fromは、実行されると初期状態に戻るアニメーションが起きてしまうので、位置は変更してそのままにしたい時に使います


```.js
gsap.set(
  位置を決める要素,
  
  //アニメーションさせない静止状態を指定する
  {
    プロパティ名:値,
    プロパティ名:値,
    ...,
  },
);
``` 



### サンプルコード

```.html
<div class="box one">box1</div>
<div class="box two">box2</div>
<div class="box three">box3</div>
<div class="box four">box4</div>
```

```.css
.box {
  align-items: center;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
}
 
.one {
  background-color: red;
}
.two {
  background-color: blue;
}
.three {
  background-color: green;
}
.four {
  background-color: black;
}
``` 


```.js
import { gsap } from "gsap";

gsap.to(
  ".one",
  {
    rotation: 180,
    x: 200,
    duration: 1,
    repeat: -1,
  },
  //開始するまでの時間(秒)
  2
);
 
gsap.from(".two", {
  rotation: 180,
  x: 200,
  duration: 1,
  repeat: -1,
});
 
gsap.fromTo(
  ".three",
  {
    rotation: 180,
    x: 200,
  },
  {
    rotation: 270,
    x: 400,
    duration: 1,
    repeat: -1,
  }
);

gsap.set(".four", {
  rotation: 180,
  x: 1000,
});
``` 
 

### イベント発生時に適用

#### Tweenをマウスホバー時に適用

例：boxクラスを持つ要素全てで、mouseenterイベント発生時にTweenを適用

```.js
document.querySelectorAll(".box").forEach((box) => {
  box.addEventListener("mouseenter", () => {
    gsap.to(".box", {
      rotation: 180,
      x: 200,
      duration: 1,
    });
  });
});
```

#### 要素クリック時にTweenを適用

例：boxクラスを持つ要素全てで、clickイベント発生時にTweenを適用

```.js
document.querySelectorAll(".box").forEach((box) => {
  box.addEventListener("click", () => {
    gsap.to(".box", {
      rotation: 180,
      x: 200,
      duration: 1,
    });
  });
});
```





### Tweenのコールバック



#### onComplete
アニメーションが完了したときに呼び出す関数

##### onCompleteParams
onComplete関数に渡すためのパラメーターの配列

```.js
gsap.to(".class", {x:100, onComplete:myFunction, onCompleteParams:["param1", "param2"]});.
```




#### onRepeat
アニメーションが新しい反復サイクル(repeat)に入るたびに呼び出す関数

##### onRepeatParams
onRepeat関数に渡すためのパラメーターの配列





#### onReverseComplete
アニメーションが逆方向から再び開始に達したときに呼び出す関数(repeatを除く)

##### onReverseCompleteParams
onReverseComplete関数に渡すためのパラメーターの配列





#### onStart
アニメーションの開始時に呼び出す関数

##### onStartParams
onStart関数に渡すためのパラメーターの配列




#### onUpdate
アニメーションが更新されるたびに呼び出す関数(再生ヘッドを移動する「ティック」ごとに)

##### onUpdateParams
onUpdate関数に渡すためのパラメーターの配列






### Tweenのオプション

fromToの場合はTo側に書くもの

- duration
- ease
- repeat



#### data
このプロパティに任意のデータ(文字列、オブジェクトへの参照など)を割り当てると、Tweenインスタンス自体にアタッチされ、後でyourTween.dataのように参照できるようになる

#### delay
数値型
アニメーションが開始されるまでの時間(秒単位)

#### duration
数値型
アニメーションの長さ(秒単位)
デフォルト：0.5

#### ease
文字列型 | 数値型
アニメーションの変化率を制御する

指定できる値

- 0から1までの値
- キーワード



|キーワード|キーワード|キーワード|
|---|---|---|
|none|||
|power1.out|power1.inOut|power1.in|
|power2.out|power2.inOut|power2.in|
|power3.out|power3.inOut|power3.in|
|power4.out|power4.inOut|power4.in|
|back.out(数値)|back.inOut(数値)|break.in(数値)|
|elastic.out(数値,数値)|elastic.inOut(数値,数値)|elastic.in(数値,数値)|
|bounce.out|bounce.inOut|bounce.in|
|slow(数値,数値,boolean)	|||
|steps(数値)	|||
|circ.out|circ.inOut|circ.in|
|expo.out|expo.inOut|expo.in|
|sine.out|sine.inOut|sine.in|
|(Custom)|||

```.js
 "rough({
   template:easeのキーワード, 
   strength: 数値,
   points: 数値, 
   taper: ("none"/"in"/"out"/"both"), 
   randomize: boolean, 
   clamp: boolean
 })"
```

デフォルト：「power1.out」




#### id
文字列型
後でgsap.getById()で見つけて、GSDevToolsで表示させるために、ユニークなIDをTweenにアサインできる


#### immediateRender
ブーリアン型
通常、トゥイーンはdelayを指定しない限り、次のティック(更新サイクル)まで最初のレンダリングを待機する
「true」を設定すると、インスタンス化の直後に強制的にレンダリングされる

|Tweenの種類|デフォルトでのimediateRenderの設定|
|---|--|
|to()|false|
|from()|true|
|fromTo()|true|
|scrollTriggerが適用されているもの|true|



#### inherit
ブーリアン型
通常トゥイーンは親タイムラインのデフォルトオブジェクト(定義されている場合)から継承する
inherit：falseを設定することで、トゥイーンごとにこれを無効にできる

#### lazy
ブーリアン型
Tweenが最初にレンダリングされて開始値を読み取るとき、GSAPは現在の「ティック」の最後まで値の書き込みを遅らせようする
これにより、ブラウザが嫌うレイアウトの読み書きを避けることができ、パフォーマンスが向上する
特定のトゥイーンのレイジーレンダリングを無効にするには、lazy：falseを設定する
デフォルト：「true」(durationが0のTweenを除く)


#### overwrite
ブーリアン型

|値|内容|
|---|---|
|true|影響を受けるプロパティに関係なく、同じターゲットのすべてのトゥイーンがすぐに強制終了される|
|auto|トゥイーンが初めてレンダリングされるときに、アクティブなアニメーション(同じターゲットの同じプロパティをアニメーション化する)の競合を追跡し、他のトゥイーンのそれらの部分のみを強制終了する<br>競合しないパーツはそのまま残る|
|false|上書きされない|

デフォルト：false





#### paused
ブーリアン型
「true」の場合、アニメーションは作成直後に一時停止
デフォルト：「false」


#### repeat
数値型
アニメーションを何回繰り返すかの指定
1だと、通常の再生+repeat1回の合計2回の再生
デフォルト：0


#### repeatDelay
数値型
リピートの間に待機する時間(秒単位)を指定する
デフォルト：0


#### repeatRefresh
ブーリアン型
「true」を設定すると、Tweenのrepeatが無効化し、完全な反復ごとに内部的に開始/終了値を再記録する
(yoyoは含まれない)
例
`x："rando(-100,100)"`は、繰り返しごとに新しいランダムx値を取得する
duration、delay、staggerは更新されない


#### reversed
ブーリアン型
「true」の場合、アニメーションは再生ヘッドを逆にして開始する



#### runBackwards
ブーリアン型
trueの場合、アニメーションは開始値と終了値を反転する
(イージングは反転しない)
↓
runBackwards：trueを設定することで、to()をfrom()にすることができる


#### stagger
数値型 | オブジェクト型
複数のターゲットが定義されている場合、`stagger:0.1`（各開始時間の間の0.1秒間）のような値を設定することで、それぞれの開始時間を簡単にずらすことができる
staggerオブジェクトを使用すると、高度なstaggerを使用できる


#### startAt
オブジェクト
プロパティの開始値を定義(アニメーション化されていない場合も有効)

```.js
startAt: {x: -100, opacity: 0}
```

#### yoyo
ブーリアン型
「true」にするとyoyoを有効化

#### yoyoEase
ブーリアン型  | 文字列型
トゥイーンのヨーヨーの段階にイージングを変更できる
「power2.in」のように特定のイーズを指定するか、「true」に設定して、トゥイーンの通常のイーズを単純に反転させる
yoyoEaseを使うと、yoyoが自動的にtrueになる
デフォルト：「false」



####  keyframes
配列型
ターゲットをさまざまな状態にアニメーションするには、キーフレームを使う
to()トゥイーンとして役立つvarsオブジェクトの配列

```.js
keyframes: [{x:100, duration:1}, {y:100, duration:0.5}]. 
```

すべてのキーフレームは完全に連続してシーケンスされるが、delayを定義して各ステップ間にギャップを追加する(マイナスのdelayはオーバーラップを追加)

## Timeline

Tweenを連結して、長い(複雑な)アニメーションを作れます

### サンプルコード

#### 共通のHTML、CSS

```.html
<div class="box">box</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
}
``` 


#### Timelineを使わないでアニメーションを連続する場合のJavaScript
複数のアニメーションを連続で実装したい場合

```.js
import { gsap } from "gsap";

//0秒後に行うアニメーション
gsap.to(
  ".box",
  {
    x: 400,
  },
  0
);

//1秒後に行うアニメーション
gsap.to(
  ".box",
  {
    y: 400,
  },
  1
);

//2秒後に行うアニメーション
gsap.to(
  ".box",
  {
    x: 0,
  },
  2
);

//3秒後に行うアニメーション
gsap.to(
  ".box",
  {
    y: 0,
  },
  3
);
```


#### Timelineを使ってアニメーションを連続する場合のJavaScript

タイムラインを作成し、.to()を連結してアニメーションを構成します。
初期状態を指定したい場合は、.set()を最初に指定します(timelineの外で指定することも可能)

```.js
import { gsap } from "gsap";
 
//timeline作成
const tl = gsap.timeline();

//0秒後に行うアニメーション
tl.to(
  ".box",
  {
    x: 400,
  },
  0
)

//1秒後に行うアニメーション
.to(
  ".box",
   {
    y: 400,
  },
  1
)
//2秒後に行うアニメーション
.to(
  ".box",
  {
    x: 0,
  },
  2
)

//3秒後に行うアニメーション
.to(
  ".box",
  {
    y: 0,
  },
  3
);
```

### 各Tweenの開始時間の指定
数値以外の指定も可能です


#### 時間指定で数値以外に指定できるもの

|値|説明|
|---|---|
|+=数値|前のTweenの終了後に指定の時間のギャップ|
|-=数値|前のTweenの終了前に指定の時間オーバーラップ|
|>数値|最後のTweenの終了時の指定した数値秒後(マイナスも指定可能、数値省略時はデフォルトの0.5になる)|
|<数値|最後のTweenの開始時の指定した数値秒後(マイナスも指定可能、数値省略時はデフォルトの0.5になる)|
|ラベル|他のラベル名+=数値、他のラベル名-=数値も可能|



#### +=、-=
数値ではなく文字列なのでクォーテーションで囲むのを忘れないようにします


|値の例|説明|
|---|---|
|"+=2"|2 秒のギャップを作成|
|"-=2"|2 秒のオーバーラップを作成|


```.html
<div class="box">box1</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
}
``` 

```.js
import { gsap } from "gsap";

//timeline作成
const tl = gsap.timeline();

//0秒時点で行うアニメーション
//(durationを省略しているので、長さはデフォルトの0.5秒)
tl.to(
  ".box",
  {
    x: 400,
  },
  0
)

//前のtweenが終わって1秒後に行うアニメーション
//1秒時点で開始されるのではなく、前のアニメーション(0.5秒間)が終了してから1秒後なので、1.5秒時点で開始される
.to(
  ".box",
  {
    y: 400,
  },
  "+=1"
)
   
//前のtweenが終わって1秒後に行うアニメーション
//2秒時点で開始されるのではなく、前のアニメーション(0.5秒間)が終了してから1秒後なので、3秒時点で開始される
.to(
  ".box",
  {
    x: 0,
  },
  "+=1"
)

//前のtweenが終わって1秒後に行うアニメーション
//3秒時点で開始されるのではなく、前のアニメーション(0.5秒間)が終了してから1秒後なので、4.5秒時点で開始される
.to(
  ".box",
  {
    y: 0,
  },
  "+=1"
);
```






#### ラベル
ラベルを使用してタイムライン上の特定の位置をラベリングできます

- ラベルの位置にアニメーションを配置する
- timelineの制御時(後述)に、ラベルの位置に移動する

など

```.html
<div class="box one">box1</div>
<div class="box two">box2</div>
<div class="box three">box3</div>
<div class="box four">box4</div>
```

```.css
.box {
  align-items: center;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
}

.one {
  background-color: red;
}
.two {
  background-color: blue;
}
.three {
  background-color: green;
}
.four {
  background-color: black;
}
``` 

```.js
import { gsap } from "gsap";

const tl = gsap.timeline();

//ラベルを追加(ラベル名「labelA」、2秒の位置)(ラベル名「labelB」、6秒の位置)
tl.addLabel("labelA", 2)
  .addLabel("labelB", 6)
  .to(".one", { x: 200 }, "labelA") //「labelA」から開始
  .to(".two", { x: 200 }, "labelA-=1") //「labelA」の1秒前に開始
  .to(".three", { x: 200 }, "labelA+=1") //「labelA」の1秒後に開始
  .to(".four", { x: 200 }, "labelB+=0.5"); //「labelB」の0.5秒後に開始
``` 
  

### イベント発生時に適用

#### mouseenterイベント発生時に適用

```.js
import { gsap } from "gsap";

//timeline作成
const tl = gsap.timeline();

//boxクラスを持つ要素全てで、clickイベント発生時にTimelineを適用
document.querySelectorAll(".box").forEach((box) => {
  box.addEventListener("mouseenter", () => {
    //0秒後に行うアニメーション
    tl.to(
      ".box",
      {
        x: 400,
      },
      0
    )

      //1秒後に行うアニメーション
      .to(
        ".box",
        {
          y: 400,
        },
        1
      )
      //2秒後に行うアニメーション
      .to(
        ".box",
        {
          x: 0,
        },
        2
      )
      //3秒後に行うアニメーション
      .to(
        ".box",
        {
          y: 0,
        },
        3
      );
  });
});
``` 



#### clickイベント発生時に適用

```.js
import { gsap } from "gsap";

//timeline作成
const tl = gsap.timeline();

//boxクラスを持つ要素全てで、clickイベント発生時にTimelineを適用
document.querySelectorAll(".box").forEach((box) => {
  box.addEventListener("click", () => {
    //0秒後に行うアニメーション
    tl.to(
      ".box",
      {
        x: 400,
      },
      0
    )

      //1秒後に行うアニメーション
      .to(
        ".box",
        {
          y: 400,
        },
        1
      )
      //2秒後に行うアニメーション
      .to(
        ".box",
        {
          x: 0,
        },
        2
      )
      //3秒後に行うアニメーション
      .to(
        ".box",
        {
          y: 0,
        },
        3
      );
  });
});
```





### Timelineのコールバック







#### onComplete
ファンクション型
アニメーション完了時に呼び出される関数

##### onCompleteParams
配列型
onComplete関数に渡すためのパラメーターの配列

```.js
gsap.timeline({onComplete: myFunction, onCompleteParams: ["param1", "param2"]});.
```




#### onRepeat
ファンクション型
アニメーションが繰り返されるたびに呼び出される関数

##### onRepeatParams]
配列型
 onRepeat関数に渡すためのパラメーターの配列


```.js
gsap.timeline({onRepeat: myFunction, onRepeatParams: ["param1", "param2"]});.
```





#### onReverseComplete
ファンクション型
アニメーションが逆方向から再び開始に達したときに呼び出される関数
reverse()で、トゥイーンが最初に戻り、時間が0に達すると、onReverseCompleteが呼び出される

##### onReverseCompleteParams
配列型
onReverseComplete関数に渡すためのパラメーターの配列

```.js
gsap.timeline({onReverseComplete: myFunction, onReverseCompleteParams: ["param1", "param2"]});.
```



#### onStart
ファンクション型
アニメーションの開始時に呼び出される関数

##### onStartParams
配列型
onStart関数に渡すためのパラメーターの配列

```.js
gsap.timeline({onStart: myFunction, onStartParams: ["param1", "param2"]});
```



#### onUpdate
ファンクション型
アニメーションが更新されるたびに（アニメーションがアクティブな間はすべてのフレームで）呼び出される関数

##### onUpdateParams
配列型
onUpdate関数に渡すためのパラメーターの配列

```.js
gsap.timeline（{onUpdate：myFunction、onUpdateParams：["param1"、 "param2"]}）;
```




### Timelineのオプション

#### autoRemoveChildren
ブーリアン型
「true」の場合、子Tween/Timelineが完了するとすぐに、自動的に強制終了/削除
※ルートのタイムラインはautoRemoveChildren：trueになっている



#### delay
数値型
アニメーションが開始されるまでの時間(秒単位)


#### pause
ブーリアン型
trueの場合、アニメーションは作成直後に一時停止


#### repeat
数値型
アニメーションが最初の反復後に繰り返される回数
繰り返しが1の場合、アニメーションは合計2回再生される(最初の再生と1回の繰り返し)
無限に繰り返すには、-1

#### repeatDelay	
数値型
リピート間の長さ(秒単位)


#### repeatRefresh
ブーリアン型
trueを設定すると、繰り返しタイムラインがすべての子Tweenをinvalidate()し、完全な反復ごとに内部的に開始/終了値を再記録(yoyoを除く)



#### smoothChildTiming
ブーリアン型
タイミング関連のプロパティがオンザフライで変更されたときにスムーズな再生を維持するために、子アニメーションを自動的に再配置す(startTimeを変更する)かどうかを制御



#### yoyo
ブーリアン型
trueならyoyoを有効化

## Effects

Effectsを使うと、「ターゲット」と「configオブジェクト」を引数に持つ関数にラップされたカスタムアニメーションを作成できます


### effectsの作成

```.html
<div class="box">box</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
}
```


```.js
import { gsap } from "gsap";
  
//effectを作成
gsap.registerEffect({
  name: "zoomIn",

  //未指定の場合のデフォルト値の指定
  defaults: { duration: 0.5, scale: 1 },

  effect: (targets, config) => {
    return gsap.to(targets, {
      duration: config.duration,
      scale: config.scale,
      ease: "expo",
    });
  },

  //extendTimelineをtrueにするとGSAPタイムラインで使える
  extendTimeline: true,
});
```

### effectsの使用

#### 単発で使う

```.js
gsap.effects.zoomIn(".box", { scale: 1.5 });
``` 

#### タイムライン上で使う

```.js
const tl = gsap.timeline();
 
tl
  //zoomInエフェクト
  .zoomIn(".box", { scale: 1.5 })
  //Tween
  .to(".box", { y: 100 }, "+=1")
 
  //zoomInエフェクト
  .zoomIn(".box", { scale: 1 }, "+=1");
``` 

#### Hoverエフェクトとして使う

例：boxクラスを持つ要素すべてで、mouseenterイベント発生時にzoomInエフェクトを適用

```.js
document.querySelectorAll(".box").forEach((box) => {
  box.addEventListener("mouseenter", () => {
    gsap.effects.zoomIn(box, { duration: 0.2, scale: 1.5 });
  });
});
``` 
 
#### クリックイベントとして使う
例：boxクラスを持つ要素すべてで、clickイベント発生時にzoomInエフェクトを適用

```.js
document.querySelectorAll(".box").forEach((box) => {
  box.addEventListener("click", () => {
    gsap.effects.zoomIn(box, { duration: 0.2, scale: 1.5 });
  });
});
``` 
 


## TweenとTimelineの制御


### メソッド
|メソッド|内容|
|---|---|
|pause()|停止|
|play()|再生(pause時はその場所から続きを再生)|
|progress()|アニメーションの進行状況を0～1の間で返す　引数を渡すと、その位置に移動|
|restart()|最初から再生|
|resume()|続きから再生|
|reverse()|逆再生|
|seek(数値)|タイムラインを指定の位置に移動(数値以外にラベルも指定可能)|
|time()|現在の位置を取得　引数を渡すと、その位置に移動|
|duration()|アニメーションの長さを取得 引数を渡すとその長さになるようにtimeScaleが調整される|
|timeScale()|引数倍速にする|



### サンプルコード

####共通のHTMLとCSS

```.html
<button id="pause">pause</button>
<button id="play">play</button>
<button id="progress">progress</button>
<button id="restart">restart</button>
<button id="resume">resume</button>
<button id="reverse">reverse</button>
<button id="seek">seek</button>
<button id="time">time</button>
<button id="duration">duration</button>
<button id="timeScale2">timeScale(2)</button>
<button id="timeScale1">timeScale(1)</button>
 
<div class="box">box</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
}
```


#### Tween制御のJavaScript

```.js
import { gsap } from "gsap";
 
//Tween作成
const tw = gsap.fromTo(
  ".box",

  {
    x: 0,
  },

  {
    x: 1000,
    duration: 10,
    repeat: -1,
  }
);
//IDpauseを持つ要素で、clickイベント発生時Tweenを停止
document.querySelectorAll("#pause").forEach((pause) => {
  pause.addEventListener("click", () => {
    tw.pause();
  });
});

//IDplayを持つ要素で、clickイベント発生時Tweenを再生
document.querySelectorAll("#play").forEach((play) => {
  play.addEventListener("click", () => {
    tw.play();
  });
});

//IDprogressを持つ要素で、clickイベント発生時Tweenの進行状況を取得(0が先頭、1が完了)
document.querySelectorAll("#progress").forEach((progress) => {
  progress.addEventListener("click", () => {
    console.log(tw.progress());
  });
});

//IDrestartを持つ要素で、clickイベント発生時Tweenを最初から再生
document.querySelectorAll("#restart").forEach((restart) => {
  restart.addEventListener("click", () => {
    tw.restart();
  });
});

//IDresumeを持つ要素で、clickイベント発生時Tweenが停止している場合、続きからから再生
document.querySelectorAll("#resume").forEach((resume) => {
  resume.addEventListener("click", () => {
    tw.resume();
  });
});

//IDreverseを持つ要素で、clickイベント発生時Tweenを逆再生
document.querySelectorAll("#reverse").forEach((reverse) => {
  reverse.addEventListener("click", () => {
    tw.reverse();
  });
});
 
//IDseekを持つ要素で、clickイベント発生時Tweenを指定した時間に移動
document.querySelectorAll("#seek").forEach((seek) => {
  seek.addEventListener("click", () => {
    //2秒時点に移動
    tw.seek(2);
  });
});
//IDtimeを持つ要素で、clickイベント発生時Tweenの現在位置を取得
document.querySelectorAll("#time").forEach((time) => {
  time.addEventListener("click", () => {
    //タイムラインの現在位置を取得
    console.log(tw.time());
  });
});

//IDdurationを持つ要素で、clickイベント発生時Tweenを
document.querySelectorAll("#duration").forEach((duration) => {
  duration.addEventListener("click", () => {
    //タイムラインのdurationを取得
    console.log(tw.duration());
  });
});
 
//IDtimeScale2を持つ要素で、clickイベント発生時Tweenを2倍速にする
document.querySelectorAll("#timeScale2").forEach((timeScale) => {
  timeScale.addEventListener("click", () => {
    //2倍速にする
    tw.timeScale(2);
  });
});

//IDtimeScale1を持つ要素で、clickイベント発生時Tweenを1倍速にする
document.querySelectorAll("#timeScale1").forEach((timeScale) => {
  timeScale.addEventListener("click", () => {
    //1倍速にする
    tw.timeScale(1);
  });
});
```



#### Timeline制御のJavaScript

```.js
import { gsap } from "gsap";

//timeline作成
const tl = gsap.timeline({ repeat: 2, repeatDelay: 1 });

tl.to(
  ".box",

  {
    x: 400,
  },
  1
)

.to(
  ".box",
  {
    y: 400,
  },
  2
)
 
.to(
  ".box",
  {
    x: 0,
  },
  3
)
 
.to(
  ".box",
  {
    y: 0,
  },
  4
);

//IDpauseを持つ要素で、clickイベント発生時timelineを停止
document.querySelectorAll("#pause").forEach((pause) => {
  pause.addEventListener("click", () => {
    tl.pause();
  });
});

//IDplayを持つ要素で、clickイベント発生時timelineを再生
document.querySelectorAll("#play").forEach((play) => {
  play.addEventListener("click", () => {
    tl.play();
  });
});

//IDprogressを持つ要素で、clickイベント発生時timelineの進行状況を取得(0が先頭、1が完了)
document.querySelectorAll("#progress").forEach((progress) => {
  progress.addEventListener("click", () => {
    console.log(tl.progress());
  });
});

//IDrestartを持つ要素で、clickイベント発生時timelineを最初から再生
document.querySelectorAll("#restart").forEach((restart) => {
  restart.addEventListener("click", () => {
    tl.restart();
  });
});

//IDresumeを持つ要素で、clickイベント発生時timelineが停止している場合、続きからから再生
document.querySelectorAll("#resume").forEach((resume) => {
  resume.addEventListener("click", () => {
    tl.resume();
  });
});

//IDreverseを持つ要素で、clickイベント発生時timelineを逆再生
document.querySelectorAll("#reverse").forEach((reverse) => {
  reverse.addEventListener("click", () => {
    tl.reverse();
  });
});

//IDseekを持つ要素で、clickイベント発生時timelineを指定した時間に移動
document.querySelectorAll("#seek").forEach((seek) => {
  seek.addEventListener("click", () => {
    //2秒時点に移動
    tl.seek(2);
  });
});
//IDtimeを持つ要素で、clickイベント発生時timelineの現在位置を取得
document.querySelectorAll("#time").forEach((time) => {
  time.addEventListener("click", () => {
    //タイムラインの現在位置を取得
    console.log(tl.time());
  });
});
 
//IDdurationを持つ要素で、clickイベント発生時timelineを
 document.querySelectorAll("#duration").forEach((duration) => {
  duration.addEventListener("click", () => {
    //タイムラインのdurationを取得
    console.log(tl.duration());
  });
});

//IDtimeScale2を持つ要素で、clickイベント発生時timelineを2倍速にする
document.querySelectorAll("#timeScale2").forEach((timeScale) => {
  timeScale.addEventListener("click", () => {
    //2倍速にする
    tl.timeScale(2);
  });
});

//IDtimeScale1を持つ要素で、clickイベント発生時timelineを1倍速にする
document.querySelectorAll("#timeScale1").forEach((timeScale) => {
  timeScale.addEventListener("click", () => {
    //1倍速にする
    tl.timeScale(1);
  });
});
``` 
 

## Stagger

要素のグループ(同じクラス名など)を完全に同じではなく、バリエーションを変えて動かすことができます


### 数値での指定

例：boxクラスを持った全ての要素がx軸方向に50px移動するアニメーション
(各要素のアニメーションは0.5秒間隔で開始)

```.html
<div class="box">box1</div>
<div class="box">box2</div>
<div class="box">box3</div>
<div class="box">box4</div>
<div class="box">box5</div>
<div class="box">box6</div>
<div class="box">box7</div>
<div class="box">box8</div>
<div class="box">box9</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
  overflow: hidden;
  padding: 10px;
  word-break: break-all;
}
``` 

```.js
import { gsap } from "gsap";

gsap.to(".box", {
  x: 200,
  //各要素を0.5秒間隔で再生開始
  stagger: 0.5,
});
```


### より高度なStagger

Staggerオブジェクトを使用します。


```.js
gsap.to(".box", {
 x: 20,
 
 //staggerオブジェクト
 stagger: { 
 　each: 1,
 　
 　//最後の要素から再生
 　from: "end",　
 }
});
```





#### amount

数値型
すべてのStaggerの間で分割される合計時間(秒単位)
amountが1で、直線的にずれている要素が100個ある場合
各サブTweenの開始時間の間隔は0.01秒になる
各Tweenの間に特定の時間を指定する場合は、代わりにeachプロパティを使う


#### each
数値型
Staggerを数値で指定していた、アニメーション開始の間隔(秒単位)
Staggerに分割する合計時間を指定する場合は、eachではなくamountプロパティを使う


#### from
文字列型 | インテジャー型 | 配列型
Staggerが発生する配列内の位置

特定の要素から始めるには、ターゲット配列内のその要素のインデックスを表す番号を指定する
from:4は、配列の5番目の要素でstaggerを始める(配列はゼロベースのインデックスを使用するため)
各要素のアニメーションは、配列内の「from」値への要素の近接度に基づいて開始される
(要素が近いほど、開始が早くなる)

##### fromプロパティに指定できるキーワード

|キーワード|内容|
|---|---|
|"start"|最初の要素から再生|
|"center"|真ん中の要素から再生|
|"edges"|端の要素から再生|
|"random"|ランダムな順番で再生|
|"end"|最後の要素から再生|


グリッドを定義している場合は配列を使う
`[0.5,0.5]`が中央、`[1,0]`が右上隅など、各軸の進行状況を示す10進値を指定できる
デフォルト：0


#### grid
配列型 | "auto"キーワード
要素がグリッドに視覚的に表示されている場合

|値の例|内容|
|---|---|
|grid:[9,15]|行と列の数を示す|
|grid:"auto"|行と列を自動的計算(レスポンシブレイアウトに適す)|



#### axis
文字列型
Gridを定義する場合、staggerは、x軸とy軸の両方の「from」値までの各要素の合計距離に基づいているが、1つの軸(「x」か「y」のどちらか)だけに焦点を合わせることができる

#### ease	
文字列型 | ファンクション型
イージングの指定
デフォルト：「"none"」




### Staggerのイージングとリピート
Staggerオブジェクトの中に書くか外に書くかの違いでアニメーションに違いが出てきます





#### イージング

|外/中|内容|
|---|---|
|外に書いた場合|イージングがそれぞれの要素に掛かる(各要素は同じ動き)|
|中に書いた場合|全体の動きに対してイージングが掛かる(各要素の動きに差異が出る)|

##### 外

```.js
 import { gsap } from "gsap";
 
 gsap.to(".box", {
   x: 200,
 
   ease: "power2.inOut",
   stagger: {
     each: 0.5,
   },
 });
```

##### 中

```.js
import { gsap } from "gsap";

gsap.to(".box", {
  x: 200,
  stagger: {
    each: 0.5,
    //staggerオブジェクトの中に書いた場合
    ease: "power2.inOut",
  },
});
``` 

#### リピート

|外/中|内容|
|---|---|
|外に書いた場合|全の要素のアニメーションが終わってから2週目のアニメーション|
|中に書いた場合|前の要素のアニメーションが終わったら即、次の要素のアニメーション|



##### 外

```.js
import { gsap } from "gsap";

gsap.to(".box", {
  x: 200,
 
  //staggerオブジェクトの外に書いた場合
  repeat: -1,
  stagger: {
    each: 0.5,
  },
});
```
##### 中

```.js
import { gsap } from "gsap";

gsap.to(".box", {
  x: 200,
  stagger: {
    each: 0.5,
    //staggerオブジェクトの中に書いた場合
    repeat: -1,
  },
});
``` 
 

## コアプラグイン
コアに含まれていて、インポートとレジスト不要なので、プラグインを使っている感覚無しで使えます

|名前|内容|
|---|---|
|AttrPlugin|属性の変更によるアニメーション|
|CSSPlugin|CSSのプロパティ変更によるアニメーション|
|EndArrayPlugin|配列をTween|
|ModifiersPlugin|モディファイア関数|
|SnapPlugin|値のスナップ|



### AttrPlugin

DOM要素の任意の数値属性をTweenできます
「%」のような接尾辞がある場合は保持されます

#### サンプルコード

```.html
<textarea id="textarea" cols="30" rows="10"></textarea>
```

```.js
import { gsap } from "gsap";

gsap.to("#textarea", {
  duration: 1,
  attr: { rows: 20, cols: 50 },
  ease: "none",
  repeat: -1,
});
``` 



### EndArrayPlugin

イージングを適用して、数値の配列を別の数値の配列にTweenできます
長さが不均一な配列がある場合は、両方の配列にあるインデックスのみがアニメーション化されます

#### サンプルコード

```.js
import { gsap } from "gsap";

const arr = [1, 2, 3];

gsap.to(arr, {
  endArray: [5, 6, 7],
  onUpdate() {
    console.log(arr)
  }
});
```

### CSSPlugin
紹介したCSSのプロパティによるアニメーションは、実はこのプラグインが使われています。



### ModifiersPlugin
あるオブジェクトのxを別のオブジェクトのyに基づいて変更したり、回転を移動方向に基づいて変更したりすることができます

モディファイア関数には、次の2つのパラメーターが渡されます


#### value
数値型 | 文字列型
標準のTweenから適用される予定の値

値の例

- xプロパティをアニメーション化する場合は数値
- leftプロパティをアニメーション化する場合は`"212px"`のような値
- boxShadowプロパティの場合は`"10px 5px 10px rgb(255,0,0)"`のような値


#### target
オブジェクト型
ターゲット自身



#### サンプルコード

```.html
<div class="box">box</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
  overflow: hidden;
  padding: 10px;
  word-break: break-all;
}
``` 

```.js
import { gsap } from "gsap";

const degrees = 45;

gsap.to(".box", {
  rotation: 180,
  x: 200,
  duration: 1,
  repeat: -1,

  modifiers: {
    rotation: gsap.utils.unitize(function (rotation) {
      //45度にスナップする
      return Math.round(rotation / degrees) * degrees;
    }),
  },
});
```



### SnapPlugin

Tweenを特定の配列または増分で最も近い値にスナップできます
基本的に、Tween中のすべての値(終了値だけでなくライブ)に次のスナップ動作のいずれかを実装するプロパティにモディファイアを追加します
スナッププロパティはいくつでも定義できます

#### サンプルコード

```.html
<div class="box">box</div>
```

```.css
.box {
  align-items: center;
  background-color: red;
  color: white;
  display: flex;
  font-weight: bold;
  justify-content: center;
  height: 100px;
  width: 100px;
  overflow: hidden;
  padding: 10px;
  word-break: break-all;
}
``` 

```.js
import { gsap } from "gsap";

gsap.to(".box", {
  x: 1000,
  y: 400,
  rotate: 360,
  snap: {
    //100ごとにスナップ
    x: 100,

    //指定した数でスナップ
    //x: [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],

    //指定した数でスナップ(特定の距離内にある場合のみ)
    // x: {
    //   values: [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
    //   radius: 50,
    // },
  },
  duration: 1,
  repeat: -1,
});
``` 


## その他のプラグイン

この記事では扱いませんが、他にも多様なプラグインが用意されています

### Extra Plugins
誰でも使える
別途インポートとレジストが必要です

- Observer
- Draggable
- Easel
- Flip
- MotionPath
- Pixi
- ScrollTo
- ScrollTrigger
- TextPlugin	

### Club Plugins

Club GreenSockメンバーのみ使用可能なもの
使用には、会員(年会費)の支払いが必要です


- DrawSVG
- ScrollSmoother
- GSDevTools
- Inertia
- MorphSVG
- MotionPathHelper
- Physics2D
- PhysicsProps
- ScrambleText
- SplitText

### Extra Eases

- EasePack
  - ExpoScaleEase
  - RoughEase
  - SlowMo
- CustomEase
- CustomBounce
- CustomWiggle