Задать вопрос

Как правильно сбросить svg анимацию?

Здравствуйте.
Есть такой график.
<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>

При нажатии на кнопку он появляется и анимируется. Сначала появляется точка 1, далее рисуется линия, доходя до середины появляется точка 2, потом опять рисовка линии и точка 3.
Запускаю анимацию так
elem.beginElement();
При обновлении страницы и первом запуске все работает нормально. Но если скрыть график кнопкой и снова запустить, то начинает анимироваться только линия, а точка появляются сразу.
Советы из гугла типа onend не полностью решают проблему. График исчезает как надо и начинает анимироваться верно, но точки появляются без задержки . Были советы про создание каждый раз копии этого графика.
Как правильно сбросить анимацию, что бы при переключении кнопки всегда начиналась сначала как в первый раз но без обновления страницы и копирования/удаления графика.
Ссылка на код: codesandbox
  • Вопрос задан
  • 376 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
RAX7
@RAX7
beginElement и onend новые фичи и еще плохо поддерживаются браузерами. Нормальным способом сделать анимацию на svg можно с помощью библиотек на js (animejs, kutejs, gsap).
Я не знаю нормального способа как сбросить smil анимацию, можно клонировать тег animate, заменить оригинал клоном и клону задать атрибут begin = performance.now().
https://codesandbox.io/s/graph-animation-yglnz?fil...
P.s. свойства stroke-dashoffset и opacity должны нормально анимироваться через css (keyframes/transition), так что от smil анимации можно вообще избавиться.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Dr_Elvis
@Dr_Elvis
В гугле забанен
Предлагаю к каждой анимации добавить "анти анимацию", которая при выключении тумблера будет делать то же самое, только наоборот, ну и конечно очень быстро.
Итого:
Добавить анимацию наоборот к каждому элементу:
<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>

А далее запускаем эти анимации при выключении тумблера:
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);
      });
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы