canvas

Posted コメントするカテゴリー: javascript

canvas

canvasについて調べます。

canvasの特徴

・html5で標準化されている。
・特定のブラウザを除き広くサポートされている。
・メソッドを呼び出して画面(図形)を描画します。
・canvasタグ内で描画APIを呼び出して画面を描画します。

SVGとの違い

svgはxml構造のツリー構造で画面を構築します。
canvasはメソッドを呼び出すことで図形を描画します。
その為の描画APIも多数あります。

描画メソッドはcanvasタグでは定義されておらず、描画コンテキストに定義されています。
描画コンテキストはcanvasタグ内で実行するjavascriptでgetContext()メソッドにより呼び出すことができます。

単純なサンプル

以下に簡単なcanvasのサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
    // canvasのDOMを取得
    const canvas = document.getElementById('canvas');
    
    // getContextメソッドでコンテキストを取得
    // ここでは2次元の平面的な図形を扱うので、引数に「2d」を指定
    const ctx = canvas.getContext('2d');
    
    // コンテキストのstyleを定義(背景色: グレー、大きさ: 150の正方形)
    ctx.fillStyle = '#cccccc';
    ctx.fillRect(0, 0, 150, 150);
</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面アクセスすると、150pxの正方形が表示されます。
以降、canvasでどんなことができるのか、試していきます。

SVGアニメーション – Web Animations API を使う – モーフィングアニメーションについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – モーフィングアニメーションについて

SVGを使用したモーフィングアニメーションを試します。
以下サンプルです。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
<svg width="300" height="250">
    <path 
        d            = "M 10,10 90,150 120,20 Z"
        stroke       = "#eeeeee"
        stroke-width = "1"
        fill         = "#dddddd"
    >
        <animate
            attributeName = "d"
            repeatCount   = "indefinite"
            dur           = "3s"
            to            = "M 130,40 150,180 160,40 Z"
        >
    </path>
</svg>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、SVG画像がモーフィングします。

考え方としては、

<path 
    d            = "M 10,10 90,150 120,20 Z"
    stroke       = "#eeeeee"
    stroke-width = "1"
    fill         = "#dddddd"
>

で指定したSVG画像に対し、

<animate
    attributeName = "d"
    repeatCount   = "indefinite"
    dur           = "3s"
    to            = "M 130,40 150,180 160,40 Z"
>

上記で指定した「to」のパス情報に3秒かけて、パスの変化をしている。
ということになります。

モーフィングする際のパス情報は、開始時と終了時で同じ数のパスにする必要があります。

attributeNameのパラメータにはサンプルではパスを示す「d」を指定していますが、
「d」以外の値(例えば色の塗りつぶし情報等)でも指定可能です。

SVGアニメーション – Web Animations API を使う – pathに沿ったアニメーションについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – pathに沿ったアニメーションについて

これまではSVGの要素をjavascriptを使ってアニメーションする例がほとんどでした。

今回の投稿は少し経路を変えて、pathによるSVGにアニメーションを試してみます。
とあるオブジェクトをpathに沿ってアニメーションさせるには、幾通りの方法があるようです。

ここでは「SVGのanimateMotion定義でアニメーションする方法」と「CSSのoffset-path定義でパスを指定してアニメーションする方法」について試してみようと思います。

SVGのanimateMotion定義でアニメーションする方法

「animateMotion」はSVGにより定義されており、ある要素がモーションパスに沿って移動する方法です。

例として以前(https://propansystem.net/blog/8297)投稿した下記のSVG描画をあげます。

<path
    d            = "M 0,0 90,150 120,20 10,10"
    stroke       = "#999999"
    stroke-width = "1"
    fill         = "#cccccc"
>

上記のSVG画像は画面上では三角形が描画されます。

このSVG画像を「モーションパスに沿って動く側」として考え、
次に「モーションパス側」を定義します。
モーションパス側の図形としては以前に投稿(https://propansystem.net/blog/8270)した中から、
polygon(多角形)のものを流用します。

<path
    d            = "M20,50 10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165 z"
    stroke       = "#999999"
    stroke-width = "3"
    fill         = "#eeeeee"
/>

ただし、この多角形のSVG画像をそのまま「animateMotion」として組み合わせても動作しません。
モーションパスの定義して、以下のように記述をします。

<animateMotion
    dur         = "10s"
    repeatCount = "indefinite"
    path        = "M20,50 10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165 z"
    fill        = "#eeeeee"
/>

上記2つの「パスに沿って動く側」と「モーションパスを定義する側」のSVG図形を組み合わせると
パスにそったアニメーションになります。

かんたんなサンプルを以下に用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
<!-- アニメーション用パス(SVG) -->
<svg width="300" height="250">

    <!-- モーション時にわかりやすいようにパス表示する        -->
    <!-- このpathの記述は書かなくてもanimateMotinoは動作する -->
    <path
        d            = "M20,50 10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165 z"
        stroke       = "#999999"
        stroke-width = "3"
        fill         = "#eeeeee"
    />

    <!-- パス上を移動するSVG図形 -->
    <path
        d            = "M 0,0 90,150 120,20 10,10"
        stroke       = "#999999"
        stroke-width = "1"
        fill         = "#cccccc"
    >
        <!-- モーションパスを定義するSVG図形 -->
        <animateMotion
            dur         = "10s"
            repeatCount = "indefinite"
            path        = "M20,50 10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165 z"
            fill        = "#eeeeee"
        />
    </path>
</svg>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、モーションパス上を移動するSVG図形が表示され、アニメーション動作します。

CSSのoffset-path定義でパスを指定してアニメーションする方法

CSSの定義を用いたSVGアニメーションとして、以下の2つのCSS定義が重要です。
・offset-path
・offset-distance

前者の「offset-path」については、SVG図形をアニメーションさせる際のモーション(ガイド線)の役割をし、
後者の「offset-distance」については、どのようにモーションの上を動作させるかを決めます。

以下に簡単なサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
/* アニメーションする側のSVG図形 */
.elem1 {
    width           : 10px;
    height          : 10px;
    offset-path     : path('M20,50 10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165 z'); 
    offset-distance : 0;
    animation       : move 15000ms ease-in-out infinite alternate;
    back
}
/* アニメーション時のパス表示 */
.elem2 {
    position        : absolute;
    width           : 300px;
    height          : 300px;
}
/* アニメーション定義 */
@keyframes move {
    0%   {offset-distance : 0%;   }
    100% {offset-distance : 100%; }
}
</style>
</head>
<body>

<!-- アニメーションする側のSVG図形 -->
<div class="elem1">
<svg width="300" height="300">
<g>
    <path
        d            = "M 0,0 90,150 120,20 10,10"
        stroke       = "#999999"
        stroke-width = "1"
        fill         = "#cccccc"
    </path>
</g>
</svg>
</div>

<!-- アニメーション時のパスを表示する(この出力は無くても動作する) -->
<div class="elem2">
<svg width="300" height="300">
<g>
    <path
        d            = "M20,50 10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165 z"
        stroke       = "#666666"
        stroke-width = "3"
        fill         = "#999999"
    />
</g>
</svg>
</div>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、アニメーションする側のSVG図形が、
CSSの「offset-path」で定義したパスに沿ってアニメーションすることがわかります。

SVGアニメーション – Web Animations API を使う – CSSアニメーション再生時のgetAnimations()の取得について

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – CSSアニメーション再生時のgetAnimations()の取得について

前回の投稿(https://propansystem.net/blog/10005)のサンプルをもとに、
CSSアニメーション再生時のgetAnimations()の取得について試してみます。

SVGでのアニメーション再生中のオブジェクトの情報をgetAnimations()で
取得できることがわかりました。

同様にcssアニメーション中のdivタグの情報をgetAnimations()で取得してみます。

cssのアニメーションは指定オブジェクトを左から右へ500px移動するシンプルなものにしました。

@keyframes cssAnimation {
    0% {
        transform: translateX(0px);
    }
    100% {
        transform: translateX(500px);
    }
}

このcssアニメーション中にgetAnimations()を実行し、取得した結果を画面に出力するサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
.bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
    animation        : cssAnimation 10s ease-out 0s forwards;
}
@keyframes cssAnimation {
    0% {
        transform        : translateX(0px);
    }
    100% {
        transform        : translateX(500px);
    }
}
</style>
</head>
<body>
<!-- ボタン -->
<div class="bottom">
    <input type="button" id="getAnimations" value="getAnimations情報の取得と出力">
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1</div>
<!-- getAnimationsの取得結果 -->
<div class="params" id="getAnimationsVal"></div>

<script>
// DOM要素取得
let test1_dom            = document.querySelector("#test1_dom"       );
let getAnimations_dom    = document.querySelector("#getAnimations"   );
let getAnimationsVal_dom = document.querySelector("#getAnimationsVal");

// getAnimationsの実行と画面出力
getAnimations_dom.addEventListener('click', (e) => {
    let animations = test1_dom.getAnimations();
    let animations_display_value = '';
    // 各アニメーションの詳細を表示
    animations.forEach((animation, index) => {
        animations_display_value += 'Animation    :' + index                                 + '<br />';
        animations_display_value += 'Play State   :' + animation.playState                   + '<br />';
        animations_display_value += 'Start Time   :' + animation.startTime                   + '<br />';
        animations_display_value += 'Current Time :' + animation.currentTime                 + '<br />';
        animations_display_value += 'Duration     :' + animation.effect.getTiming().duration + '<br />';
        animations_display_value += 'Animation ID :' + animation.id                          + '<br />';
    });
    // 画面内のDOMへ出力する
    getAnimationsVal_dom.innerHTML = animations_display_value;
}, false);
</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスするとcssアニメーションが再生されます。
再生中に「getAnimations情報の取得と出力」ボタンを押下すると、
SVG再生中に取得表示した時と同様に、cssアニメーション再生中の情報も取得できることがわかります。

SVGアニメーション – Web Animations API を使う – アニメーション再生時のgetAnimations()について

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション再生時のgetAnimations()について

アニメーション再生時に、再生しているdiv要素のメソッドとして「getAnimations()」が使えます。
このメソッドは再生中のアニメーションのAnimationのオブジェクト(の配列)として取得することができます。
また、アニメーションを停止してidleになっている要素では取得できません。
css定義されたアニメーションも取得できます。

以下に簡単なサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
.bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div class="bottom">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
</div>
<!-- ボタン -->
<div class="bottom">
    <input type="button" id="getAnimations"   value="getAnimationsの実行"   >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<!-- getAnimationsの取得結果 -->
<div class="params" id="getAnimationsVal"></div>
<script>
// DOM要素取得
let start_animate_dom    = document.querySelector("#start_animate"   );
let pause_animate_dom    = document.querySelector("#pause_animate"   );
let reverse_animate_dom  = document.querySelector("#reverse_animate" );
let finish_animate_dom   = document.querySelector("#finish_animate"  );
let cancel_animate_dom   = document.querySelector("#cancel_animate"  );
let display_dom          = document.querySelector("#display"         );
let test1_dom            = document.querySelector("#test1_dom"       );
let getAnimations_dom    = document.querySelector("#getAnimations"   );
let getAnimationsVal_dom = document.querySelector("#getAnimationsVal");

// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration: 5000
};
animation1 = test1_dom.animate(keyframes1, options1);

animation1.cancel(); // 初期値は停止

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
    animation1.play();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
    animation1.pause();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
    animation1.reverse();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
    animation1.finish();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
    animation1.cancel();
    display_dom.innerHTML = animation1.playState;
}, false);

// getAnimationsの実行と画面出力
getAnimations_dom.addEventListener('click', (e) => {
	let animations = test1_dom.getAnimations();
	let animations_display_value = '';
    // 各アニメーションの詳細を表示
    animations.forEach((animation, index) => {
        animations_display_value += 'Animation    :' + index                                 + '<br />';
        animations_display_value += 'Play State   :' + animation.playState                   + '<br />';
        animations_display_value += 'Start Time   :' + animation.startTime                   + '<br />';
        animations_display_value += 'Current Time :' + animation.currentTime                 + '<br />';
        animations_display_value += 'Duration     :' + animation.effect.getTiming().duration + '<br />';
        animations_display_value += 'Animation ID :' + animation.id                          + '<br />';
    });
    // 画面内のDOMへ出力する
    getAnimationsVal_dom.innerHTML = animations_display_value;
}, false);

// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック
</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面アクセスして「アニメーション開始」ボタンを押下し、
「getAnimations情報の取得と出力」ボタンを押下すると、アニメーション再生中は1つの(再生中の)オブジェクトの情報が取得できます。

ボタン押下時のイベントには、getAnimations情報の詳細を取得し、画面内のDOMに出力する処理を書いています。

// getAnimationsの実行と画面出力
getAnimations_dom.addEventListener('click', (e) => {
	let animations = test1_dom.getAnimations();
	let animations_display_value = '';
    // 各アニメーションの詳細を表示
    animations.forEach((animation, index) => {
        animations_display_value += 'Animation    :' + index                                 + '<br />';
        animations_display_value += 'Play State   :' + animation.playState                   + '<br />';
        animations_display_value += 'Start Time   :' + animation.startTime                   + '<br />';
        animations_display_value += 'Current Time :' + animation.currentTime                 + '<br />';
        animations_display_value += 'Duration     :' + animation.effect.getTiming().duration + '<br />';
        animations_display_value += 'Animation ID :' + animation.id                          + '<br />';
    });
    // 画面内のDOMへ出力する
    getAnimationsVal_dom.innerHTML = animations_display_value;
}, false);

アニメーションの再生中に「getAnimations情報」を何度か押下すると、
再生中の都度の情報が取得できていることがわかります。

また、アニメーションの再生が終わると、getAnimationsの情報は取得できなくなり、
画面出力も空白になります。

SVGアニメーション – Web Animations API を使う – アニメーションのPromiseについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーションのPromiseについて

Animationオブジェクトには以下のプロパティが定義されています。
①Animation.ready
②Animation.finished

これはPromiseの仕組みで動作します。
PromiseはECMAScript 2015から導入された概念で、javascriptで利用できますが、言語として組み込まれたのは他の言語です。

Promiseは非同期処理を抽象化したオブジェクトと、オブジェクトを操作する仕組みです。
ここではPromiseの詳解はしないですが、このPromiseの概念はjavascriptを書き進めるにあたり避けて通れない概念です。

SVGアニメーションでPromiseを利用する例として、上記の「ready」と「finished」を軸に進めます。

Promiseのおもな動き

Promiseには非同期処理をおもに取り扱います。
非同期処理の結果が解決(resolve)された際の処理、コールバック関数をthenメソッドを使って設定することができます。
また、解決ではなく非同期処理が失敗(reject)された際にも処理(コールバック関数)が呼ばれます。

Animation.readyの動き

Animation.readyはアニメーションの再生準備が完了した際にthenのコールバック関数を実行します。
以下、簡単なサンプルです。
再生準備が完了したかどうかをconsole.logに出力しています。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<script>
// DOM要素取得
let start_animate_dom   = document.querySelector("#start_animate"  );
let pause_animate_dom   = document.querySelector("#pause_animate"  );
let reverse_animate_dom = document.querySelector("#reverse_animate");
let finish_animate_dom  = document.querySelector("#finish_animate" );
let cancel_animate_dom  = document.querySelector("#cancel_animate" );
let display_dom         = document.querySelector("#display"        );
let test1_dom           = document.querySelector("#test1_dom"      );
// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration: 5000
};
animation1 = test1_dom.animate(keyframes1, options1);

animation1.cancel(); // 初期値は停止

// Promiseの確認
// 再生準備ができているかを確認する
animation1.ready.then(function() {
    console.log("再生準備完了");
});

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
    animation1.play();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
    animation1.pause();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
    animation1.reverse();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
    animation1.finish();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
    animation1.cancel();
    display_dom.innerHTML = animation1.playState;
}, false);


// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック
</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

Animation.finishedの動き

上記と同様に「再生完了しているか」を確認するサンプルです。
再生完了をPromiseを使って「animation1.finished.then」という形で確認しています。
非同期的に動作するので、再生秒数にかか関わらず動作します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<script>
// DOM要素取得
let start_animate_dom   = document.querySelector("#start_animate"  );
let pause_animate_dom   = document.querySelector("#pause_animate"  );
let reverse_animate_dom = document.querySelector("#reverse_animate");
let finish_animate_dom  = document.querySelector("#finish_animate" );
let cancel_animate_dom  = document.querySelector("#cancel_animate" );
let display_dom         = document.querySelector("#display"        );
let test1_dom           = document.querySelector("#test1_dom"      );
// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration: 5000
};
animation1 = test1_dom.animate(keyframes1, options1);

animation1.cancel(); // 初期値は停止

// Promiseの確認
// 再生準備ができているかを確認する
animation1.ready.then(function() {
    console.log("再生準備完了");
});

// 再生完了しているかを確認する
animation1.finished.then(function() {
    console.log("再生完了");
});

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
    animation1.play();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
    animation1.pause();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
    animation1.reverse();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
    animation1.finish();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
    animation1.cancel();
    display_dom.innerHTML = animation1.playState;
}, false);


// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック
</script>
</body>
</html>

サーバ上のHTMLはこちら(test2.html)

2つのAnimationオブジェクトに対し、Animation.finishedを参照してPromise.allで終了タイミングを取得する

アニメーション1とアニメーション2を用意し、1と2をそれぞれ再生して「どちらも終了したタイミング」を
Promise.allを用いて取得(確認)します。

便宜上、このサンプルの場合のアニメーション1とアニメーション2は途中で異常終了しなものとしています。

Promise.allを使う場合は、引数の中にアニメーション1とアニメーション2のfinishedを格納したPromiseを使用しています。

アニメーション1の「anifini1」を取得

// 再生完了しているかを確認する
let anifini1 = animation1.finished.then(function() {
    console.log("アニーメション1 再生完了");
});

アニメーション2の「anifini2」を取得

// 再生完了しているかを確認する
let anifini2 = animation2.finished.then(function() {
    console.log("アニーメション2 再生完了");
});

取得した「anifini1」と「anifini2」をPromise.allの引数として使用し、
アニメーション1とアニメーション2の両方が完了したタイミングで、アラート(とconsoleログ)を出力

// Promise allの確認
Promise.all([anifini1, anifini2]).then(() => {
	console.log('Promise.all then');
	alert('Promise.all then');
});

サンプルの全体は以下のように書きました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom, #test2_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1</div>
<div id="test2_dom">TEST2</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value1"></div>
<div class="params" id="currentTime_value2"></div>
<script>
//-----------------------------
// DOM要素取得
let start_animate_dom   = document.querySelector("#start_animate"  );
let pause_animate_dom   = document.querySelector("#pause_animate"  );
let reverse_animate_dom = document.querySelector("#reverse_animate");
let finish_animate_dom  = document.querySelector("#finish_animate" );
let cancel_animate_dom  = document.querySelector("#cancel_animate" );
let test1_dom           = document.querySelector("#test1_dom"      );
let test2_dom           = document.querySelector("#test2_dom"      );

//-----------------------------
// アニメーション1用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration: 5000
};
animation1 = test1_dom.animate(keyframes1, options1);

//-----------------------------
// アニメーション2用オブジェクト
//-----------------------------
let animation2;
// keyframes定義
const keyframes2 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options2 = {
    duration: 10000
};
animation2 = test2_dom.animate(keyframes2, options2);

//-----------------------------
animation1.cancel(); // 初期値は停止
animation2.cancel(); // 初期値は停止

//-----------------------------
// Promiseの確認
//-----------------------------
// 再生準備ができているかを確認する
animation1.ready.then(function() {
    console.log("アニーメション1 再生準備完了");
});

// 再生完了しているかを確認する
let anifini1 = animation1.finished.then(function() {
    console.log("アニーメション1 再生完了");
});

//-----------------------------
// Promiseの確認
//-----------------------------
// 再生準備ができているかを確認する
animation2.ready.then(function() {
    console.log("アニーメション2 再生準備完了");
});

// 再生完了しているかを確認する
let anifini2 = animation2.finished.then(function() {
    console.log("アニーメション2 再生完了");
});

// Promise allの確認
Promise.all([anifini1, anifini2]).then(() => {
	console.log('Promise.all then');
	alert('Promise.all then');
});

//-----------------------------
// アニメーション操作
//-----------------------------
start_animate_dom.addEventListener('click', (e) => {
    animation1.play();
    animation2.play();
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
    animation1.pause();
    animation2.pause();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
    animation1.reverse();
    animation2.reverse();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
    animation1.finish();
    animation2.finish();
    display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
    animation1.cancel();
    animation2.cancel();
    display_dom.innerHTML = animation1.playState;
}, false);


// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーション1が再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value1').innerHTML = disp_sec;
    }

    // アニメーション2が再生中の場合に秒数を更新
    if (animation2.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec2 = (animation2.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value2').innerHTML = disp_sec2;
    }
}, 10); // 0.01秒ごとにチェック
</script>
</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面アクセスして「アニメーション開始」ボタンを押下すると、
アニメーション1とアニメーション2がそれぞれ実行されます。

アニメーション1とアニメーション2は再生秒数が異なるので、
アニメーションが終了するタイミングは別々になります。

どちらのアニメーションも終了したタイミングでPromise.allが動き、アラート表示されることが確認できます。

SVGアニメーション – Web Animations API を使う – アニメーションのfinish、cancel、removeイベントについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーションのfinish、cancel、removeイベントについて

前回までの投稿でanimationのplayStateプロパティでアニメーション中の状態(idle、running、paused、finished、pending)を取得することができました。

// アニメーションが再生中の場合に秒数を更新
if (animation1.playState === 'running') {

ここではアニメーションが終了、停止、削除された時のイベントについて、試してみます。

finish()イベント

アニメーションが終了した時に呼ばれるイベント

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #cccccc;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"  value="アニメーション開始">
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<script>
// DOM要素取得
let start_animate_dom  = document.querySelector("#start_animate" );
let cancel_animate_dom = document.querySelector("#cancel_animate");
let display_dom        = document.querySelector("#display"       );
let test1_dom          = document.querySelector("#test1_dom"     );

// アニメーション用定義
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(500px)'},
];
// option定義
const options1 = {
    duration   : 3000
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	// 開始ボタン押下でスライダ移動した挙動を同じ動きをする
	animation1.play();
	display_dom.innerHTML = animation1.playState;
}, false);

// アニメーション終了時のイベント(注:domではなくanimateのインスタンスに対してのイベント付与)
animation1.addEventListener('finish', (e) => {

	// finish時にアラート
	alert("animation finish !");

	display_dom.innerHTML = animation1.playState;
}, false);

// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック

</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

サンプル画面のアニメーション開始を実行し、アニメーションが終わるとアラートが表示されます。
その際「animation1.addEventListener(‘finish’, (e) => {」で記述したfinishのイベントリスナが呼ばれることがわかります。

cancel()イベント

アニメーションがidel状態に入った時に呼ばれるイベント

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<script>
// DOM要素取得
let start_animate_dom   = document.querySelector("#start_animate"  );
let pause_animate_dom   = document.querySelector("#pause_animate"  );
let reverse_animate_dom = document.querySelector("#reverse_animate");
let finish_animate_dom  = document.querySelector("#finish_animate" );
let cancel_animate_dom  = document.querySelector("#cancel_animate" );
let display_dom         = document.querySelector("#display"        );
let test1_dom           = document.querySelector("#test1_dom"      );
// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration   : 3000
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーションキャンセル時のイベント(注:domではなくanimateのインスタンスに対してのイベント付与)
animation1.addEventListener('cancel', (e) => {
	// cancel時にアラート
	alert("animation cancel !");
	display_dom.innerHTML = animation1.playState;
}, false);

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	animation1.play();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
	animation1.pause();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
	animation1.reverse();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
	animation1.finish();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
	animation1.cancel();
	display_dom.innerHTML = animation1.playState;
}, false);

// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック
</script>
</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスし「アニメーション終了」ボタンを押下したとき、
「animation1.addEventListener(‘cancel’, (e) => {」のイベントリスナが呼ばれていることがわかります。

remove()イベント

アニメーションが削除された時に呼ばれるイベント

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
    <input type="button" id="remove_animate"  value="手動削除"              >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<script>
// DOM要素取得
let start_animate_dom   = document.querySelector("#start_animate"  );
let pause_animate_dom   = document.querySelector("#pause_animate"  );
let reverse_animate_dom = document.querySelector("#reverse_animate");
let finish_animate_dom  = document.querySelector("#finish_animate" );
let cancel_animate_dom  = document.querySelector("#cancel_animate" );
let remove_animate_dom  = document.querySelector("#remove_animate" );
let display_dom         = document.querySelector("#display"        );
let test1_dom           = document.querySelector("#test1_dom"      );
// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration   : 3000
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーションキャンセル時のイベント(注:domではなくanimateのインスタンスに対してのイベント付与)
animation1.addEventListener('remove', (e) => {
	// remove時にアラート
	alert("animation remove !");
	display_dom.innerHTML = animation1.playState;
}, false);

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	animation1.play();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
	animation1.pause();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
	animation1.reverse();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
	animation1.finish();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
	animation1.cancel();
	display_dom.innerHTML = animation1.playState;
}, false);

// 手動削除
remove_animate_dom.addEventListener('click', (e) => {
	// removeイベントを発火する
    const removeEvent = new Event('remove');
    animation1.dispatchEvent(removeEvent); // 手動でremoveイベントを発生させる

	// 要素を削除する
	test1_dom.remove();

	display_dom.innerHTML = animation1.playState;
}, false);

// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック
</script>
</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスして「手動削除」ボタンを押下すると、
「remove_animate_dom.addEventListener(‘click’, (e) => {」のイベントリスナ内で、
animation1のオブジェクトに対してremoveイベントを発火させています。

// removeイベントを発火する
const removeEvent = new Event('remove');
animation1.dispatchEvent(removeEvent); // 手動でremoveイベントを発生させる

なぜこの方法をとるかというと、animation1のオブジェクトを直接

animation1.remove()

という形で削除メソッドを実行しても「animation1オブジェクトはremoveメソッドを持たない」為にエラーになります。

なので、new Eventでremoveイベントを定義し、それをdispatchEventすることによって
animation1オブジェクトを削除しています。

削除時の挙動としては「animation1.addEventListener(‘remove’, (e) => {」で定義したremoveのイベントハンドラが実行されアラートが表示されることがわかります。
その後、明示的にDOM要素を削除していますが、

// 要素を削除する
test1_dom.remove();

この削除命令がなくてもanimation1のremoveイベントハンドラは実行される点に注意が必要です。

SVGアニメーション – Web Animations API を使う – アニメーション実行時のstartTimeプロパティについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行時のstartTimeプロパティについて

startTimeプロパティはアニメーションする要素の再生開始タイミングを決定します。
また、サンプルでも動作させていますが、startTimeプロパティの値を決定した後、
アニメーションが再生されるまでcurrentTime(現在の再生位置)がマイナスからカウントダウンされるように表示されます。
例えば再生開始(startTime)が5秒後の場合は、現在の再生位置(currentTime)は-5秒から0に減っていきます。

再生開始タイミングがどのように影響するかを確認できる簡単なサンプルを用意しました。
スライダ位置を調整すると自動的にN秒(スライダ値)後にアニメーションが開始されます。

画面内にはN秒後にアニメーション再生される秒数表示と、現在の再生位置(N秒)がわかる秒数表示をしています。
秒数表示は0.01秒ごと画面描画しています。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottom {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #cccccc;
    font-size        : 1.1rem;
    width            : 150px;
}
.range {
    width: 100%; /* スライダーの幅を画面最大に */
}
</style>
</head>
<body>
<!-- 開始ボタン -->
<div id="bottom">
    <input type="button" id="start_animate"  value="アニメーション開始">
    <input type="button" id="cancel_animate" value="アニメーション停止">
</div>
<!-- スライダ -->
<div class="params_box">
	<span class="param_title">再生開始(startTime)</span>
	<div><input type="range" class="range" id="range1" value="0" max="1000"></div>
	<span class="params" id="range1_value"></span>
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 再生秒数 -->
<div class="params" id="currentTime_value"></div>
<script>
// DOM要素取得
let start_animate_dom  = document.querySelector("#start_animate" );
let cancel_animate_dom = document.querySelector("#cancel_animate");
let display_dom        = document.querySelector("#display"       );
let test1_dom          = document.querySelector("#test1_dom"     );
let range1_dom         = document.querySelector("#range1"        );

// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(500px)'},
];
// option定義
const options1 = {
    duration   : 10000 // 100秒で一周
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	// 開始ボタン押下でスライダ移動した挙動を同じ動きをする
	change_range_slider();
}, false);

// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
	animation1.cancel();
	display_dom.innerHTML = animation1.playState;
}, false);

// スライダ値を取得しイベントを付与する
range1_dom.addEventListener('input', change_range_slider);
function change_range_slider()
{
	// 設定値を画面出力
	document.getElementById('range1_value').innerHTML = (range1_dom.value / 10) + '秒後に再生する';

	// 一旦アニメーションを停止する
	animation1.cancel();

	// アニメーションの再生位置を変更する
	animation1.startTime = animation1.timeline.currentTime + (range1_dom.value * 100);

	// divタグの状態を出力する
	display_dom.innerHTML = animation1.playState;
}

// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック

</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスしてスライダを操作すると、N秒後にアニメーションが開始されます。
スライダを変更すると都度、N秒後にアニメーションが開始されることと、現在位置としてcurrentTime秒が変化することがわかります。

SVGアニメーション – Web Animations API を使う – アニメーション実行中の再生位置について

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行中の再生位置について

前回の投稿(https://propansystem.net/blog/9976)で、再生時のステータス値を確認するサンプルを用意しました。

ここでは、再生時の再生位置(秒)を取得するサンプルを書いて試してみます。

再生位置はcurrentTimeプロパティの値を取得することで得られます。
また、下記サンプルでは0.01秒ごとに取得した値を画面描画しています。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottomStart {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #cccccc;
    font-size        : 1.1rem;
    width            : 150px;
}
.range {
    width: 100%; /* スライダーの幅を画面最大に */
}
</style>
</head>
<body>
<!-- 開始ボタン -->
<div id="bottomStart">
    <input type="button" id="start_animate"  value="アニメーション開始">
    <input type="button" id="cancel_animate" value="アニメーション停止">
</div>
<!-- 再生秒数の表示 -->
再生秒数:<span class="params" id="currentTime_value"></span>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>

<script>
// DOM要素取得
let start_animate_dom  = document.querySelector("#start_animate" );
let cancel_animate_dom = document.querySelector("#cancel_animate");
let display_dom        = document.querySelector("#display"       );
let test1_dom          = document.querySelector("#test1_dom"     );
let range1_dom         = document.querySelector("#range1"        );

// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(500px)'},
];
// option定義
const options1 = {
    duration   : 10000, // 100秒で一周
    iterations : Infinity
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	animation1.play();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
	animation1.cancel();
	display_dom.innerHTML = animation1.playState;
}, false);

// 再生秒数を定期的に更新する
setInterval(() => {
    // アニメーションが再生中の場合に秒数を更新
    if (animation1.playState === 'running') {
        // currentTimeはミリ秒で返されるので、秒に変換して表示
        let disp_sec = (animation1.currentTime / 1000).toFixed(2) + '秒';
        document.getElementById('currentTime_value').innerHTML = disp_sec;
    }
}, 10); // 0.01秒ごとにチェック

</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスして「アニメーション開始」ボタンを押下します。

ボタンのすぐ下に「再生秒数」がリアルタイムに表示され、値が取得できていることが確認できます。

SVGアニメーション – Web Animations API を使う – アニメーション実行中の再生倍率について

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行中の再生倍率について

前回の投稿(https://propansystem.net/blog/9978)で、逆再生を行う方法としてplaybackRateプロパティを使用する方法をとりあげました。

ここでは、playbackRateについて再生倍率を制御する目的で試してみます。

簡単なサンプルを書いて試してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottomStart {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #cccccc;
    font-size        : 1.1rem;
    width            : 150px;
}
.range {
    width: 100%; /* スライダーの幅を画面最大に */
}
</style>
</head>
<body>
<!-- 開始ボタン -->
<div id="bottomStart">
    <input type="button" id="start_animate"  value="アニメーション開始">
    <input type="button" id="cancel_animate" value="アニメーション停止">
</div>
<!-- スライダ -->
<div class="params_box">
	<span class="param_title">再生倍率調整</span>
	<div><input type="range" class="range" id="range1" value="0" max="1000"></div>
	<span class="params" id="range1_value"></span>
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>

<script>
// DOM要素取得
let start_animate_dom  = document.querySelector("#start_animate" );
let cancel_animate_dom = document.querySelector("#cancel_animate");
let display_dom        = document.querySelector("#display"       );
let test1_dom          = document.querySelector("#test1_dom"     );
let range1_dom         = document.querySelector("#range1"        );

// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(500px)'},
];
// option定義
const options1 = {
    duration   : 100000, // 100秒で一周
    iterations : Infinity
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	animation1.play();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
	animation1.cancel();
	display_dom.innerHTML = animation1.playState;
}, false);

// スライダの要素を取得し、再生速度調整用のイベントを付与する
range1_dom.addEventListener('input', change_range_slider);
function change_range_slider()
{
	// パターン内のDOM情報を取得する
	let set_param_value = range1_dom.value;

	// アニメーションの再生速度(playbackRate)を変更する
	animation1.playbackRate = set_param_value;

	// 設定値を画面出力
	document.getElementById('range1_value').innerHTML = range1_dom.value + '倍';
}

</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスして「アニメーション開始」ボタンを押下したあと、「再生倍率調整」のスライダを動かすと再生時の倍率を1~1000で変更することができます。

アニメーションは「DIVタグをx軸法j広告に100秒かけて500px移動する」というシンプルなもので、optionsで「iterations : Infinity」を指定して無限に繰り返すようになっています。

アニメーション開始ボタンを押下して、スライダを動かすと再生倍率が変わりDIVタグの移動スピードが変化することがわかります。

これはあくまでも再生倍率なので、divタグの移動スピードを早めている訳ではないことに注意が必要です。

SVGアニメーション – Web Animations API を使う – アニメーション実行中のreverse()メソッドと、iterationsプロパティのInfinityについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行中のreverse()メソッドと、iterationsプロパティのInfinityについて

前回の投稿(https://propansystem.net/blog/9976)で、option定義でiterations属性の値を「Infinity」にしたサンプルを試します。

前回のサンプルのOptions定義「iterations」プロパティに「Infinity」の値を追加し、
アニメーション開始後にreverse()メソッドを有効にする逆再生ボタンを押下するとjavascriptエラーになります。

Uncaught InvalidStateError: Failed to execute 'reverse' on
 'Animation': Cannot play reversed Animation with infinite target effect end.
 at HTMLInputElement.<anonymous> 

「Infinity」プロパティを有効にすると無限再生することになる為、終了状態を持たない為エラーになります。

SVGアニメーション – Web Animations API を使う – アニメーション実行中のreverseメソッドとplaybackRateプロパティについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行中のreverseメソッドとplaybackRateプロパティについて

前回投稿したサンプルをもとに、アニメーション実行中のreverseの動きを詳しくみてみます。

まず、通常のアニメーション再生ではplay()メソッドを使い、「アニメーション開始→アニメーション終了」まで順再生されます。

次に下記のように逆再生(reverse()メソッド)を使った場合は、アニメーションが逆再生されます。

// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
	//animation1 = test1_dom.animate(keyframes1, options1);
	animation1.reverse();
	display_dom.innerHTML = animation1.playState;
}, false);

この時、逆再生中にもう一度「アニメーション逆再生」ボタンを押下すると順再生に戻ります。
これは「逆再生の逆は順再生」という意味の挙動になります。

別な逆再生の例として「Animation.playbackRate」をあげます。
本来の指定の仕方では逆再生用のプロパティではなく「再生速度の倍率」を表します。
playbackRateの値を「2」にすると、再生倍率は2倍になり、
「3」にすると再生倍率は3倍になります。

また負の数では逆方向への再生になり、「-2」だと逆再生方向に2倍の速度でアニメーションします。
「0」の場合にはアニメーションは停止します。

注意点としては、この「playbackRate」の値が「負の数値」を使った場合は、reverse()メソッドにかかわらず逆再生される点です。

SVGアニメーション – Web Animations API を使う – アニメーション実行中のplayStateの値について

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行中のplayStateの値について

アニメーション実行中にanimationしているオブジェクトのplayStateプロパティを参照することで、実行状態が見えます。
playStateは以下のものがあります。

開始
一時停止
逆再生
終了
停止

実際にサンプルを用意して確かめてみると、逆再生の時の値は「running」と表示され、通常の開始と同じ値になります。(ただしDIVのアニメーションの動きは逆です)

以下に簡単なサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottomStart {
    margin-bottom    : 10px;
}
#test1_dom {
    color            : #5f5d5d;
    background-color : #eeeeee;
    font-size        : 1.1rem;
    width            : 150px;
}
</style>
</head>
<body>
<!-- 開始ボタン -->
<div id="bottomStart">
    <input type="button" id="start_animate"   value="アニメーション開始"    >
    <input type="button" id="pause_animate"   value="アニメーション一時停止">
    <input type="button" id="reverse_animate" value="アニメーション逆再生"  >
    <input type="button" id="finish_animate"  value="アニメーション終了"    >
    <input type="button" id="cancel_animate"  value="アニメーション停止"    >
</div>
<!-- アニメーション用DIV -->
<div id="test1_dom">TEST1 (<span id="display"></span>)</div>
<!-- 状態表示 -->

<script>
// DOM要素取得
let start_animate_dom   = document.querySelector("#start_animate"  );
let pause_animate_dom   = document.querySelector("#pause_animate"  );
let reverse_animate_dom = document.querySelector("#reverse_animate");
let finish_animate_dom  = document.querySelector("#finish_animate" );
let cancel_animate_dom  = document.querySelector("#cancel_animate" );
let display_dom         = document.querySelector("#display"        );
let test1_dom           = document.querySelector("#test1_dom"      );
// アニメーション用オブジェクト
let animation1;
// keyframes定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];
// option定義
const options1 = {
    duration   : 10000
};
animation1 = test1_dom.animate(keyframes1, options1);
animation1.cancel(); // 初期値は停止

// アニメーション開始
start_animate_dom.addEventListener('click', (e) => {
	//animation1 = test1_dom.animate(keyframes1, options1);
	animation1.play();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション一時停止
pause_animate_dom.addEventListener('click', (e) => {
	//animation1 = test1_dom.animate(keyframes1, options1);
	animation1.pause();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション逆再生
reverse_animate_dom.addEventListener('click', (e) => {
	//animation1 = test1_dom.animate(keyframes1, options1);
	animation1.reverse();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション終了
finish_animate_dom.addEventListener('click', (e) => {
	//animation1 = test1_dom.animate(keyframes1, options1);
	animation1.finish();
	display_dom.innerHTML = animation1.playState;
}, false);
// アニメーション停止
cancel_animate_dom.addEventListener('click', (e) => {
	//animation1 = test1_dom.animate(keyframes1, options1);
	animation1.cancel();
	display_dom.innerHTML = animation1.playState;
}, false);

</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

SVGアニメーション – Web Animations API を使う – アニメーション実行中にKeyFrameEffectのcompositeプロパティを変更した場合の挙動について

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – アニメーション実行中にKeyFrameEffectのcompositeプロパティを変更した場合の挙動について

アニメーション実行中にKeyFrameEffectのcompositeプロパティをスクリプトから変更することができます。
compositeプロパティはアニメーションのkeyframeの複数の項目がある場合、
その複数の項目の値をどのように設定するかを制御します。

例えばdivが画面上に2つある場合、一つをDivAとし、もう一つをDivBとする場合、
DivAに設定されたkeyframeの項目とDivBに設定されたkeyframeの項目の値をどのようにするかを制御します。

ここでは「DivA」と「DivB」をもとに掘り下げてみます。

ボタンは「add」「accumulate」「replace」3種類あり、それぞれ以下の挙動になります。

①add

DivAとDivBのkeyframeのプロパティを加算(合算)します。
例えばDivAに、以下のkeyframeが設定されており、

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(150px)'},
];

DivBに、以下のkeyframeが設定されている場合、

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

addした結果は以下のようになります。

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(150px)'},
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

②accumulate

DivAとDivBのkeyframeのプロパティを累積します。
例えばDivAに、以下のkeyframeが設定されており、

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(150px)'},
];

DivBに、以下のkeyframeが設定されている場合、

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

addした結果は以下のようになります。

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(350px)'},
];

③replace

DivAとDivBのkeyframeのプロパティを上書き(置き換え)します。
例えばDivAに、以下のkeyframeが設定されており、

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(150px)'},
];

DivBに、以下のkeyframeが設定されている場合、

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

replaceした結果は以下のようになります。

[
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

(注意…説明では②accumulateと同じ値になりますが、プロパティがtranslateXのみで、2項目しかないので見かけ上は同様になります)

上記にまとめた挙動を確認する為
画面上のボタン押下によってアニメーション再生中にcompositeプロパティを動的に変更した時の動きを確認できるサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
<style>
#bottomStart {
    margin-bottom    : 10px;
}
#pseudoElementTest1 {
    color            : #5f5d5d;
    background-color : #ffdfdf;
    font-size        : 1.1rem;
    width            : 100px;
}
#pseudoElementTest2 {
    color            : #5f5d5d;
    background-color : #f4f4f4;
    background-color : #dfe7ff;
    font-size        : 1.1rem;
    width            : 100px;
}
</style>
</head>
<body>
<!-- 開始ボタン -->
<div id="bottomStart">
    <input type="button" id="animate_timline_test" value="アニメーション開始">
</div>

<!-- 変更ボタン -->
<input type="button" id="set_composite_add"        value="addに変更">
<input type="button" id="set_composite_accumulate" value="accumulateに変更">
<input type="button" id="set_composite_replace"    value="replaceに変更">

<!-- 状態 -->
<div>現在の状態:<span id="pseudoElementDisp"></span></div>

<!-- アニメーション用DIV -->
<div id="pseudoElementTest1">TEST1</div>
<div id="pseudoElementTest2">TEST2</div>
<script>
//--------------------------------
// DOM要素取得
//--------------------------------
let animateTimlineTestDom = document.querySelector("#animate_timline_test");
let pseudoElementTest1Dom = document.querySelector("#pseudoElementTest1");
let pseudoElementTest2Dom = document.querySelector("#pseudoElementTest2");
let pseudoElementDispDom  = document.querySelector("#pseudoElementDisp");

// プロパティ変更ボタン
let dom_set_composite_add        = document.getElementById('set_composite_add');
let dom_set_composite_accumulate = document.getElementById('set_composite_accumulate');
let dom_set_composite_replace    = document.getElementById('set_composite_replace');

//--------------------------------
// アニメーション用定義
//--------------------------------
// アニメーション用オブジェクト
let animation1;
let animation2;
// keyframesの定義
const keyframes1 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(150px)'},
];
const keyframes2 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

// アニメーション開始ボタン
animateTimlineTestDom.addEventListener('click', (e) => {
    // デフォルトはaddにする
    updateanimation('add');
}, false);

// 「addに変更」
dom_set_composite_add.addEventListener('click', () => {
    updateanimation('add');
}, false);

// 「accumulateに変更」
dom_set_composite_accumulate.addEventListener('click', () => {
    updateanimation('accumulate');
}, false);

// 「replaceに変更」
dom_set_composite_replace.addEventListener('click', () => {
    updateanimation('replace');
}, false);

// 引数に基づいたアニメーションの開始
function updateanimation(upd_composite)
{
    // 画面表示
    pseudoElementDispDom.innerHTML = upd_composite;

    // optionの定義
    const currentOptions1 = {
        duration   : 15000,
        iterations : Infinity
    };
    const currentOptions2 = {
        duration   : 15000,
        iterations : Infinity,
        composite  : upd_composite // このタイミングでcompositeの値を更新
    };

    // オプションを設定する
    animation1 = pseudoElementTest1Dom.animate(keyframes1, currentOptions1);
    // オプションを設定する
    animation2 = pseudoElementTest2Dom.animate(keyframes2, currentOptions2);

    // アニメーション開始
    animation1.play();
    animation2.play();
}

</script>
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスして「アニメーション開始」を押下します。
すると、画面上の2つのdivタグがアニメーションします。
アニメーション中に「addに変更」「accumulateに変更」「replaceに変更」のいずれかのボタンを押下すると、
2つめのDiv「TEST2」のcompositeプロパティの値が動的に変化します。

「アニメーション開始」ボタン押下後、addに変更ボタンを押下するとDivタグ「pseudoElementTest2」のcurrentOptions2プロパティが変わり、

const keyframes2 = [
    {transform: 'translateX(0px)'  },
    {transform: 'translateX(200px)'},
];

のプロパティの値が動的に変わる(この場合は項目の加算)ことがわかります。

また、「accumulateに変更」ボタン、「replaceに変更」ボタンを押下した時も同様に変化することがわかります。

さらに、アニメーション中に「accumulateに変更」ボタンをN回押下するとプロパティが更新された後、
また「accumulateに変更」ボタンを押下すると値が累積してアニメーションすることがわかります。
この場合はtranslateXの値がN回押下分累積した値になることがわかります。

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのタイミングプロパティを変更する

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのタイミングプロパティを変更する

KeyFrameEffectのタイミングプロパティをスクリプトから変更することができます。

画面上のボタン押下によってアニメーション再生中にタイミングプロパティを変更するサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="animate_timline_test" value="animate start">
<div>
<input type="button" id="set_timing_1" value="タイミングプロパティ1に更新">
<input type="button" id="set_timing_2" value="タイミングプロパティ2に更新">
</div>

<div class="KeyframeEffectDom">
    <div>タイミングプロパティ -> <span id="timing"></span></div>
</div>

<div class="animate_timeline_dom">TestDom</div>

<script>

let keyf = [
    {transform: "translateX(0px)"  },
    {transform: "translateX(400px)"},
];

// タイミングプロパティ1
let time1 = {
    direction : 'normal',
    duration  : 5000
};

// タイミングプロパティ2
let time2 = {
    direction : 'reverse',
    duration  : 10000
};

let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

let keyframes_test = new KeyframeEffect(
    animate_timeline_dom,
    keyf,
    time1
);

let anim_test = new Animation(
    keyframes_test,
    document.timeline,
);

let timingdom = document.querySelector("#timing");
timingdom.innerHTML = 'タイミングプロパティ 1';

animate_timline_test.addEventListener('click', () => {
    anim_test.play();
}, false);

set_timing_1.addEventListener('click', () => {
	timingdom.innerHTML = 'タイミングプロパティ 1';
	anim_test.effect.updateTiming(time1); // タイミングプロパティ1 のセット
}, false);

set_timing_2.addEventListener('click', () => {
	timingdom.innerHTML = 'タイミングプロパティ 2';
	anim_test.effect.updateTiming(time2); // タイミングプロパティ2 のセット
}, false);

</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスして「Animate Startボタン」を押下します。
初期値ではタイミングプロパティ1がセットされています。
アニメーション中に「タイミングプロパティ2に更新」ボタンを押下すると、
途中でタイミングプロパティ2の値に切り替わり、アニメーションが
「direction : ‘reverse’」の為に逆再生になります。

今回はわかりやすいようにkeyframeは固定しています。
なので、transformでdomの移動方向は変更していません。

また、タイミングプロパティ2の再生中に、ふたたび「タイミングプロパティ1に更新」ボタンを押下すると、アニメーションは順再生に戻ります。

再生時間が終了していなければ、何度でも切り替えて動作することが確認できます。

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのkeyframeを変更する

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのkeyframeを変更する

KeyFrameEffectのkeyframeをスクリプトから変更することができます。

画面上にkeyframeを変更するボタンを設置し、ボタン押下によってアニメーション再生中にkeyfarmeを変更するサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="animate_timline_test" value="animate start">
<input type="button" id="set_keyframe_1"       value="set [keyframe 1]">
<input type="button" id="set_keyframe_2"       value="set [keyframe 2]">

<div class="KeyframeEffectDom">
    <div>keyframe -> <span id="keyframe"></span></div>
</div>

<div class="animate_timeline_dom">TestDom</div>

<script>

let keyf1 = [
    {transform: "translateX(0px)"  },
    {transform: "translateX(400px)"},
    {transform: "translateY(300px)"},
    {transform: "scale(2)"         },
];

let keyf2 = [
    {transform: "scale(1)"         },
    {transform: "scale(0.2)"       },
    {transform: "translateY(300px)"},
    {transform: "scale(3)"         },
    {transform: "translateX(500px)"},
];

let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

let keyframes_test = new KeyframeEffect(
    animate_timeline_dom,
    keyf1,
    {
        duration: 5000,
        delay   : 100,
        endDelay: 300
    }
);

let anim_test = new Animation(
    keyframes_test,
    document.timeline,
);


let keyframedom = document.querySelector("#keyframe");
keyframedom.innerHTML = 'keyframe 1';

animate_timline_test.addEventListener('click', () => {
    anim_test.play();
}, false);

set_keyframe_1.addEventListener('click', () => {
	keyframedom.innerHTML = 'keyframe 1';
	anim_test.effect.setKeyframes(keyf1); // keyframe 1 のセット
}, false);

set_keyframe_2.addEventListener('click', () => {
	keyframedom.innerHTML = 'keyframe 2';
	anim_test.effect.setKeyframes(keyf2); // keyframe 2 のセット
}, false);

</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスし、set [keyframe 1]および、set [keyframe 2]ボタンを押下し、
animate startボタンを押下すると、変更されたkeyframeでアニメーションされることがわかります。

以下の画像は実行時の画面キャプチャです。

アニメーション操作を複数回していますが、最後のアニメーション再生の際には、アニメーション途中でkeyframeの変更ボタンを押下していますが、アニメーション再生中でもkeyframeが動的に切り替わっていることがわかります。

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのタイミングプロパティをgetComputedTimingを使って確認する

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのタイミングプロパティをgetComputedTimingを使って確認する

KeyFrameEffectのタイミングプロパティをgetComputedTimingを使って取得できるので、その内容がどうなっているのかを確認します。

サンプル全体はこちら

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate timline test">
<div class="animate_timeline_dom">Test DOM</div>

<div class="KeyframeEffectDom">
    <div>getComputedTiming -> </div>
    <div id="KeyframeEffectDom1"></div>
</div>

<script>

