简体   繁体   中英

JavaScript SVG continously appending animated element to SVG element

I have SVG element and I'm dynamically with JavaScript creating Circle element with animateMotion element. Circle should dynamically follow along with SVG path. I'm attaching endEvent listener to AnimateMotion element so after completing animation, created Circle element should be removed from DOM and whole process should start again. It works fine for first animation, but not for another iterations. Code is below - where I made mistake?

 const test = document.getElementById('test'); function createAnimation() { const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); const animation = document.createElementNS('http://www.w3.org/2000/svg', 'animateMotion'); circle.setAttributeNS(null, 'r', '8'); circle.setAttributeNS(null, 'fill', '#00F'); animation.setAttributeNS(null, 'dur', '2s'); animation.setAttributeNS(null, 'path', "M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z"); circle.appendChild(animation); test.appendChild(circle); animation.addEventListener('endEvent', () => { circle.parentElement.removeChild(circle); }); return new Promise((resolve) => { animation.addEventListener('endEvent', () => { resolve(); }); }); } (async() => { while (true) { await createAnimation(); } })();
 <svg id="test" viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg"> <path fill="none" stroke="lightgrey" d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" /> </svg>

SMIL animations are based on a global clock. By default, if you don't specify a begin , the animation will start at time 0. Where time 0 is when the document is created/displayed.

After the first run through of the animation (duration = 2s), the global timing clock will be at 2s.

At that point you add a new circle and <animateMotion> element. Its start time defaults to "0" also. Meaning that the browser considers that the run period for that animation has been and gone. That is because we are past the 2 sec mark by now.

Try the following:

  1. Add begin="indefinite" to the animation. That tells the browser that you intend to start the animation yourself.

     animation.setAttribute('begin', 'indefinite');
  2. Trigger the animation after you have finished creating it.

     animation.beginElement();

However...

Why keep creating more and more circles? Is there a reason for that? Why not just restart the animation when it is finished? Something like

createAnimation();

animation.addEventListener('endEvent', () => {
   animation.beginElement();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM