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