button_1.addEventListener('click', () => {

    // DOM要素を取得
    let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

    let keyframes_test = new KeyframeEffect(
        animate_timeline_dom,
        [
            {transform: "translateX(0px)"  },
            {transform: "translateX(200px)"},
            {transform: "translateY(100px)"},
            {transform: "scale(2)"         },
        ],
        {
            duration: 5000,
            delay   : 100,
            endDelay: 300
        }
    );
    
    let anim_test = new Animation(
        keyframes_test,
        document.timeline,
    );

    // アニメーションの再生
    anim_test.play();
    
    // 画面表示用DOMを取得する
    let keyframeeffectdom1 = document.querySelector("#KeyframeEffectDom1");

    let keyframeeffectdom1obj = anim_test.effect.getComputedTiming();

    for(var key in keyframeeffectdom1obj){
        keyframeeffectdom1.innerHTML += key + ' -> ' + keyframeeffectdom1obj[key] + '<br />';
    }

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

実行して内容を確認すると、画面上には以下の出力になります。

getKeyframes ->
delay -> 100
direction -> normal
duration -> 5000
easing -> linear
endDelay -> 300
fill -> none
iterationStart -> 0
iterations -> 1
activeDuration -> 5000
currentIteration -> null
endTime -> 5399.999999999999
localTime -> 0
progress -> null

という出力になります。

この結果から KeyframeEffectのタイミングプロパティで指定した3つのプロパティ

duration: 5000,
delay   : 100,
endDelay: 300

がそれぞれ取得していることがわかります。

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのプロパティをgetKeyframesを使って確認する

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのプロパティをgetKeyframesを使って確認する

KeyFrameEffectのプロパティをgetKeyframesを使って取得できるので、その内容がどうなっているのかを確認します。

前回のサンプルを少し変えて、getKeyframesで取得した値を画面に出力するものを用意しました。
サンプル全体はこちら

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate timline test">
<div class="animate_timeline_dom">Test DOM</div>

<div class="KeyframeEffectDom">
    <div>getKeyframes -> </div>
    <div id="KeyframeEffectDom1"></div>
</div>

<script>

button_1.addEventListener('click', () => {

    // DOM要素を取得
    let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

    let keyframes_test = new KeyframeEffect(
        animate_timeline_dom,
        [
            {transform: "translateX(0px)"  },
            {transform: "translateX(200px)"},
            {transform: "translateY(100px)"},
            {transform: "scale(2)"         },
        ],
        { duration: 5000 },
    );
    
    let anim_test = new Animation(
        keyframes_test,
        document.timeline,
    );

    // アニメーションの再生
    anim_test.play();
    
    // 画面表示用DOMを取得する
    let keyframeeffectdom1 = document.querySelector("#KeyframeEffectDom1");

    let keyframeeffectdom1obj = anim_test.effect.getKeyframes();

    // DOMに取得内容を出力する
    keyframeeffectdom1obj.forEach(function(_x) {
        for(var key in _x){
            keyframeeffectdom1.innerHTML += key + ' -> ' + _x[key] + '<br />';
        }
        keyframeeffectdom1.innerHTML += '----------------<br />';
    });

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

実行して内容を確認すると、画面上には以下の出力になります。

getKeyframes ->
offset -> null
easing -> linear
composite -> auto
transform -> translateX(0px)
computedOffset -> 0
----------------
offset -> null
easing -> linear
composite -> auto
transform -> translateX(200px)
computedOffset -> 0.3333333333333333
----------------
offset -> null
easing -> linear
composite -> auto
transform -> translateY(100px)
computedOffset -> 0.6666666666666666
----------------
offset -> null
easing -> linear
composite -> auto
transform -> scale(2)
computedOffset -> 1
----------------

という出力になります。

この結果から KeyframeEffectで指定した4つのプロパティ

{transform: "translateX(0px)"  },
{transform: "translateX(200px)"},
{transform: "translateY(100px)"},
{transform: "scale(2)"         },

がそれぞれ取得していることがわかります。

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのプロパティを確認する

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – KeyFrameEffectのプロパティを確認する

前回投稿したAnimationの第一引数「keyframes_test」は

animation の基本構文

var animation = new Animation([effect][, timeline]);

のeffectにあたり、KeyFrameEffectオブジェクトと言えます。

このオブジェクトのプロパティを出力して調べてみます。

前回のスクリプトにconsole.logを追加し、KeyFrameEffectオブジェクトの下記のプロパティを出力してみます。

target
pseudoElement
iterationComposite
composite

サンプル全体はこちら

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate timline test">
<div class="animate_timeline_dom">Test DOM</div>

<script>

button_1.addEventListener('click', () => {

	// DOM要素を取得
	let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

	let keyframes_test = new KeyframeEffect(
		animate_timeline_dom,
		[
			{transform: "translateX(0px)"  },
			{transform: "translateX(200px)"},
			{transform: "translateY(100px)"},
			{transform: "scale(2)"         },
		],
		{ duration: 5000 },
	);
	
	let anim_test = new Animation(
		keyframes_test,
		document.timeline,
	);

    // アニメーションの再生
    anim_test.play();
    
    console.log("anim_test effect             -> " + anim_test.effect);
    console.log("anim_test target             -> " + anim_test.effect.target);
    console.log("anim_test pseudoElement      -> " + anim_test.effect.pseudoElement);
    console.log("anim_test iterationComposite -> " + anim_test.effect.iterationComposite);
    console.log("anim_test composite          -> " + anim_test.effect.composite);

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

実行して内容を確認すると

anim_test effect             -> [object KeyframeEffect]
anim_test target             -> [object HTMLDivElement]
anim_test pseudoElement      -> null
anim_test iterationComposite -> undefined
anim_test composite          -> replace

という出力になります。

SVGアニメーション – Web Animations API を使う – KeyFrameEffectについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – KeyFrameEffectについて

KeyFrameEffectを試します。

基本構文

new KeyframeEffect(target, keyframes)
new KeyframeEffect(target, keyframes, options)
new KeyframeEffect(sourceKeyFrames)

サンプル

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate timline test">
<div class="animate_timeline_dom">Test DOM</div>

<script>

button_1.addEventListener('click', () => {

	// DOM要素を取得
	let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

	let keyframes_test = new KeyframeEffect(
		animate_timeline_dom,
		[
			{transform: "translateX(0px)"  },
			{transform: "translateX(200px)"},
			{transform: "translateY(100px)"},
			{transform: "scale(2)"         },
		],
		{ duration: 5000 },
	);
	
	let anim_test = new Animation(
		keyframes_test,
		document.timeline,
	);

    // アニメーションの再生
    anim_test.play();

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

サンプルでは、以下の箇所がKeyframeEffectを使用した定義です。

	let keyframes_test = new KeyframeEffect(
		animate_timeline_dom,
		[
			{transform: "translateX(0px)"  },
			{transform: "translateX(200px)"},
			{transform: "translateY(100px)"},
			{transform: "scale(2)"         },
		],
		{ duration: 5000 },
	);

targetは対象のDOM
keyframesは任意のアニメーションの内容を指定
optionsは任意のタイミングプロパティの内容を指定

前回の投稿で、animation の基本構文を書きました。

var animation = new Animation([effect][, timeline]);

この「effect」については、次の定義になります。

(MDNから抜粋)
このアニメーションに関連付けられた AnimationEffect を取得または設定します。
これはふつう、 KeyframeEffect オブジェクトになります。

上記のサンプルで、アニメーションの定義を次のようにしていますが、

	let anim_test = new Animation(
		keyframes_test,
		document.timeline,
	);

「keyframes_test」という記述が「new KeyframeEffect」したものであり、それが「new Animation([effect][, timeline]);」のeffectとして割り当てていると言えます。

new Animation の引数に new KeyframeEffect を記述する

new Animationの引数に直接new keyframeEffectを記述する例です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #cccccc;
    width: 150px;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate timline test">
<div class="animate_timeline_dom">Test DOM</div>

<script>

button_1.addEventListener('click', () => {

	let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

	let anim_test = new Animation(
		new KeyframeEffect(
			animate_timeline_dom,
			[
				{transform: "translateX(0px)"  },
				{transform: "translateX(200px)"},
				{transform: "translateY(100px)"},
				{transform: "scale(2)"         },
			],
			{ duration: 5000 },
		),
		document.timeline,
	);

    // アニメーションの再生
    anim_test.play();

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test2.html)

SVGアニメーション – Web Animations API を使う – timelineについて

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – timelineについて

前回、animationの再生は、以下のように書きました。

var animation = new Animation([effect][, timeline]);

引数のtimelineについて試してみます。
前回のサンプルにtimelineの値を出力してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #ebebeb;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate timline test">
<div class="animate_timeline_dom">test</div>
<div id="log_disp"></div>

<script>
 
// animate timline testボタンの押下
let dom_button_1 = document.getElementById('button_1');

button_1.addEventListener('click', () => {

	// DOM要素を取得
	let animate_timeline_dom = document.querySelector(".animate_timeline_dom");

	// アニメーションのeffectとtimelineを定義
	animation = animate_timeline_dom.animate(
		[
			{ backgroundColor: '#fff', width:'100px'},
			{ backgroundColor: '#999', width:'50px' },
		],
		{
	    	duration: 8000
	    }
	);

	// timelineの値を出力して確認
	let log_disp_dom = document.getElementById('log_disp');

	const log_output = () => {
		let log_str = "";
		log_str += "animation.timeline.currentTime -> " + animation.timeline.currentTime.toFixed(2) + "<br />";
		log_str += "animation.startTime            -> " + animation.startTime.toFixed(2)            + "<br />";
		log_str += "animation.currentTime          -> " + animation.currentTime.toFixed(2)          + "<br />";
		log_disp_dom.innerHTML = log_str;
	}

	setInterval(log_output, 10);

    // アニメーションの再生
    animation.play();

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスしてanimate timeline test ボタンを押下すると
8秒かけて、domの長さと色が変化するアニメーションが始まります。

ここで注意したい点は

animation.timeline.currentTime
animation.startTime
animation.currentTime

で、それぞれどんな値(秒数)が取得できているかという点です。

currentTimeは画面が表示されてからの秒数がカウントされています。
animation.startTimeは、ボタンを押下してアニメーションが開始された秒数です。
animation.currentTimeは、アニメーションが再生されている秒数で、アニメーションが終了するとリセットされます。

試しに8秒以上経過した後に、もう一度、animate timeline test ボタンを押下する(例では2回押下)とどうなるか、試してみます。

動きを見ると、animation.timeline.currentTime は画面が表示されてからリセットされずに秒数カウントがされてます。
animation.startTime はボタンを押したタイミングでのanimation.timeline.currentTimeの値を取得しています。
animation.currentTimeは上記の例と同様、アニメーションの再生中の秒数をカウントしており、再生が終わるとリセットされていることがわかります。

SVGアニメーション – Web Animations API を使う – 基本的な記述

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – 基本的な記述

Animation()によるAnimationオブジェクトの生成を試します。

animationオブジェクトを生成する際の第二引数に用い、AnimationTimelineというインタフェースを取得している。

var animation = new Animation([effect][, timeline]);

これまで紹介してきた

Element.animate()

とは異なり、play()メソッドでアニメーションを開始する。

まずはこれまでの Element.animate() の書き方でサンプルを用意し、それをもとに、その後 animation = new Animation を試します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.animate_timeline_dom {
    background-color: #ebebeb;
}
</style>

</head>
<body>

<input type="button" id="button_1" value="animate test">
<div class="animate_dom">test</div>
<div id="log_disp"></div>

<script>

// アニメーション用の空オブジェクトを定義
let animation;

// 「animate test」ボタンのDOM取得と押下イベントの用意
let dom_button_1 = document.getElementById('button_1');
button_1.addEventListener('click', () => {

    // DOM要素を取得
    let animate_dom = document.querySelector(".animate_dom");

    // アニメーションの effect と timeline を定義
    animation = animate_dom.animate(
        [
            {backgroundColor: '#fff', width:'100px'},
            {backgroundColor: '#999', width:'50px' },
        ],
        {
            duration: 8000
        }
    );

    // アニメーションの再生
    animation.play();

}, false);
</script>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

いままでは Element.animate() という形でアニメーションを定義、再生していましたが、
Web Animation API のインターフェースとしてのAnimationを使用し、

animation.play();

というメソッドでアニメーション再生しています。

画面にアクセスして、animate testボタンを押下した時の動きは以下のようになります。

duration: 8000 の定義をしているので、8秒かけて
{backgroundColor: ‘#fff’, width:’100px’}
から
{backgroundColor: ‘#999′, width:’50px’ }
へアニメーションしていることがわかります。

SVGアニメーション – Web Animations API を使う – Animation

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Animation

ここからは Animation のAPI(インターフェイス) を使用した方法を試します。

Animation のAPIのプロパティとメソッド

プロパティ

Animation.currentTime
Animation.effect
Animation.finished
Animation.id
Animation.pending
Animation.playState
Animation.playbackRate
Animation.ready
animation.replaceState
Animation.startTime
Animation.timeline

メソッド

Animation.cancel()
Animation.finish()
Animation.pause()
Animation.play()
Animation.reverse()

(MDNから抜粋)

Animation()によるAnimationオブジェクトの生成

animationオブジェクトを生成するには以下のように書きます。

var animation = new Animation([effect][, timeline]);

引数はそれぞれ以下の指定をします。

effect
アニメーションに割り当てるエフェクト効果を指定。
現時点ではKeyFrameEffectオブジェクトのみ。

timeline
アニメーションに関連づけるtimelineを指定
現時点ではDocumentTimelineオブジェクトのみ。

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – 同一DOM要素に多重付与したanimate()をcomposite合成する

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – 同一DOM要素に多重付与したanimate()をcomposite合成する

同一DOM要素に多重に付与した animate()を合成するには、compositeプロパティを使用します。

このプロパティには下記の3つのうち、いずれかを指定します。

replace
add
accumulate

composite プロパティに「replace」を指定する場合

replace を指定した場合
transform の値は keyframes2 のtransformの値に置き換わって制御されます。
width と backgroundColor はそのまま keyframes1 の値が制御されます
(keyframes2と別項目なので置き換わりません)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.pseudoElementTest {
    color: #000000;
    font-size: 1.2rem;
    width: 100px;
}
</style>

</head>
<body>

<div class="pseudoElementTest">test</div>
<input type="button" id="button_test1" value="pseudoElementTest1">

<script>
// DOM要素を取得
let pseudoElementTest = document.querySelector(".pseudoElementTest");

// アニメーション用
let animation1;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {transform: 'translateX(0px)'  , width:'100px', backgroundColor:'#FF6600'},
    {transform: 'translateX(100px)', width:'50px' , backgroundColor:'#669933'},
];

// アニメーション2 keyframesの定義
const keyframes2 = [
    {transform: 'translateY(0px)'  },
    {transform: 'translateY(100px)'},
];

// botton1
let dom_test1 = document.getElementById('button_test1');

// botton1押下
dom_test1.addEventListener('click', () => {

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }

    const currentOptions1 = {
        duration      : 8000
    };

    const currentOptions2 = {
        duration      : 8000,
        composite     : 'replace'
    };

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes1, currentOptions1);

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes2, currentOptions2);

    // アニメーション1の再生と停止
    animation1.play();
}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

composite プロパティに「add」を指定する場合

add を指定した場合
transform の値は keyframes1とkeyframes2 のtransformの値が加算されて制御されます。
width と backgroundColor はそのまま keyframes1 の値が制御されます
(keyframes2と別項目なので加算もされず、置き換わりもしません)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.pseudoElementTest {
    color: #000000;
    font-size: 1.2rem;
    width: 100px;
}
</style>

</head>
<body>

<div class="pseudoElementTest">test</div>
<input type="button" id="button_test1" value="pseudoElementTest1">

<script>
// DOM要素を取得
let pseudoElementTest = document.querySelector(".pseudoElementTest");

// アニメーション用
let animation1;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {transform: 'translateX(0px)'  , width:'100px', backgroundColor:'#FF6600'},
    {transform: 'translateX(100px)', width:'50px' , backgroundColor:'#669933'},
];

// アニメーション2 keyframesの定義
const keyframes2 = [
    {transform: 'translateY(0px)'  },
    {transform: 'translateY(100px)'},
];

// botton1
let dom_test1 = document.getElementById('button_test1');

// botton1押下
dom_test1.addEventListener('click', () => {

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }

    const currentOptions1 = {
        duration      : 8000
    };

    const currentOptions2 = {
        duration      : 8000,
        composite     : 'add'
    };

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes1, currentOptions1);

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes2, currentOptions2);

    // アニメーション1の再生と停止
    animation1.play();
}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

composite プロパティに「accumulate」を指定する場合

accumulate を指定した場合
transform の値は keyframes1とkeyframes2 のtransformの値が累積されて制御されます。
width と backgroundColor はそのまま keyframes1 の値が制御されます
(keyframes2と別項目なので累積もされず、置き換わりもしません)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.pseudoElementTest {
    color: #000000;
    font-size: 1.2rem;
    width: 100px;
}
</style>

</head>
<body>

<div class="pseudoElementTest">test</div>
<input type="button" id="button_test1" value="pseudoElementTest1">

<script>
// DOM要素を取得
let pseudoElementTest = document.querySelector(".pseudoElementTest");

// アニメーション用
let animation1;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {transform: 'translateX(0px)'  , width:'100px', backgroundColor:'#FF6600'},
    {transform: 'translateX(100px)', width:'50px' , backgroundColor:'#669933'},
];

// アニメーション2 keyframesの定義
const keyframes2 = [
    {transform: 'translateY(0px)'  },
    {transform: 'translateY(100px)'},
];

// botton1
let dom_test1 = document.getElementById('button_test1');

// botton1押下
dom_test1.addEventListener('click', () => {

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }

    const currentOptions1 = {
        duration      : 8000
    };

    const currentOptions2 = {
        duration      : 8000,
        composite     : 'accumulate'
    };

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes1, currentOptions1);

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes2, currentOptions2);

    // アニメーション1の再生と停止
    animation1.play();
}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

補足

keyframes1 では、
 transform
 width
 backgroundColor
の値を制御しており、

keyframes2 では、
 transform
の値を制御しています。

accumulateはこの例ではaddと同様の動きになりますが、keyframesの項目数が多くなり、制御する項目を設定する順番でアニメーションに作用する順が変わります。

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – 同一DOM要素に多重にanimate()を適用した場合

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – 同一DOM要素に多重にanimate()を適用した場合

同一DOM要素に多重にanimate()を適用した場合、原則「後着優先」で処理されます。

例えば、アニメーション要素が2つあり、

①アニメーション1が10秒かけて色変化する
②アニメーション2が2秒後から5秒かけて色変化する

という場合、

アニメーション開始と同時に①のアニメーションが開始→終了されます。

ただ、この①の処理中に②が同一DOM要素に対してアニメーションされた場合、①のアニメーション要素は打ち消され、②のアニメーションが優先されます。

また、②のアニメーションが短時間で終わる場合は、②のアニメーション終了後に①のアニメーションが引続き継続されます。

以下、簡単なサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.pseudoElementTest {
    color: #000000;
    font-size: 1.2rem;
}
</style>

</head>
<body>

<div class="pseudoElementTest">test</div>
<input type="button" id="button_test1" value="pseudoElementTest1">

<script>
// DOM要素を取得
let pseudoElementTest = document.querySelector(".pseudoElementTest");

// アニメーション用
let animation1;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {width:'100px', height:'50px', backgroundColor:'#FF6600'}, // オレンジ
    {width:'50px' , height:'50px', backgroundColor:'#FFFF00'}, // イエロー
];

// アニメーション2 keyframesの定義
const keyframes2 = [
    {width:'100px', height:'50px', backgroundColor:'#0033FF'}, // ブルー
    {width:'550px', height:'50px', backgroundColor:'#CC33FF'}, // パープル
];

// botton1
let dom_test1 = document.getElementById('button_test1');


// botton1押下
dom_test1.addEventListener('click', () => {

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }

    const currentOptions1 = {
        duration      : 10000
    };

    const currentOptions2 = {
        duration      : 5000,
        delay         : 2000,
    };

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes1, currentOptions1);

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes2, currentOptions2);

    // アニメーション1の再生と停止
    animation1.play();
}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面アクセスしてボタンを押下すると、アニメーション①が開始されます。

このとき、

「オレンジ → イエロー」の背景色が10秒かけて変化しますが、

2秒後にアニメーション②が開始された際、

「ブルー → パープル」のアニメーション②が優先されて開始することがわかります。

このように options が無指定でデフォルト設定の場合「後着優先」の処理がされることがわかります。

この動きを時系列の表にすると、次のアニメーションと時間の流れになります。

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – pseudoElement

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – pseudoElement

pseudoElement はDOMに記述された疑似要素セレクターの文字列(::before、::after、::marker等)に、アニメーションを適用します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.pseudoElementTest {
    color: #000000;
    font-size: 1.2rem;
}
.pseudoElementTest::before {
    content: "test1234";
}
</style>

</head>
<body>

<div class="pseudoElementTest"></div>
<input type="button" id="button_test1" value="pseudoElementTest1">

<script>
// DOM要素を取得
let pseudoElementTest = document.querySelector(".pseudoElementTest");

// アニメーション用
let animation1;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {color: '#333333', width: 200},
    {color: '#FF9900', width: 200},
    {color: '#FF5566', width: 200}
];

// botton1
let dom_test1 = document.getElementById('button_test1');


