画像処理関数・メソッド

【JavaScript】 DOMのanimateメソッドでアニメーションしてみる

更新日:2021/09/09

DOM要素のanimateメソッドを使用すると、CSSの@keyframesと同じような感覚で要素のアニメーションを制御できます。
jQueryにも同名のメソッドがありますが、今回はWeb Animations API のメソッドについて紹介します。

 

animateメソッドの概要

まずは次のデモを見てください。

デモ

これは次のようなDOM要素とCSSで構成されています。

HTML


<div id="demo1" style="height: 100px;width: 100px;border: 1px solid black;"></div>

CSS


#demo1{
    animation: anime infinite 10s linear;
}
@keyframes anime {
    0% {
        background-color : #fff;
        border-radius :  0 ;
        margin-left : 0;
    }
    50% {
        background-color : #000;
        border-radius :  50px ;
        margin-left : 300px;
    }
    100% {
        background-color : #fff;
        border-radius :  0 ;
        margin-left : 0;
    }
}

上のデモの欠点は、ブラウザがアニメーション動作の開始を決定しているということです。
つまり、任意のタイミングで開始や停止がおこなえません。

animateメソッドを使用することで、このようなアニメーションの動作を制御することができます。

 

animateメソッドの使用例

前項のデモをanimateメソッドに置き換えてみます。

次のコードは、スタイルの変化を配列で渡しています。


window.addEventListener( "DOMContentLoaded" , ()=>{

    const div = document.getElementById("demo");
    div.animate( {
            backgroundColor : ["#fff","#000","#fff" ],
            borderRadius : [ "0" , "50px"  , "0" ],
            marginLeft : [ "0" , "300px", "0" ],
        } , {
            duration: 10000,
            iterations: Infinity
        });
});

CSSと同じような形式で、キーフレームを渡すことも可能です。


window.addEventListener( "DOMContentLoaded" , ()=>{

    const div = document.getElementById("demo");
    div.animate( [ {
            backgroundColor : "#fff",
            borderRadius : "0",
            marginLeft :  "0" ,
        } , {
            backgroundColor :"#000",
            borderRadius :  "50px" ,
            marginLeft :  "300px",
        }  ,{
            backgroundColor :"#fff" ,
            borderRadius :  "0" ,
            marginLeft : "0" ,
        }  ] , {
            duration: 10000,
            iterations: Infinity
        } );

});

 

animateメソッドの構文

animateは、DOM要素からアクセスできるメソッドです。

次のような構文で、二つの引数を受け付けます。

引数の値の一部は、CSSのプロパティ名を指定します。
"-"が含まれるプロパティ名は、"-"を取り除き、続く一文字を大文字で表記するキャメルケースで記述します。

例:
background-color → backgroundColor

引数1:キーフレーム

一番目の引数は、変化させたいCSSスタイルを列挙します。

列挙方法は、次の二つの方法があります。

スタイル値を配列で指定

変化させたいスタイルをプロパティ名としたオブジェクトを指定します。
各プロパティの値は、変化させたい値を順番に並べた配列です。

指定例


{
        backgroundColor : ["#fff","#000","#f00"],
        borderRadius : [ "0" , "50px" , "0" ],
        marginLeft : [ "0" , "300px" , "0" ],
        offset: [ 0, 0.5 ] // 後述
        easing: [ "linear", "ease-in-out" ] // 後述
}

配列の要素は、一番目の値が0%で最後が100%に相当します。
それ以外の値は等間隔で割り振られます。

また、各々の要素数を同じにする必要はありません。

各々の要素数で間隔が決まる


{
        backgroundColor : ["#fff","#000","#f00"], // 0% , 50% , 100%
        borderRadius : [ "0" ,  "0" ],  // 0% , 100%
        marginLeft : [ "0" , "300px" , "300px" , "0" ], // 0% , 33% , 66% , 100%
}

間隔を自分で制御したいときは、offsetプロパティを使用できます。

offsetは、0から1までの小数で指定します。
0が0%、1が100%に相当します。

offset指定例


{
        backgroundColor : ["#fff","#000","#f00"], // 0% , 20% , 100%
        offset: [ 0, 0.2 ] 
}

easingプロパティは、「最初はゆっくりで後半は速く」などといった、アニメーション動作の動きを指定できます。

easing指定例


{
        backgroundColor : ["#fff","#000","#f00"], // 0% , 20% , 100%
         easing: [ "linear", "ease-in-out" ]
}

easingプロパティは次の値を指定できます。

easingプロパティの値
意味
"linear"一定の速度で変化
"ease"最初は速く後半は減速
"ease-in"最初は遅く後半は加速
"ease-in-out"最初は遅く中盤加速後半は減速
"ease-out"最初は速く後半は減速。最初はeaseよりも少し速い
"step-start"最初に100%の状態に変化
"step-end"0%の状態を維持し、最後に100%の状態に変化
"cubic-bezier( 引数1 , 引数2 , 引数3 , 引数4)"4つの引数で変化をカスタマイズする
"steps( 引数1 , 引数2 )"2つの引数で変化をカスタマイズする

具体的な変化については、次のツールで確認できます。
css/javascript イージング確認ツール

スタイルの組を配列で指定

スタイル値を組み合わせたオブジェクトを、順番に並べた配列です。

こちらも方法でも、offseteasing指定が可能です。


    [
        {
            backgroundColor : "#fff",
            borderRadius :  "0" ,
            marginLeft : "0",
            offset: 0,
            easing : "linear" ,
        },
        {
            backgroundColor : "#000",
            borderRadius :  "50px" ,
            marginLeft : "300px",
            offset: 0.5,
            easing : "ease-in-out" ,
        },
        {
            backgroundColor : "#f00",
            borderRadius :  "0" ,
            marginLeft : "0" ,
        },
    ]

引数2:タイミング

animateメソッドの2番目の引数は、再生時間などを指定します。
この値はミリ秒を表す整数値、またはオブジェクトです。

次の2つの例は、共に5秒のアニメーションを実行しています。

ミリ秒で指定


div.animate( { backgroundColor : ["#fff","#000","#f00"] } , 5000 );

オブジェクトで指定


div.animate( { backgroundColor : ["#fff","#000","#f00"] } , { duration : 5000 } );

オブジェクトで指定した場合、次のようなプロパティを使用できます。

プロパティ名意味
duration再生時間(ミリ秒)ミリ秒
delay再生開始までの待機時間(ミリ秒)ミリ秒(規定値は0)
direction再生方向"normal" :

0%から100%へ変化
"reverse" :
100%から0%へ変化
"alternate" :
0%から100%→100%から0%の繰り返し
"alternate-reverse" :
"alternate"の逆パターン
規定値:"normal"

easingアニメーション動作の変化率easingプロパティの値参照
endDelay再生終了後の待機時間ミリ秒(規定値は0)
fillアニメーション前後の状態"none" :

delay中を含めてcssのみ適用
"forwards" :
終了時の状態を維持
"backwards" :
delay中からアニメーション開始時の状態を反映
"both" :
"forwards""backwards"の両方
規定値:"none"

iterationStart再生開始のタイミング。

0.2とした場合、20%から100%の次に
0%から20%まで再生される

0以上の小数(規定値は0)
iterations再生回数0以上の小数(規定値は1)

Infinityを指定すると、無限ループする

idアニメーションを識別するためのID文字列で指定
compositeCSSなどの元となる状態と

アニメーションの現在の状態との処理方法

"replace" :
アニメーションの現在の状態で置き換え
"add" :
元となる状態にアニメーションの状態を追加
"accumulate" :
元となる状態にアニメーションの状態を累積
規定値:"replace"

iterationComposite繰り返し時の状態の取り扱い方法"replace" :

現在の状態で置き換え
"accumulate" :
これまでの状態を累積
規定値:"replace"

 

Animationのメソッド

animeteメソッドを実行すると、戻り値としてAnimationオブジェクトを受け取ることができます。

このオブジェクトを使用することで、アニメーションの一時停止や再開などをおこなえます。

Animationオブジェクトメソッドの使用例

デモ

html


