はじめに
AngularJSを少しでも触ったことのある方なら、データバインディングによって簡単に動的なWebページが作れるのはご存じでしょう。
本稿では、動的に変化させるWebページにCSS Transitionsを使ったアニメーションを加えることで、Webページの見た目にも動きを加えるテクニックについて紹介したいと思います。
Transitionとは遷移といった意味です。
CSS Animationsという規格も存在するんですが、CSS Animationsは繰り返しのあるアニメーションの表現に強いです。
CSS TransitionsはCSSプロパティの値の変更、つまり遷移を、一瞬の切り替わりではなく連続的な変化で表現します。
AngularJSのバージョンは1.4.8で確認しています。
ngAnimate
AngularJSでアニメーションといえばまずngAnimateが思い浮かぶと思います。
はじめにngAnimateとCSS Transitionsの関係から紹介しましょう。
さて、ngAnimateのドキュメントを見ると「CSS-based Animations」の説明から入っています。
簡単なサンプルを示しましょう。
まずはアニメーションなしで、ngShowを使ってチェックボックスの値に応じて要素の表示非表示を切り替えるコードです。
<div ng-app="app">
<div ng-controller="MainController">
<button ng-click="toggleShow()">toggle</button>
<div class="message" ng-show="show">
hello
</div>
</div>
</div>
var MainController = function ($scope) {
$scope.show = false;
$scope.toggleShow = function () {
$scope.show = !$scope.show;
};
};
angular.module('app', [])
.controller('MainController', MainController);
https://jsfiddle.net/xj7fz3fz/ で動作確認できるようにしています。
今はチェックボックスの値を変えると、即座に表示のオンオフが切り替わっています。
これを、徐々に透明になるように、あるいは透明な状態から徐々に現れてくるように変更します。
はじめに、ngAnimateの依存モジュールへの追加を行います。
angular-animateをscriptタグなどで読み込むのを忘れないでください。
angular.module('app', ['ngAnimate'])
.controller('MainController', MainController);
次にスタイルを追加します。
.message {
opacity: 1;
}
.message.ng-hide-add, .message.ng-hide-remove {
transition: all linear 0.5s;
}
.message.ng-hide {
opacity: 0;
}
これだけでアニメーションの追加が行えます。
動作は https://jsfiddle.net/t8j818xo/ で確認できます。
少しだけ解説をしましょう。
スタイルの方はAngularJS独自の要素は何もない標準のCSSです。
transition
プロパティがCSS Transitionsのキモとなります。
transition
プロパティは、transition-property
、transition-duration
、transition-timing-function
、transition-delay
の4つのプロパティの省略表記です。
上の例ではall linear 0.5s
と3つの値を与えていて、順にtransition-property
、transition-timing-function
、transition-delay
に対応しています。
transition-peroperty
では、アニメーション対象にするCSSプロパティを指定します。
上の例ではall
を与えているので全てのCSSプロパティを対象とします。
上の例ではopacity
のみを変化させているので、all
の代わりにopacity
と書くこともできます。
transition-duration
はアニメーションの時間を指定します。
上の例では0.5s
を与えていて、opacity
の値が0から1に、あるいは1から0に0.5秒かけて連続的に変化します。
transition-timing-function
では、CSSプロパティの変化の仕方を指定します。
上の例ではlinear
を与えているので、アニメーション開始時点から終了時点までプロパティを線形に変形します。
上の例ではtransition-delay
が0.5s
なので、アニメーション開始から0.25秒後のopacity
の値は大体0.5になります。
他にも組み込みのtiming functionが存在しているので詳しくは http://www.w3.org/TR/css3-transitions/#transition-timing-function-property などを参照してください。
ngAnimateの話に戻ります。
ngAnimateを読み込んでいると、ngShowやngIf、ngRepeat、ngViewといったいくつかのディレクティブで要素が変化するときにclass
の追加や削除が行われるようになります。
ngShowでは、要素が非表示のときにng-hide
がclass
に追加されます。
ngAnimateを読み込んでいると、ngShowの値がtrueからfalseに切り替わるときにng-hide-add
、falseからtrueに切り替わるときにng-hide-remove
が一瞬だけclass
に追加されます。
そのタイミングでtransition
プロパティを適用することでアニメーションを実現しています。
CSS Transitions
ngAnimateではCSS Transitionsを使うことで少ない記述でWebページにアニメーションを追加できることが確認できました。
CSS Transitionsは非常に強力で、ngAnimateを使わなくても便利になる場面があります。
例えば、ある要素の座標をCSSのtransform
プロパティで設定してるとして、Scope中の変数の値でtransform
プロパティの値が変化するとしましょう。
HTMLとJavaScript、CSSは以下のようなコードになります。
<div ng-app="app">
<div ng-controller="MainController">
<div>
<label>x</label><input type="range" min="0" max="500" step="50" ng-model="x">
</div>
<div>
<label>y</label><input type="range" min="0" max="500" step="50" ng-model="y">
</div>
<div class="message" ng-style="messageStyle()">
hello
</div>
</div>
</div>
var MainController = function ($scope) {
$scope.x = 50;
$scope.y = 50;
$scope.messageStyle = function () {
return {
transform: 'translate(' + $scope.x + 'px,' + $scope.y + 'px)'
};
};
};
angular.module('app', [])
.controller('MainController', MainController);
.message {
width: 50px;
height: 50px;
background-color: red;
}
xとyをバインディングしているだけの単純なコードです。
input要素でxとyを変更すると即座にmessageの位置が変化すると思います。
ここで、CSSにCSS Transitionsの記述を以下のように追加します。
.message {
width: 50px;
height: 50px;
background-color: red;
transition-property: transform;
transition-duration: 1s;
}
動作確認は https://jsfiddle.net/hyuavLkn/1/ でできます。
messageの位置がアニメーションで連続的に変化するようになりました。
このようにngAnimateを使わない場合でも、AngularJSのデータバインディングとCSS Transitionsを組み合わせることで面白い動きのWebページが簡単につくれます。
おわりに
私は普段から可視化アプリケーションの開発を行っているんですが、ユーザーの操作による可視化結果の変化をアニメーションで表現することは当たり前になっています。
可視化のライブラリといえばD3.jsが有名だと思いますが、私の場合はアプリケーションの大規模化につれて開発が苦しくなってきたので、AngularJSなどを使って可視化部分の開発も行うようになってきました。
D3.jsが持っているアニメーションの機能は非常に強力なのですが、AngularJSでは可視化のためのアニメーションという点ではサポートがほとんどありません。
しかし、CSS Transitionsを使うことで、AngularJSでもD3.jsにも負けない強力なアニメーション表現ができるようになるので覚えてみて損はないかと思います。