vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

AngularのAnimate

はじめに

前回に続いてAngular.jsのお話。

昔Angular.jsの弱点としてアニメーションが挙げられていた気がしていたので(別のものと混同している恐れもあります)、
ちょこっと調べてみたところver.1.14位からちゃんと対応されていました。

というわけで今回は、公式ドキュメントを中心に試してみたことをメモることにします。

あ、ちなみに扱うのはver.2系だけです。

アニメーションさせてみる

まずはボタンをクリックした時に、ボタンのサイズ変更、及び背景色を変更するサンプルを試してみました。

前回作成したプロジェクトに、「ng g component gui-anime」でコンポーネントを追加し、それをあれこれいじっています。

まずはコードから。

Htmlにアニメーションのターゲット兼トリガーとなるボタンを追加し、
Typescript側でアニメーションとアニメーション開始のトリガーとなる要素(State)を作成します。

gui-anime.component.html

< p>
  gui-anime works!
< /p>
< button [@buttonState]="state" (click)="onAnimeButtonClicked()">Anime< /button>

gui-anime.component.ts

import { Component,
  Input,
  trigger,
  state,
  style,
  transition,
  animate,
  OnInit } from '@angular/core';

@Component({
  selector: 'app-gui-anime',
  templateUrl: './gui-anime.component.html',
  styleUrls: ['./gui-anime.component.css'],
  
  animations: [
    trigger('buttonState', [
      state('inactive', style({
        backgroundColor: '#eee',
        transform: 'scale(1)'
      })),
      state('active',   style({
        backgroundColor: '#cfd8dc',
        transform: 'scale(1.5)'
      })),
      transition('inactive => active', animate('100ms ease-in')),
      transition('active => inactive', animate('100ms ease-out'))
    ])
  ]
  
})
export class GuiAnimeComponent implements OnInit {
  public state: string;
  constructor() { }
  
  ngOnInit() {
    this.state = "inactive";
  }
  private onAnimeButtonClicked(){
    this.state = (this.state === "active")? "inactive": "active";
  }
}

イベント

Angularではクリックなどのイベントは()で囲まれます。

今回はボタンクリックのイベントを取得したいため、gui-anime.component.htmlで「(click)」を設定しています。

(click)="onAnimeButtonClicked()"

アニメーションのトリガーとなる要素(State)の指定と値の変更

上記のコードでは、クリックしたらアニメーションが始まるのではなく、gui-anime.component.tsで設定している「buttonState」が特定の値(inactive、active)に変更された場合に開始されるようになっています。

これをボタンに設定して、クリックイベントで「state」の中身を入れ替える、という処理を行っています。

[@buttonState]="state"

[@〜]とすることで、コンポーネントの持つ要素(今回はアニメーションのトリガーとなる「buttonState」)の「state」との関連付けができるようです。

[]は下記のPropertyBindingか?とも思うのですが、確信が持てず。。。
この辺りは追って調べてみることにします。

アニメーション

さて、今回のメインであるアニメーションです。

animations: [
    trigger('buttonState', [
      state('inactive', style({
        backgroundColor: '#eee',
        transform: 'scale(1)'
      })),
      state('active',   style({
        backgroundColor: '#cfd8dc',
        transform: 'scale(1.5)'
      })),
      transition('inactive => active', animate('100ms ease-in')),
      transition('active => inactive', animate('100ms ease-out'))
    ])
  ]

ここでは2つのstateが指定されており、
先ほど登場した「buttonState」の値が「inactive」または「active」(それぞれのstateの第一引数)に変更された時に、
第二引数でそれぞれ指定しているCSSの値(背景色、スケール値)が適用される内容となっています。

で、その後ろに連なる2つのtransitionによって、「inactive」から「active」またはその逆への変化がアニメーションで繋げられる、という処理が行われます。

transitionの第二引数にてアニメーションの時間と後述するEaseTypeが指定されています。

EaseType

transitionで指定されているEaseType。

これを指定することで、アニメーション(今回は拡大・縮小)する速度が一定ではなく最初だけゆっくり(ease-in)や、最後だけゆっくり(ease-out)といった変化をつけることができます。

UnityのTween系でも登場しますね。
そちらでは覚えきれない位たくさんの種類のEaseTypeから目的に合致したものを利用することができます。

ではAngularではどうかというと、実は今回使っているアニメーション、というのはAngular独自のものではなくCSSのアニメーションです。

で、CSSで使用できるものはというと、下記のみです。

  • ease(デフォルト)
  • linear(はじめから終わりまで一定)
  • ease-in(最初だけゆっくり)
  • ease-out(最後だけゆっくり)
  • ease-in-out(最初と最後だけゆっくり)
  • cubic-bezier()(カスタム)

SCSSなどであればEasing Function 早見表で紹介されているようなEaseTypeが使えるようなのですが、
CSSでは種類がかなり少ない(またはカスタムで作成する)ようです。

カスタムについては次回辺りためしてみたいと思います。

アニメーションの開始・終了イベント

複数のアニメーションを連続で実行したい、アニメーションの実行後に何か処理をしたい、といった場合に、それを検知するイベントが欲しいところ。

そのような場合は、クリックイベントのように「start」「done」イベントを設定します。

Start

< button [@buttonState]="state" 〜省略〜(@buttonState.start)="onAnimeStarted()">Anime< /button>

Done

< button [@buttonState]="state" 〜省略〜(@buttonState.done)="onAnimeFinished()">Anime< /button>

アニメーションのトリガーである「buttonState」に紐付けられていますね。

あとはクリックイベントと同じく、gui-anime.component.tsに「onAnimeStarted()」や「onAnimeFinished()」を追加するだけです。

参考

Animation

EaseType