A
A
Anton Myasnov2020-06-21 15:28:42
JavaScript
Anton Myasnov, 2020-06-21 15:28:42

How to properly reset svg animation?

Hello.
There is such a schedule.

<svg
                            xmlns="http://www.w3.org/2000/svg"
                            width="731"
                            height="366"
                            viewBox="0 0 731 366"
                    >
                        <g fill="none" fill-rule="evenodd">
    
    
                            <!--ЛИНИЯ-->
                            <path
                                    id="graph"
                                    stroke-linejoin="round"
                                    stroke-width="4"
                                    d="M24 359.5c337.042-37 563.376-143.167 679-318.5"
                                    style="stroke:#D3D802;stroke-width:3px;stroke-dasharray:1358;stroke-dashoffset:1358;"
                            />
                            <animate
                                    xlink:href="#graph"
                                    begin='click'
                                    id="ani-graph"
                                    dur="3s"
                                    attributeName="stroke-dashoffset"
                                    to="0"
                                    fill="freeze"
                            />
                            <!--КРУЖКИ-->
                            <circle
                                    id="point1"
                                    cx="23"
                                    cy="359"
                                    r="5"
                                    fill="#FFF"
                                    stroke="#EF7D01"
                                    stroke-width="4"
                                    opacity="0"
                            />
                            <animate
                                    xlink:href="#point1"
                                    begin='click'
                                    restart="whenNotActive"
                                    id="ani-point1"
                                    attributeName="opacity"
                                    to="1"
                                    fill="freeze"
                                    dur="0.25s"
    
                            />
    
                            <circle
                                    id="point3"
                                    cx="703"
                                    cy="41"
                                    r="5"
                                    fill="#FFF"
                                    stroke="#EF7D01"
                                    stroke-width="4"
                                    opacity="0"
                            />
                            <animate
                                    xlink:href="#point3"
                                    begin='click'
                                    restart="whenNotActive"
                                    id="ani-point3"
                                    attributeName="opacity"
                                    to="1"
                                    fill="freeze"
                                    dur="0.25s"
    
                            />
    
                            <circle
                                    id="point2"
                                    cx="383"
                                    cy="279"
                                    r="5"
                                    fill="#FFF"
                                    stroke="#EF7D01"
                                    stroke-width="4"
                                    opacity="0"
                            />
                            <animate
                                    xlink:href="#point2"
                                    begin='click'
                                    restart="always"
                                    id="ani-point2"
                                    attributeName="opacity"
                                    to="1"
                                    fill="freeze"
                                    dur="0.25s"
    
                            />
                        </g>
                    </svg>

When you click on the button, it appears and animates. First, point 1 appears, then a line is drawn, reaching the middle, point 2 appears, then again drawing a line and point 3.
I start the animation like this
elem.beginElement();
When the page is updated and the first run, everything works fine. But if you hide the chart with the button and start it again, then only the line starts to animate, and the dot appears immediately.
Advice from Google like onend does not completely solve the problem. The graph disappears as it should and starts to animate correctly, but the points appear without delay. There were tips about creating a copy of this chart every time.
How to correctly reset the animation so that when switching the button it always starts over as the first time, but without refreshing the page and copying / deleting the graph.
Link to code: codesandbox

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
RAX7, 2020-06-21
@MambliJoe

beginElement and onend are new features and still poorly supported by browsers. The normal way to make animation on svg is with the help of js libraries (animejs, kutejs, gsap).
I don't know a normal way to reset the smil animation, you can clone the tag animate, replace the original with a clone, and set the attribute to the clone begin = performance.now().
https://codesandbox.io/s/graph-animation-yglnz?fil...
Ps The stroke-dashoffset and opacity properties should animate normally via css (keyframes/transition), so you can get rid of the smil animation altogether.

E
Elvis, 2020-06-21
@Dr_Elvis

I propose to add an "anti-animation" to each animation, which, when the toggle switch is turned off, will do the same thing, only in reverse, and of course very quickly.
Total:
Add reverse animation to each element:

<svg
              xmlns="http://www.w3.org/2000/svg"
              width="731"
              height="366"
              viewBox="0 0 731 366"
            >
              <g fill="none" fill-rule="evenodd">
                <!--ЛИНИЯ-->
                <path
                  id="graph"
                  stroke-linejoin="round"
                  stroke-width="4"
                  d="M24 359.5c337.042-37 563.376-143.167 679-318.5"
                  style="stroke:#D3D802;stroke-width:3px;stroke-dasharray:1358;stroke-dashoffset:1358;"
                />
                <animate
                  xlink:href="#graph"
                  begin="click"
                  id="ani-graph"
                  dur="3s"
                  attributeName="stroke-dashoffset"
                  to="0"
                  fill="freeze"
                />
                <!--анимация наоборот-->
                <animate
                  xlink:href="#graph"
                  begin="click"
                  id="ani2-graph"
                  dur="0.01s"
                  attributeName="stroke-dashoffset"
                  to="1358"
                  fill="freeze"
                />
                <!--КРУЖКИ-->
                <circle
                  id="point1"
                  cx="23"
                  cy="359"
                  r="5"
                  fill="#FFF"
                  stroke="#EF7D01"
                  stroke-width="4"
                  opacity="0"
                />
                <animate
                  xlink:href="#point1"
                  begin="click"
                  restart="whenNotActive"
                  id="ani-point1"
                  attributeName="opacity"
                  to="1"
                  fill="freeze"
                  dur="0.25s"
                />
                <!--анимация наоборот-->
                <animate
                  xlink:href="#point1"
                  begin="click"
                  restart="whenNotActive"
                  id="ani2-point1"
                  attributeName="opacity"
                  to="0"
                  fill="freeze"
                  dur="0.01s"
                />

                <circle
                  id="point3"
                  cx="703"
                  cy="41"
                  r="5"
                  fill="#FFF"
                  stroke="#EF7D01"
                  stroke-width="4"
                  opacity="0"
                />
                <animate
                  xlink:href="#point3"
                  begin="click"
                  restart="whenNotActive"
                  id="ani-point3"
                  attributeName="opacity"
                  to="1"
                  fill="freeze"
                  dur="0.25s"
                />
                <!--анимация наоборот-->
                <animate
                  xlink:href="#point3"
                  begin="click"
                  restart="whenNotActive"
                  id="ani2-point3"
                  attributeName="opacity"
                  to="0"
                  fill="freeze"
                  dur="0.01s"
                />

                <circle
                  id="point2"
                  cx="383"
                  cy="279"
                  r="5"
                  fill="#FFF"
                  stroke="#EF7D01"
                  stroke-width="4"
                  opacity="0"
                />
                <animate
                  xlink:href="#point2"
                  begin="click"
                  restart="always"
                  id="ani-point2"
                  attributeName="opacity"
                  to="1"
                  fill="freeze"
                  dur="0.25s"
                />
                <!--анимация наоборот-->
                <animate
                  xlink:href="#point2"
                  begin="click"
                  restart="always"
                  id="ani2-point2"
                  attributeName="opacity"
                  to="0"
                  fill="freeze"
                  dur="0.01s"
                />
              </g>
            </svg>

And then we start these animations when the toggle switch is turned off:
document.addEventListener("DOMContentLoaded", function() {
        let radioBtn = document.querySelector("#checkbox");
        let badImg = document.querySelector(".graph__img--bad");
        let goodImg = document.querySelector(".graph__svg");
        //let graphInfo = document.querySelector(".graph-info"); Тут закомментировал, так как элемента нет
        let graphMark = document.querySelector(".graph__mark");
        let graphBody = document.querySelector(".graph__radio");
        let graphSection = document.querySelector(".graph");

        let svgLine = document.getElementById("ani-graph");
        let svgPoint1 = document.getElementById("ani-point1");
        let svgPoint2 = document.getElementById("ani-point2");
        let svgPoint3 = document.getElementById("ani-point3");

        let animate = document.querySelectorAll("animate");
        const toggleGraph = () => {
          let isChecked = radioBtn.checked;

          if (isChecked) {
            svgLine.beginElement();

            setTimeout(() => svgPoint1.beginElement(), 100);
            setTimeout(() => svgPoint2.beginElement(), 800);
            setTimeout(() => svgPoint3.beginElement(), 1730);

            badImg.classList.add("hide");
            goodImg.classList.add("show");
            //graphInfo.classList.add("show"); Тут закомментировал, так как элемента нет
            graphMark.classList.add("show");
            graphBody.classList.add("show");
            graphSection.classList.add("active");
          } else {
            animate.forEach(item => {
              item.onend = () => {
                console.log("endEvent fired");
              };
            });
            badImg.classList.remove("hide");
            goodImg.classList.remove("show");
            //graphInfo.classList.remove("show"); Тут закомментировал, так как элемента нет
            graphMark.classList.remove("show");
            graphBody.classList.remove("show");
            graphSection.classList.remove("active");

            document.getElementById("ani2-graph").beginElement();// Запуск анимации наоборот
            document.getElementById("ani2-point1").beginElement();// Запуск анимации наоборот
            document.getElementById("ani2-point2").beginElement();// Запуск анимации наоборот
            document.getElementById("ani2-point3").beginElement();// Запуск анимации наоборот
          }
        };

        radioBtn.addEventListener("click", toggleGraph);
      });

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question