<div id="demo2" style="height: 100px;width: 100px;border: 1px solid black;"></div>

<button id="stop">停止</button><button id="pause">一時停止</button>
<button id="play1">再生</button><button id="play2">2倍速</button>
<button id="play10">10倍速</button><button id="play5s">5秒後再生</button><span id="wait"></span>

css

#demo2{ background-color: red;}
button{ margin:10px;}

JavaScript


window.addEventListener( "DOMContentLoaded" , ()=>{

    const div = document.getElementById("demo2");
    const anime = div.animate( {
            backgroundColor : ["#fff","#000" ,"#fff"],
            borderRadius : [ "0" , "50px" , "0" ],
            marginLeft : [ "0" , "300px" , "0"],
        }, {
            duration: 30000,
            iterations: Infinity,
            composite:"add",
        });
    anime.cancel();

    const isRunning = ()=>anime.playState === "running";
    const isFunction = func=>typeof func === "function";

    const buttonDisabled = flg => buttons.forEach( b => b.disabled = flg );
    const readyWait = ( func = null)=>{
        buttonDisabled(true);
        anime.ready.then( isFunction( func ) ? func : ()=>buttonDisabled( false ));
    };
    const buttonClick = (methodName , func = null) => {
        anime[methodName](  ); readyWait( func );
    };
    const play = (speed) => {
        anime.updatePlaybackRate(speed);
        readyWait( isRunning() ? null : ()=>buttonClick("play"));
    };
    const waitMessage = (element,countTime) =>{
        let statTime = null;
        let currentSec = countTime;
        const display = timestamp=>{
            if( statTime === null ) statTime = timestamp;
            if( currentSec < 0 ) { element.textContent = ""; return;}
            const nowSec = countTime - Math.floor( (timestamp - statTime) / 1000 );
            if( nowSec >=0 && currentSec !== nowSec )
                    element.textContent = nowSec.toString();
            currentSec = nowSec;
            requestAnimationFrame( display );
        };
        requestAnimationFrame( display );
    };

    const waitSpan = document.getElementById("wait");
    const animeFunc = {
        stop : ()=>buttonClick( "cancel"  ),
        pause :()=>buttonClick( "pause"  ),
        play1 :()=>play(1), play2 :()=>play(2), play10 :()=>play(10),
        play5s : ()=> {
            anime.startTime =  anime.timeline.currentTime +5000;
            waitMessage( waitSpan , 5 );
        }
    };

    const buttons = Object.entries( animeFunc ).map(
        data => {
            const button = document.getElementById( data[0] );
            button.addEventListener( "click" , data[1] );
            return button;
        }
    );

    readyWait();
});

メソッド一覧

Animationオブジェクトのメソッド
メソッド名意味
cancel()再生を中止しリセットする
pause()再生を一時停止する
play()再生開始または再開する
reverse()逆再生をおこなう
updatePlaybackRate()再生速度を変更する
finish()再生を終了(最後まで再生した状態)する

これらのメソッドを実行しても、即座に反映されるわけではありません。
アニメーションの処理は時間がかかるため、非同期で実行されます。

プロパティ一覧

Animationオブジェクトのプロパティ
プロパティ名変更可否
currentTime現在の再生時間
effectKeyframeEffectオブジェクト
finished終了時に解決するPromiseオブジェクト×(読み取り専用)
idアニメーションを識別するためのID
pending非同期処理の終了待ちかどうかのフラグ×(読み取り専用)
playState再生状況を表す文字列

"idle": 再生していない状態
"running" : delay, endDelayを含んだ再生中の状態
"paused": 一時停止中の状態
"finished" : 最後まで再生した状態

×(読み取り専用)
playbackRate再生速度
ready再生準備完了時に解決するPromiseオブジェクト×(読み取り専用)
startTime再生開始した時間。

anime.timeline.currentTimeにミリ秒を
加算した値をセットすると、
ミリ秒経過後に開始することができる。
このとき、開始待ちでもplayStateは"running"になる。

oncancelcancel イベントハンドラー
onfinishfinish イベントハンドラー

更新日:2021/09/09

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。