10_9_2 SVGのシークアニメーション

<svg>要素で描いたパスに沿ってHTML要素が動くアニメーションはCSSで作成できるので、同じことがWeb Animations APIでも行えます。また、アニメーションのcurrentTimeを、シークバーのつまみの位置に合わせることで、つまみのドラッグで、パス上を動く要素を制御できるようになります。ただし現状では、Firefoxでは動作しません。

SVGのシークアニメーション

HTML

<svg width="400" height="300">
  <path d="M 100 50 L 20 150 L 100 150 L 100 280 L 300 280 L 300 150 L 380 150 300 50 Z" style="stroke:black; stroke-width:3; fill:chocolate" />
</svg>
<div class="ball"></div>
<div class="controle">
  <!== max値はアニメーションの長さ ==>
  <input type="range" min="0" max="4000" step="1" value="0" id="seek">
  <input type="button" id="play-btn" value="Play">
  <p id="output"></p>
</div>

JavaScript

const playBtn = document.getElementById('play-btn');
const output = document.getElementById('output');
const target = document.querySelector(".ball");

// targetはこれにより、(10, 80)に移動する
target.style.offsetPath = "path('M 100 50 L 20 150 L 100 150 L 100 280 L 300 280 L 300 150 L 380 150 300 50 Z')";
const keyframes = {
    offsetDistance: ["0%", "100%"]
};
const timings = {
    iterations: 1,
    duration: 4000,
    fill: 'forwards',
    easing: "ease-in-out"
};
const effect = new KeyframeEffect(target, keyframes, timings);
const anim = new Animation(effect, document.timeline);
//anim.play();  

let mode = 'seek';
playBtn.addEventListener('click', () => {
    mode = 'auto';
    anim.play();
    render();
    console.log(anim.playState); // running  
}, false);

const rangeSeek = document.querySelector('input[type="range"]');
//rangeSeek.value = 0;
rangeSeek.addEventListener('input', () => {
    anim.cancel();
    console.log(anim.playState) // idle 
    mode = 'seek';
    // シーク
    anim.currentTime = rangeSeek.value;
    output.textContent = anim.currentTime;
}, false);

const update = () => {
    // 現在の再生位置を表示
    rangeSeek.value = anim.currentTime;
    output.textContent = rangeSeek.value;
}

const render = () => {
    if (mode === 'auto') {
        console.log(anim.playState); //  running 
        update();
        window.requestAnimationFrame(render);
    }
}

anim.addEventListener('finish', () => {
    mode = 'seek';
    console.log(anim.playState); // finished  
}, false);

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA