Angular Animations (+v4) メモ

[Angular Workshop - Animations](https://www.meetup.com/ja-JP/angular-tokyo/events/240809331/)に参加してきたので忘れないうちにメモ。
スライドは http://slides.com/gerardsans/ng-japan-animations#/ です。
Gerardさんの説明がわかりやすく途中に手を動かす練習問題もあって大変良かったです :pray:

# Angular Animationって？

- [Web Animations API](https://w3c.github.io/web-animations/)の上に実装されている
    - まだ実装していないブラウザもあるのでそのときは[polyfill](https://github.com/web-animations/web-animations-js)を使う
    - Web Animations APIはローレベルでできないこともあるので、Angular Animationを作った
- CSS Transitions, CSS Animationsと似たAPI

# CSS Transitions

- 初期状態・終了状態を定義する
- 途中の状態は自動的に計算される
- アニメーションするプロパティを指定する
- アニメーションは計算コストが高い
    - opacity, transformがオススメ（って言ってた気がする）
- `transition: color 5s ease-in 1s;`
    - `color` アニメーションするプロパティ
    - `5s` アニメーションにかける時間(duration)
    - `ease-in` アニメーションの値の変化(timing)
    - `1s` アニメーション開始を遅らせる時間(delay)
- ease-inとかcubic-bezierとかを理解するのに便利なサイト
    - http://cubic-bezier.com

# CSS Animations

- CSS TransitionにKeyframeを追加したようなやつ
- 初期状態・終了状態の間に中間状態を任意の数定義できる
- その中間状態の間は自動的に計算される
- `animation: fade 5s 1s infinite linear`
    - `fade` アニメーション名、別のところで `@keyframes fade {...}` を定義
    - `5s` アニメーションにかける時間(duration)
    - `1s` アニメーション開始を遅らせる時間(delay)
    - `infinite` アニメーションの繰り返し(iterations)
    - `linear` アニメーションの値の変化(timing)

```css
@keyframes fade {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}
```

- [codepenのデモ](https://codepen.io/gsans/pen/EmwyqL)

# Angular Animations

- 基本はCSS Transitionsのように状態と、状態の間の遷移を定義する
- `fadeIn` `fadeOut` のような文字列で状態を定義
- 状態の遷移を矢印で表した文字列で定義
    - `fadeIn => fadeOut`
    - `fadeIn <= fadeOut`
    - `fadeIn <=> fadeOut`
- `void` と `*` は特殊なキーワード
    - `void` は要素が画面からなくなっている状態
    - `*` は `void` を含む全ての状態
- `:enter` は `void => *` のショートハンド
- `:leave` は `* => void` のショートハンド

- animationは別モジュールなのでnpmインストール、TSでのインポートが必要
    - `npm i @angular/animations`
    - `@NgModule({ imports: [ BrowserAnimationModule ], ... })`

## Animation Example

```ts
@Component({
  selector: 'my-app',
  template: `<button [@fade]='fade' (click)="toggleFade()">Fade</button>`,
  animations: [ trigger('fade', [
    state('fadeIn', style({ opacity: 1 })),
    state('fadeOut', style({ opacity: 0.1 })),
    transition('fadeIn <=> fadeOut', animate('2000ms linear'))
  ])]
})
export class App {
  fade = 'fadeIn';
  toggleFade(){
    this.fade = this.fade === 'fadeIn' ? 'fadeOut' : 'fadeIn';
  }
}
```

- `[@fade]`
    - アニメーションする要素のプロパティにアニメーションをバインディング
    - `@` がアニメーションを意味するプレフィックス
    - `[@fade]` は `trigger('fade', ...)` のアニメーションを指定している
    - `[@fade]="fade"`の右辺は状態を表す文字列が入っているAppクラスの変数を指している。toggleFadeで文字列が入れ替わって、その文字列に当たる状態へのtransitionが始まる
- `animations`
    - アニメーションの状態を `state` で定義
    - 状態の間の遷移を `transition` で定義
- [デモ](https://plnkr.co/edit/QvG8I73sgQ5ox4LZhGwZ?p=preview)

## Keyframes Example

```ts
export const grow = trigger('grow' , [
  state('small', style({ transform: 'scale(1)' })),
  state('large', style({ transform: 'scale(1.4)' })),
  transition('small <=> large', animate('200ms linear', keyframes([
      style({transform: 'scale(1.6)', offset: 0}),
      style({transform: 'scale(1.4)', offset: 1})
    ])
  ))
])
```

- `keyframes` の中に2つ並べるとそれぞれ初期、終了状態
- 複数並べると等分されていく
    - 別途どの位置に来るかをoffsetで明示できる
    - `style({opacity: 1, transform: 'translateX(15px)',  offset: 0.3})`

## Animation Callbacks

```ts
import {fade} from './animations';

@Component({
  selector: 'my-app',
  template: `<img [@fade]='fade' 
    (@fade.start)="start($event)" 
    (@fade.done)="done($event) >`,
  animations: [ fade ]
})
export class App {
  start(e) { }
  done(e) { }
}
```

- (この例みたいにアニメーションを別ファイルに定義するのがComponentがでかくなりすぎないのでベストプラクティスだった言ってた気がする)
- start, doneのコールバックがある
- `$event` のペイロードのかたち

```
$event == {
  element: any,        // div element
  triggerName: string, // "fade"    
  phaseName: string    // "start" or "done"
  fromState: string,   // "in" or "out"
  toState: string,     // "in" or "out"
  totalTime: number,   // 1000 (milliseconds)
}
```

- [デモ](http://plnkr.co/edit/XgP0TamK5CuAGkqM3RoR?p=preview)

## New in Angular 4.2

後日。。。