SVG анимация path, при изменении атрибута values анимация начинается сначала

Рейтинг: 1Ответов: 1Опубликовано: 16.05.2023

При нажатии на блок стрелка перемещается к его правому краю. Для этого я получаю текущее значение атрибута d у path и следующее значение d, прибавляя координаты по X, затем обновляю значение values в animate и перезапускаю анимацию с помощью beginElement(). При таком раскладе анимация работает плавно, но всегда начинается с самого первого элемента.

Если до изменения атрибута values остановить анимацию с помощью endElement() стрелка перемещается последовательно, но при этом плавный переход не работает.

В чем причина такого поведения?

function getPath(item) {
  let x = item.offsetLeft + item.offsetWidth;
  return `M${x} 15 L ${40+x} 30     V20 H${60+x} V10 H${40+x} V0 Z`;
}

window.onload = function() {
  let firstItem = document.getElementById("first_item");
  document.getElementById("arrow").setAttribute("d", getPath(firstItem));

}

var menu = document.getElementById("menu");

menu.addEventListener('click', function(event) {

  let clickedElement = event.target;

  if (clickedElement.getAttribute("class") != "menu_item") {
    return;
  }

  let el = document.getElementById("arrow");
  let anim = el.querySelector("animate");
  let currentPath = el.getAttribute("d");

  anim.setAttribute("values", `${currentPath};${getPath(clickedElement)}`);

  anim.beginElement();
});
body {
  margin: 0;
  background: gray;
}

.menu {
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.menu_item {
  background: white;
  border-radius: 6px;
  padding: 3px 10px 3px 10px;
  height: 25px;
  z-index: 2;
}

svg {
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
}
<body>
  <div id="menu" class="menu">
    <svg fill="red" stroke="black" stroke-width="1">
         <path id = "arrow" d="M0 15 L 40 30    V20 H60 V10 H40 V0 Z">
            <animate attributeName="d" dur="0.2s" keySplines = "0.42 0 0.58 1" values="" fill="freeze"/>
         </path>
      </svg>
    <div id="first_item" class="menu_item">
      Item1
    </div>
    <div class="menu_item">
      Item2
    </div>
    <div class="menu_item">
      Item3
    </div>
    <div class="menu_item">
      Item4
    </div>
  </div>
</body>

Ответы

▲ 4Принят

Тебе нужно менять начало анимации

function getPath(item) {
  let x = item.offsetLeft + item.offsetWidth;
  return `M${x} 15 L ${40+x} 30     V20 H${60+x} V10 H${40+x} V0 Z`;
}

window.onload = function() {
  let firstItem = document.getElementById("first_item");
  document.getElementById("arrow").setAttribute("d", getPath(firstItem));

}

var menu = document.getElementById("menu");

menu.addEventListener('click', function(event) {

  let clickedElement = event.target;

  if (clickedElement.getAttribute("class") != "menu_item") {
    return;
  }

  let el = document.getElementById("arrow");
  let anim = el.querySelector("animate");
  let currentPath = el.getAttribute("d");

  anim.setAttribute("values", `${currentPath};${getPath(clickedElement)}`);
  el.setAttribute("d", `${getPath(clickedElement)}`);

  anim.beginElement();
});
body {
  margin: 0;
  background: gray;
}

.menu {
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.menu_item {
  background: white;
  border-radius: 6px;
  padding: 3px 10px 3px 10px;
  height: 25px;
  z-index: 2;
}

svg {
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
}
<body>
  <div id="menu" class="menu">
    <svg fill="red" stroke="black" stroke-width="1">
         <path id = "arrow" >
            <animate attributeName="d" dur="0.2s" keySplines = "0.42 0 0.58 1" values="" fill="freeze"/>
         </path>
      </svg>
    <div id="first_item" class="menu_item">
      Item1
    </div>
    <div class="menu_item">
      Item2
    </div>
    <div class="menu_item">
      Item3
    </div>
    <div class="menu_item">
      Item4
    </div>
  </div>
</body>