これでできる! クロスブラウザJavaScript入門

第17回 アニメーションの基礎

この記事を読むのに必要な時間:およそ 4 分

こんにちは,太田です。3回ほどJavaScriptの基礎的な内容が続いたので,今回はグラフィカルなアニメーションについて解説します。グラフィカルなJavaScriptというと,難しい・応用的なイメージがあるかもしれませんが,JavaScriptでのアニメーションとはすなわちCSSを段階的に操作するということで,そのポイントを抑えれば中身は単純なものです。

アニメーションの前提知識

HTMLにおける通常のアニメーションを構成するのは,⁠特定の要素」に対して,⁠そのCSSプロパティ」「ある時点からある時点まで」の時間の中で,⁠ある値からある値に操作」する,といった要素です。

特定の要素と,CSSプロパティについては問題ないと思います。問題となるのは「時間と値の操作」です。

まず,単純にインクリメントするだけというサンプルを見てみましょう。

良くないアニメーション

var y = 0;
var element = document.getElementById('cbjs-17-1');
var id = setInterval(function(){
  y++;
  element.style.top = y/10 + 'px';
  if (y === 1000){
    clearInterval(id);
  }
}, 1); // 1ms置きに実行

単純計算で言えば,1ms置きに1000回インクリメントしているので,1秒間の処理となるはずですが,実際には1秒間に1000回もの描画(1000FPS)を行うことはまず不可能です。このままでは実行される環境に大きく依存した(低スペックな環境では極端に遅い)アニメーションになってしまいます。

そこで,開始時刻から経過した時間で現在の位置を決め,その位置に移動させる方法が一般的です。

つまり,1秒間で100px移動させたい場合なら,300msの時点では30px移動していればよく,500msでは50px,1000msを超えたら100pxにしてアニメーションを終了すればよい,ということです。時間を基準にすれば,時間通りにアニメーションが終わるというごく当たり前なことです。

修正版アニメーション

var begin = new Date() - 0;
var element = document.getElementById('cbjs-17-2');
var id = setInterval(function(){
  var current = new Date() - begin;
  if (current > 1000){
    clearInterval(id);
    current = 1000; // 1000以上になっているので,調整する
  }
  element.style.top = current / 10 + 'px';
}, 10); // 10ms置きに実行

この方法ではハイスペックな環境では滑らかなアニメーションに,ロースペックな環境では最低限のアニメーションになります。

アニメーションの汎用化とEasing関数

さて,上記の実装では汎用性がないので,もう少し使い回しができるようにしてみましょう。特に,直線的な動きだけでなく,動きにバリエーションを増やしたいと思います。その際によく使われるのがEasing関数と呼ばれるものです。

Easing関数とは,⁠主に)経過時間,初期値,変動値,継続時間の4つの変数から現在の値を求めることができる関数です。

Easing関数版アニメーション

function easing(time, from, distance, duration){
  return distance * time / duration + from;
}
var begin = new Date() - 0;
var element = document.getElementById('cbjs-17-3');
var from = 0; // 初期値
var distance = 100; // 変動値
var duration = 1000; // 継続時間
var id = setInterval(function(){
  var time = new Date() - begin; // 経過時間
  var current = easing(time, from, distance, duration);
  if (time > duration){
    clearInterval(id);
    current = from + distance;
  }
  element.style.top = current + 'px';
}, 10); // 10ms置きに実行

easing関数は自作もできますが,よく使われるのはActionScriptのライブラリであるTweenerがサポートしている関数群です。Tweener Documentation and Language Referenceにそのサンプルがあります。

JavaScriptから扱う場合はTweenerのJavaScriptポートである,JSTweenerにその関数群が実装されています。

easeOutBounce版アニメーション

var easeOutBounce = JSTweener.easingFunctions.easeOutBounce;
var begin = new Date() - 0;
var element = document.getElementById('cbjs-17-3');
var from = 0; // 初期値
var distance = 100; // 変動値
var duration = 1000; // 継続時間
var id = setInterval(function(){
  var time = new Date() - begin; // 経過時間
  var current = easeOutBounce(time, from, distance, duration);
  if (time > duration){
    clearInterval(id);
    current = from + distance;
  }
  element.style.top = current + 'px';
}, 10); // 10ms置きに実行

著者プロフィール

太田昌吾(おおたしょうご,ハンドルネーム:os0x)

1983年生まれ。JavaScriptをメインに,HTML/CSSにFlashなどのクライアントサイドを得意とするウェブエンジニア。2009年12月より、Google Chrome ExtensionsのAPI Expertとして活動を開始。

URLhttp://d.hatena.ne.jp/os0x/

コメント

コメントの記入