ウェブ アニメーションの再生コントロール(Chrome 39)

今年、Chrome 36 では、広範な Web Animations 仕様の一部として、element.animate メソッドを導入しました。これにより、命令的に効率的なネイティブ アニメーションを作成できるようになり、デベロッパーは自分に最適なアプローチでアニメーションと遷移を作成する選択肢が広がります。

簡単におさらいしてみましょう。画面全体に雲をアニメーション表示し、終了したらコールバックでアニメーション化する方法を以下に示します。

var player = cloud.animate([
    {transform: 'translateX(' + start + 'px)'},
    {transform: 'translateX(' + end + 'px)'}
], 5000);
player.onfinish = function() {
    console.info('Cloud moved across the screen!');
    startRaining(cloud);
};

これだけでも非常に簡単で、アニメーションや遷移を命令的に作成する際のツールボックスの一部として検討する価値があります。ただし、Chrome 39 では、element.animate から返される AnimationPlayer オブジェクトに再生コントロール機能が追加されました。これまでは、アニメーションを作成した後は、cancel() を呼び出すか、終了イベントをリッスンすることしかできませんでした。

このような再生機能の追加により、ウェブ アニメーションでできることの可能性が広がります。つまり、遷移についての規範的なものではなく、アニメーションを汎用のツールに変えることができます。「固定」または事前定義されたアニメーションなどがあります。

一時停止、巻き戻し、再生速度の変更

まずは、上の例を更新して、雲がクリックされたときにアニメーションを一時停止するようにしましょう。

cloud.addEventListener('mousedown', function() {
    player.pause();
});

playbackRate プロパティを変更することもできます。

function changeWindSpeed() {
    player.playbackRate *= (Math.random() * 2.0);
}

reverse() メソッドを呼び出すこともできます。これは通常、現在の playbackRate を反転(-1 を乗算)するのと同じです。ただし、いくつかの特殊なケースがあります。

  • reverse() メソッドによる変更によって実行中のアニメーションが実質的に終了する場合は、currentTime も反転します。たとえば、新しいアニメーションが反転した場合、アニメーション全体が逆方向に再生されます。

  • プレーヤーが一時停止すると、アニメーションの再生が開始されます。

プレーヤーのスクラブ

AnimationPlayer で、アニメーションの実行中に currentTime を変更できるようになりました。通常、この値は時間の経過とともに増加します(playbackRate が負の場合は減少します)。これにより、アニメーションの位置を外部から(ユーザー操作によって)制御できる場合があります。これは一般に「スクラブ」と呼ばれます。

たとえば、HTML ページが空を表しており、ドラッグ操作によって現在再生中の雲の位置を変更したい場合は、ドキュメントにハンドラを追加します。

var startEvent, startEventTime;
document.addEventListener('touchstart', function(event) {
    startEvent = event;
    startEventTime = players.currentTime;
    player.pause();
});
document.addEventListener('touchmove', function(event) {
    if (!startEvent) return;
    var delta = startEvent.touches[0].screenX -
        event.changedTouches[0].screenX;
    player.currentTime = startEventTime + delta;
});

ドキュメント上をドラッグすると、元のイベントからの距離を反映して currentTime が変更されます。操作が終了したら、アニメーションの再生を再開することもできます。

document.addEventListener('touchend', function(event) {
    startEvent = null;
    player.play();
});

マウスをページから離した場所によっては、これを反転動作と組み合わせることもできます(複合デモ)。

ユーザーの操作に応じて AnimationPlayer をスクラブする代わりに、その currentTime を使用して進行状況やステータスを表示することもできます。たとえば、ダウンロードのステータスを表示できます。

ここでの有用性は、AnimationPlayer によって値を設定でき、基となるネイティブ実装がその進行状況の可視化を処理することです。ダウンロードの場合、アニメーションの再生時間に合計ダウンロード サイズを設定し、currentTime に現在ダウンロードされているサイズを設定できます(demo)。

UI の遷移と操作

モバイル プラットフォームでは、ドラッグ、スライド、フリングなどの一般的なジェスチャーの領域となってきました。こうした操作には、多くの場合、ドラッグ可能な UI コンポーネント(リストビューの「プルして更新」、画面の左側から作り込まれたサイドバーなど)という共通のテーマがあります。

ウェブ アニメーションを使用すれば、パソコンやモバイルでも同じような効果を簡単に再現できます。たとえば、currentTime を制御するジェスチャーが完了した場合は次のようになります。

var steps = [ /* animation steps */ ];
var duration = 1000;
var player = target.animate(steps, duration);
player.pause();
configureStartMoveListeners(player);

var setpoints = [0, 500, 1000];
document.addEventListener('touchend', function(event) {
    var srcTime = player.currentTime;
    var dstTime = findNearest(setpoints, srcTime);
    var driftDuration = dstTime - srcTime;

    if (!driftDuration) {
    runCallback(dstTime);
    return;
    }

    var driftPlayer = target.animate(steps, {
    duration: duration,
    iterationStart: Math.min(srcTime, dstTime) / duration,
    iterations: Math.abs(driftDuration) / duration,
    playbackRate: Math.sign(driftDuration)
    });
    driftPlayer.onfinish = function() { runCallback(dstTime); };
    player.currentTime = dstTime;
});

これにより、「ドリフト」を引き起こす追加のアニメーションが作成されます。これは、ジェスチャーが完了した場所から、既知の正常な対象に至るまで再生されます。

これは、アニメーションの作成順序に基づいて優先度が設定されるため、driftPlayer がプレーヤーより優先されます。driftPlayer が完了すると、そのエフェクトは表示されなくなります。ただし、最終時刻は基となるプレーヤーの currentTime と一致するため、UI に一貫性はありません。

また、子猫が好きな方は、子猫のジェスチャーを紹介するデモ ウェブ アプリケーションもあります。モバイル フレンドリーで、下位互換性を保つためにポリフィルを使用しています。そのため、モバイル デバイスで読み込んでみてください。

移動して element.animate

単純なアニメーションに使用する場合、または返された AnimationPlayer を別の方法で利用する場合にも、element.animate メソッドは完全に安定します。

これら 2 つの機能は、軽量のポリフィルを使用して他の最新のブラウザでも完全にサポートされています。このポリフィルでも機能検出が行われるため、ブラウザ ベンダーが仕様を実装するにつれ、この機能は時間の経過とともにより高速かつ高まります。

ウェブ アニメーションの仕様も進化していきます。今後リリースされる機能にご興味がある場合は、より詳細なポリフィル(web-animations-next)でも提供されています。