I’m trying to animate motions of a circle moving along edges (SVG paths) in a graph. I have an array of “events” that I iterate on, and for each event I create an animateMotion
element and append it to my circle.
However it looks like I don’t understand the dur
attribute of motions: even if I create and append a motion after two seconds, with its duration set to 2 seconds, then nothing happens. If I set its duration to 4 seconds instead, then the animation starts in the middle of the path, as if 2 seconds had already elapsed.
It feels like dur
is a duration since the page was loaded or something?
<svg width="300" height="200">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<circle cx="50" cy="50" r="20" stroke="black" stroke-width="3" fill="red" />
<circle cx="200" cy="100" r="20" stroke="black" stroke-width="3" fill="red" />
<circle cx="200" cy="175" r="20" stroke="black" stroke-width="3" fill="red" />
<circle cx="50" cy="175" r="20" stroke="black" stroke-width="3" fill="red" />
<path id="edge1" d="M70,50 Q125,0 180,90" stroke="black" stroke-width="2" fill="none" marker-end="url(#arrow)" />
<path id="edge2" d="M70,175 Q125,125 180,100" stroke="black" stroke-width="2" fill="none" marker-end="url(#arrow)" />
<circle id="animCircle" r="10" fill="blue">
<animateMotion repeatCount="1">
<mpath href="#edge1" />
</animateMotion>
</circle>
</svg>
document.addEventListener("DOMContentLoaded", function() {
const animCircle = document.getElementById('animCircle');
// Function to create animateMotion elements dynamically
function createAnimateMotion(pathId, dur) {
const animElement = document.createElementNS('http://www.w3.org/2000/svg', 'animateMotion');
animElement.setAttribute('dur', dur);
animElement.setAttribute('repeatCount', '1');
const mpath = document.createElementNS('http://www.w3.org/2000/svg', 'mpath');
mpath.setAttribute('href', pathId);
animElement.appendChild(mpath);
return animElement;
}
// Initially set the animation along the first edge
const firstAnim = createAnimateMotion('#edge1', '2s');
animCircle.appendChild(firstAnim);
firstAnim.addEventListener('endEvent', function() {
// Remove the first animation
animCircle.removeChild(firstAnim);
// Set the animation along the second edge
const secondAnim = createAnimateMotion('#edge2', '4s');
animCircle.appendChild(secondAnim);
});
});
How do I create my animateMotion
elements so that they play one after the other, without depending on the time already elapsed?