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 />
duration : <span id="code_view1" class="code_view_str">5000</span><br />
endDelay : <span id="code_view2" class="code_view_str">5000</span><br />
delay : <span id="code_view2" class="code_view_str">3000</span><br />
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>
画面の「アニメーション開始」ボタンをすると、forwards、backwards、both、noneの選択により、
アニメーション1の開始前と終了後、アニメーション2の開始前と終了後の動作が変わることが確認できます。
実行例
forwardsを指定した場合

backwardsを指定した場合

bothを指定した場合

noneを指定した場合

注意が必要な点としては、上記の実行例4パターンの全てで「delay」を3000ミリ秒を指定している点です。
fillの指定は、delayの値の前後に影響する仕様なので、delayが無指定の場合や、
0の場合はfillによる状態変化がわからなくなる点に注意が必要です。