// botton1押下
dom_test1.addEventListener('click', () => {

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }

    // アニメーションのオプションを取得
    const currentOptions = {
        duration      : 3000,
        pseudoElement : '::before',
        iterations    : Infinity
    };

    // オプションを再設定する
    animation1 = pseudoElementTest.animate(keyframes1, currentOptions);

    // アニメーション1の再生と停止
    animation1.play();
}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面アクセスしてボタンを押下すると、cssの

.pseudoElementTest::before {
    content: "test1234";
}

に定義した要素(画面上ではtest1234と表示されます)の「::before」が指定されているcss要素に対してアニメーションされることがわかります。

この時、事前に定義されている「pseudoElementTest」のcss定義には影響を及ぼしていないことがわかります。

.pseudoElementTest {
    color: #000000;
    font-size: 1.2rem;
}

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – iterationStart

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – iterationStart

Element.animate()メソッド の options の iterationStart について試してみます。

iterationStart は、アニメーションの開始秒数を指定します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.params_box {
    font-size : 0.8em;
}
.range {
    width: 400px;
}
.code_view {
    font-size : 0.8em;
    padding   : 5px;
    margin    : 20px 0;
    color     : #ffffff;
    background-color: #000000;
}
.code_view_str {
    color: #ff0000;
}
.status_view {
    margin-bottom: 20px;
}

#start_animation {
	margin: 0px 0px 30px 0px;
}
#status_message1 {
	color      : #ff0000;
	font-weight: bold;
}
</style>

</head>
<body>

<div class="status_view">
    <div>ステータス1:<span id="status_message1"></span></div>
</div>

<div>
	<input type="button" id="start_animation" value="アニメーション開始">
</div>

<div>
    <div class="params_box">
        <span>iterationStart  : </span><span class="params" id="range1_value"></span>
        <div><input type="range" class="range" id="range1" value="0" max="1" step="0.1"></div>

    </div>
</div>

<div class="code_view">
const options = {<br />
&nbsp;&nbsp;&nbsp;&nbsp; duration       : <span class="code_view_str">5000</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; iterationStart : <span class="code_view_str" id="code_view1"></span><br />
&nbsp;&nbsp;&nbsp;&nbsp; iterations     : <span class="code_view_str">Infinity</span><br />
};
</div>

<svg xmlns="http://www.w3.org/2000/svg"
    width   = "500"
    height  = "100"
    viewBox = "0 0 500 100"
>
    <rect
        id     = "recttest"
        x      = "0"
        y      = "0"
        width  = "100"
        height = "50"
    />
</svg>

<script>

// アニメーション対象のDOM要素を取得
let dom_rect = document.querySelector("#recttest");

// ステータス表記
let status_message1 = document.querySelector('#status_message1');

let animation1;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {width:'100px', height:'50px', fill:'#FF6600'}, // オレンジ
    {width:'50px' , height:'50px', fill:'#FFFF00'}, // イエロー
    {width:'450px', height:'50px', fill:'#FF0000'}  // レッド
];

// スライダの要素を取得し、イベントを付与する
let dom_range1 = document.querySelector('#range1');

// 各スライダーごとのイベントに、共通の関数を割り当てて処理する
dom_range1.addEventListener('input', change_range_slider);


// スライダーを動かした時の処理
function change_range_slider()
{
    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }

    status_message1.innerHTML = '';

    // アニメーションのオプションを取得
    const currentOptions = {
        duration       : 5000,
        iterationStart : dom_range1.value,
        iterations     : Infinity
    };

    // オプションを再設定する
    animation1 = dom_rect.animate(keyframes1, currentOptions);

    // アニメーション1の再生と停止
    animation1.play();

    status_message1.innerHTML = 'アニメーション1 再生';

    // パラメータ値をHTML出力
    let range1_value_dom = document.querySelector('#range1_value');
    range1_value_dom.innerHTML = dom_range1.value;

    let code_view1_dom = document.querySelector('#code_view1');
    code_view1_dom.innerHTML = dom_range1.value;
}

// ボタン要素のDOMを取得
let dom_start_animation = document.getElementById('start_animation');

// イベントを付与
dom_start_animation.addEventListener('click',  StartAnimation, false);


// ボタン押下時の処理
function StartAnimation()
{
	console.log("ボタン押下時の処理 ");

    status_message1.innerHTML = '';

    // パラメータ値をHTML出力
    let range1_value_dom = document.querySelector('#range1_value');
    range1_value_dom.innerHTML = dom_range1.value;

    // アニメーションのオプションを取得
    const currentOptions = {
        duration       : 5000,
        iterationStart : dom_range1.value,
        iterations     : Infinity
    };

	// アニメーション1 生成
	animation1 = dom_rect.animate(keyframes1, currentOptions);

	// アニメーション1 再生
	animation1.play();
	status_message1.innerHTML = 'アニメーション1 再生';

    let code_view1_dom = document.querySelector('#code_view1');
    code_view1_dom.innerHTML = dom_range1.value;

}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

スライダーの iterationStart の値を指定し、アニメーション開始ボタンを押下すると、スライダの値(0.0~1.0)に応じた値で、アニメーションの開始タイミングが決定されます。

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – fill

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – fill

Element.animate()メソッド の options の fill について試してみます。

fill
forwards 再生後、キーを最後のフレームで保持
backwards 再生前、キーを最初のフレームに保持
both 両方を適用する
none どちらも適用しない

サンプルでは、アニメーションを2つ用意し、以下の状態変化をします。

アニメーション1 再生

アニメーション1 再生終了

アニメーション2 再生

アニメーション3 再生終了

また、アニメーション1 は暖色系の色で変化します。

オレンジ

イエロー

レッド

アニメーション2 は寒色系の色で変化します。

ブルー

パープル

グリーン

今回の animate()メソッドの options の fill については、

アニメーション1 の options に指定し、割り当てる値 (forwards, backwards, both, none)により、
どのような動きになるのかを見ます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.params_box {
    font-size : 0.8em;
}
.range {
    width: 400px;
}
.code_view {
    font-size : 0.8em;
    padding   : 5px;
    margin    : 20px 0;
    color     : #ffffff;
    background-color: #000000;
}
.code_view_str {
    color: #ff0000;
}
.status_view {
    margin-bottom: 20px;
}

#start_animation {
	margin: 0px 0px 30px 0px;
}
#status_message1, #status_message2, #fill_value {
	color      : #ff0000;
	font-weight: bold;
}
</style>

</head>
<body>

<div class="status_view">
    <div>ステータス1:<span id="status_message1"></span></div>
    <div>ステータス2:<span id="status_message2"></span></div>
</div>

<div>
    <input type="radio" name="fill_value" value="forwards" checked>forwards  (再生後、キーを最後のフレームで保持)<br />
    <input type="radio" name="fill_value" value="backwards">backwards        (再生前、キーを最初のフレームに保持)<br />
    <input type="radio" name="fill_value" value="both">both                  (両方を適用する)<br />
    <input type="radio" name="fill_value" value="none">none                  (どちらも適用しない)<br />
</div>

<div>
	<input type="button" id="start_animation" value="アニメーション開始">
</div>

<div>
    <div class="params_box">
        <span>duration (処理全体の秒数) : </span><span class="params" id="range1_value"></span>
        <div><input type="range" class="range" id="range1" value="5000" max="10000"></div>

        <span>endDelay (終了後の待機秒数) : </span><span class="params" id="range2_value"></span>
        <div><input type="range" class="range" id="range2" value="5000" max="10000"></div>
    </div>
</div>

<div class="code_view">
// アニメーション処理を実行 (animation1、animation2 共通で設定される)<br />
const options = {<br />
&nbsp;&nbsp;&nbsp;&nbsp; duration : <span id="code_view1" class="code_view_str">5000</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; endDelay : <span id="code_view2" class="code_view_str">5000</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; delay    : <span id="code_view2" class="code_view_str">3000</span><br />
&nbsp;&nbsp;&nbsp;&nbsp; fill     : <span id="code_view3" class="code_view_str"></span><br />
};<br /><br />
dom_rect.animate(keyframes, options);<br />
</div>

<svg xmlns="http://www.w3.org/2000/svg"
    width   = "500"
    height  = "100"
    viewBox = "0 0 500 100"
>
    <rect
        id     = "recttest"
        x      = "0"
        y      = "0"
        width  = "100"
        height = "50"
    />
</svg>

<script>

// アニメーション対象のDOM要素を取得
let dom_rect = document.querySelector("#recttest");

// ステータス表記
let status_message1 = document.querySelector('#status_message1');
let status_message2 = document.querySelector('#status_message2');

let animation1;
let animation2;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {width:'100px', height:'50px', fill:'#FF6600'}, // オレンジ
    {width:'50px' , height:'50px', fill:'#FFFF00'}, // イエロー
    {width:'450px', height:'50px', fill:'#FF0000'}  // レッド
];

// アニメーション2 keyframesの定義
const keyframes2 = [
    {width:'100px', height:'50px', fill:'#0033FF'}, // ブルー
    {width:'550px', height:'50px', fill:'#CC33FF'}, // パープル
    {width:'300px', height:'50px', fill:'#339900'}  // グリーン
];

// スライダの要素を取得し、イベントを付与する
let dom_range1 = document.querySelector('#range1');
let dom_range2 = document.querySelector('#range2');

// 各スライダーごとのイベントに、共通の関数を割り当てて処理する
dom_range1.addEventListener('input', change_range_slider);
dom_range2.addEventListener('input', change_range_slider);


// スライダーを動かした時の処理
function change_range_slider()
{

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }
    if (animation2) {
        animation2.pause(); // アニメーション2を一時停止
    }

    status_message1.innerHTML = '';
    status_message2.innerHTML = '';

	// 初期のアニメーション処理を実行
	const fill_value = document.querySelector('input[name="fill_value"]:checked').value;

    // アニメーションのオプションを取得
    const currentOptions = {
        duration : parseInt(dom_range1.value),
        endDelay : parseInt(dom_range2.value),
        delay    : 3000,
        fill     : fill_value
    };

    // オプションを再設定する
    animation1 = dom_rect.animate(keyframes1, currentOptions);

    // アニメーション1の再生と停止
    animation1.play();

    status_message1.innerHTML = 'アニメーション1 再生';

	// アニメーション1 再生終了時
    animation1.finished.then(() => {

    	console.log("アニメーション1 再生終了");
        status_message1.innerHTML = 'アニメーション1 再生終了';

        // アニメーション2 生成
        animation2 = dom_rect.animate(keyframes2, currentOptions);
        
        // アニメーション2 再生
        animation2.play();
        status_message2.innerHTML = 'アニメーション2 再生';
        
        // アニメーション2 再生終了時
        animation2.finished.then(() => {
        
            // アニメーション2 再生終了ログ
            console.log("アニメーション2 再生終了");
            status_message2.innerHTML = 'アニメーション2 再生終了';
        });

    });

    // パラメータ値をHTML出力
    let range1_value_dom = document.querySelector('#range1_value');
    let range2_value_dom = document.querySelector('#range2_value');
    range1_value_dom.innerHTML = dom_range1.value + "ミリ秒";
    range2_value_dom.innerHTML = dom_range2.value + "ミリ秒";

    let code_view1_dom = document.querySelector('#code_view1');
    let code_view2_dom = document.querySelector('#code_view2');
    let code_view3_dom = document.querySelector('#code_view3');
    code_view1_dom.innerHTML = dom_range1.value;
    code_view2_dom.innerHTML = dom_range2.value;
    code_view3_dom.innerHTML = fill_value;

}

// ボタン要素のDOMを取得
let dom_start_animation = document.getElementById('start_animation');

// イベントを付与
dom_start_animation.addEventListener('click',  StartAnimation, false);


// ボタン押下時の処理
function StartAnimation()
{
	console.log("ボタン押下時の処理 ");

    status_message1.innerHTML = '';
    status_message2.innerHTML = '';

	// 初期のアニメーション処理を実行
	const fill_value = document.querySelector('input[name="fill_value"]:checked').value;

    // パラメータ値をHTML出力
    let range1_value_dom = document.querySelector('#range1_value');
    let range2_value_dom = document.querySelector('#range2_value');
    range1_value_dom.innerHTML = dom_range1.value + "ミリ秒";
    range2_value_dom.innerHTML = dom_range2.value + "ミリ秒";

    // アニメーションのオプションを取得
    const currentOptions = {
        duration : parseInt(dom_range1.value),
        endDelay : parseInt(dom_range2.value),
        delay    : 3000,
        fill     : fill_value
    };

	// アニメーション1 生成
	animation1 = dom_rect.animate(keyframes1, currentOptions);

	// アニメーション1 再生
	animation1.play();
	status_message1.innerHTML = 'アニメーション1 再生';

	// アニメーション1 再生終了時
	animation1.finished.then(() => {

	    // アニメーション1 再生終了ログ
	    console.log("アニメーション1 再生終了");
        status_message1.innerHTML = 'アニメーション1 再生終了';

        // アニメーション2 生成
        animation2 = dom_rect.animate(keyframes2, currentOptions);
        
        // アニメーション2 再生
        animation2.play();
        status_message2.innerHTML = 'アニメーション2 再生';
        
        // アニメーション2 再生終了時
        animation2.finished.then(() => {
        
            // アニメーション2 再生終了ログ
            console.log("アニメーション2 再生終了");
            status_message2.innerHTML = 'アニメーション2 再生終了';
        });

	});

    let code_view1_dom = document.querySelector('#code_view1');
    let code_view2_dom = document.querySelector('#code_view2');
    let code_view3_dom = document.querySelector('#code_view3');
    code_view1_dom.innerHTML = dom_range1.value;
    code_view2_dom.innerHTML = dom_range2.value;
    code_view3_dom.innerHTML = fill_value;

}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面の「アニメーション開始」ボタンをすると、forwards、backwards、both、noneの選択により、
アニメーション1の開始前と終了後、アニメーション2の開始前と終了後の動作が変わることが確認できます。

実行例

forwardsを指定した場合

backwardsを指定した場合

bothを指定した場合

noneを指定した場合

注意が必要な点としては、上記の実行例4パターンの全てで「delay」を3000ミリ秒を指定している点です。

fillの指定は、delayの値の前後に影響する仕様なので、delayが無指定の場合や、
0の場合はfillによる状態変化がわからなくなる点に注意が必要です。

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – endDelay

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – endDelay

Element.animate()メソッド の options の endDelay について試してみます。

endDelayはアニメーション終了後の処理完了までの遅延時間として指定します。

アニメーションは 再生開始 → 再生中 → 再生終了 の一連の動きとみることができますが、
画面では見えないですが、再生終了の後に処理完了のタイミングがあります。

この処理完了は animate で生成したインスタンスに対し finished メソッドを記述することで
処理完了時のイベントを書くことができます。

また、endDelay の時間指定はミリ秒で指定し、再生終了から処理完了までの時間を制御することができます。

遅延時間を把握しやすいように、下記にサンプルコードを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.params_box {
    font-size : 0.8em;
}
.range {
    width: 400px;
}
.code_view {
    font-size : 0.8em;
    padding   : 5px;
    margin    : 20px 0;
    color     : #ffffff;
    background-color: #000000;
}
.code_view_str {
    color: #ff0000;
}
.status_view {
    margin-bottom: 20px;
}
</style>

</head>
<body>

<div class="status_view">
    <div>ステータス1:<span id="status_message1"></span></div>
    <div>ステータス2:<span id="status_message2"></span></div>
</div>

<div>
    <div class="params_box">
        <span>duration (処理全体の秒数) : </span><span class="params" id="range1_value"></span>
        <div><input type="range" class="range" id="range1" value="0" max="10000"></div>

        <span>endDelay (終了後の待機秒数) : </span><span class="params" id="range2_value"></span>
        <div><input type="range" class="range" id="range2" value="0" max="10000"></div>
    </div>
</div>

<div class="code_view">
// アニメーション処理を実行 (animation1、animation2 共通で設定される)<br />
const options = {<br />
&nbsp;&nbsp;&nbsp;&nbsp; duration: "<span id="code_view1" class="code_view_str">4000</span>"<br />
&nbsp;&nbsp;&nbsp;&nbsp; endDelay: "<span id="code_view2" class="code_view_str">4000</span>"<br />
};<br /><br />
dom_rect.animate(keyframes, options);<br />
</div>

<svg xmlns="http://www.w3.org/2000/svg"
    width   = "500"
    height  = "100"
    viewBox = "0 0 500 100"
>
    <rect
        id     = "recttest"
        x      = "0"
        y      = "0"
        width  = "100"
        height = "50"
        fill   = "#999"
    />
</svg>

<script>
// アニメーション対象のDOM要素を取得
let dom_rect = document.querySelector("#recttest");

// ステータス表記
let status_message1 = document.querySelector('#status_message1');
let status_message2 = document.querySelector('#status_message2');

let animation1;
let animation2;

// アニメーション1 keyframesの定義
const keyframes1 = [
    {width:'100px', height:'50px', fill:'#B0E0E6'}, // LightBlue
    {width:'50px' , height:'50px', fill:'#6495ED'}, // CornflowerBlue
    {width:'450px', height:'50px', fill:'#00008B'}  // DarkBlue
];
// アニメーション1 オプション定義
const options1 = {
    duration: 5000,
    endDelay: 4000
};

// アニメーション2 keyframesの定義
const keyframes2 = [
    {width:'100px', height:'50px', fill:'#F08080'}, // LightCoral
    {width:'550px', height:'50px', fill:'#FFA07A'}, // LightSalmon
    {width:'300px', height:'50px', fill:'#FF0000'}  // Red
];
// アニメーション2 オプション定義
const options2 = {
    duration: 5000,
    endDelay: 4000
};

// スライダの要素を取得し、イベントを付与する
let dom_range1 = document.querySelector('#range1');
let dom_range2 = document.querySelector('#range2');

// 各スライダーごとのイベントに、共通の関数を割り当てて処理する
dom_range1.addEventListener('input', change_range_slider);
dom_range2.addEventListener('input', change_range_slider);

// スライダーを動かした時の処理
function change_range_slider()
{

    if (animation1) {
        animation1.pause(); // アニメーション1を一時停止
    }
    if (animation2) {
        animation2.pause(); // アニメーション2を一時停止
    }

    status_message1.innerHTML = '';
    status_message2.innerHTML = '';

    // アニメーションのオプションを取得
    const currentOptions = {
        duration: parseInt(dom_range1.value),
        endDelay: parseInt(dom_range2.value)
    };

    // オプションを再設定する
    animation1 = dom_rect.animate(keyframes1, currentOptions);

    // アニメーションの再生と停止
    animation1.play();
    status_message1.innerHTML = 'アニメーション1 再生';

    animation1.finished.then(() => {
    	console.log("アニメーション1 再生終了");
        status_message1.innerHTML = 'アニメーション1 再生終了';

        // アニメーション2 生成
        animation2 = dom_rect.animate(keyframes2, options2);
        
        // アニメーション2 再生
        animation2.play();
        status_message2.innerHTML = 'アニメーション2 再生';
        
        // アニメーション2 再生終了時
        animation2.finished.then(() => {
        
            // アニメーション2 再生終了ログ
            console.log("アニメーション2 再生終了");
            status_message2.innerHTML = 'アニメーション2 再生終了';
        });

    });

    // パラメータ値をHTML出力
    let range1_value_dom = document.querySelector('#range1_value');
    let range2_value_dom = document.querySelector('#range2_value');
    range1_value_dom.innerHTML = (dom_range1.value / 1000) + "秒";
    range2_value_dom.innerHTML = (dom_range2.value / 1000) + "秒";

    let code_view1_dom = document.querySelector('#code_view1');
    let code_view2_dom = document.querySelector('#code_view2');
    code_view1_dom.innerHTML = dom_range1.value;
    code_view2_dom.innerHTML = dom_range2.value;

}


//--------------------------------------
// 初期処理
//--------------------------------------

// アニメーション1 生成
animation1 = dom_rect.animate(keyframes1, options1);

// アニメーション1 再生
animation1.play();
status_message1.innerHTML = 'アニメーション1 再生';

// アニメーション1 再生終了時
animation1.finished.then(() => {

    // アニメーション1 再生終了ログ
    console.log("アニメーション1 再生終了");
    status_message1.innerHTML = 'アニメーション1 再生終了';
    
    // アニメーション2 生成
    animation2 = dom_rect.animate(keyframes2, options2);

    // アニメーション2 再生
    animation2.play();
    status_message2.innerHTML = 'アニメーション2 再生';
    
    // アニメーション2 再生終了時
    animation2.finished.then(() => {
    
        // アニメーション2 再生終了ログ
        console.log("アニメーション2 再生終了");
        status_message2.innerHTML = 'アニメーション2 再生終了';
    });

});


</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にはアニメーションの定義が2つ用意しており、わかりやすいようにrect(矩形)の色が変化と幅が変化します。

アニメーション1 (寒色系の色で変化)
LightBlue

CornflowerBlue

DarkBlue

アニメーション2 (暖色系の色で変化)
LightCoral

LightSalmon

Red

また、endDelay の値をスライダーで動的に指定することができます。

動きとしては、
アニメーション1 の「再生 → 再生中 → 再生終了」後に、アニメーション2の「再生 → 再生中 → 再生終了」
という動作をしますが、

スライダーで値を調整すると、アニメーション1 の終了後に、処理終了までの遅延時間が調整され、アニメーション2 の再生開始のタイミングに影響していることがわかります。

実行例

スライダーの値をデフォルト、endDelayが短い場合、長めの場合、でそれぞれ実行例を示します。

実行例1.スライダーはデフォルト(4.0秒)の状態で実行

実行例2.処理全体の秒数を1.224秒、endDelayの待機秒数を2.656秒に設定した場合

実行例3.処理全体の秒数を1.224秒、endDelayの待機秒数を5.443秒に設定した場合

それぞれのパターンの例をみると、endDelayの指定秒数により、アニメーション1が終わり、アニメーション2が始まるまでに遅延時間が変化することがわかります。

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – easing の cubic-bezier

Posted コメントするカテゴリー: javascript

SVGアニメーション – Web Animations API を使う – Element.animate()メソッドの options – easing の cubic-bezier

Element.animate()メソッド の options の easing の cubic-bezier について試してみます。

cubic-bezierはメソッドとして指定し、cubic-bezier()の引数を指定して、
3次ベジェ曲線を定義し、その3次ベジェ曲線の変化量をアニメーションに反映させてアニメーション変化をします。

引数は4つあり、下記の値を指定します。

第1制御点の x座標
第1制御点の y座標
第2制御点の x座標
第2制御点の y座標

値はnumber型として指定します。

イージング関数の変化量は下記サイトで代表的なものが確認できます。
https://easings.net/ja

以下、前回のサンプルをもとに、変化量をcubic-bezierで指定したサンプルです。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
#start_animation {
    margin-bottom: 10px;
}
</style>

</head>
<body>

<div>
    <input type="button" id="start_animation" value="アニメーション開始">
</div>

<svg xmlns="http://www.w3.org/2000/svg"
    width   = "500"
    height  = "100"
    viewBox = "0 0 500 100"
>
    <rect
        id     = "recttest"
        x      = "0"
        y      = "0"
        width  = "100"
        height = "70"
        fill   = "#999"
    />
</svg>

<script>

// ボタン要素のDOMを取得
let dom_start_animation = document.getElementById('start_animation');

// イベントを付与
dom_start_animation.addEventListener('click',  StartAnimation, false);

// ボタン押下時の処理
function StartAnimation()
{
    // アニメーション対象のDOM要素を取得
    let dom_recttest = document.querySelector("#recttest");

    // keyframesの定義
    const keyframes = [
        {x:'0px'  , fill:'#999999', easing: 'cubic-bezier(0.23, 1, 0.32, 1)'}, // グレー
        {x:'100px', fill:'#3399FF', easing: 'cubic-bezier(0.23, 1, 0.32, 1)'}, // ブルー
        {x:'400px', fill:'#FF9900', easing: 'cubic-bezier(0.23, 1, 0.32, 1)'}, // オレンジ
    ];

    // アニメーション処理のタイミングプロパティを定義
    const options = {
        duration: 5000
    };

    dom_recttest.animate(keyframes, options);
}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)