SVG-атрибут поворота элемента <animateMotion>, установленный на auto, работает неправильно - PullRequest
0 голосов
/ 12 сентября 2018

У меня вопрос к svg анимации.Пожалуйста, найдите мой код здесь .Используя JavaScript, я добавляю элемент animateMotion к символу красной стрелки.Я хотел бы добиться следующего:

  • Стрелка должна двигаться по пути, обозначенному прямоугольником, и вращаться, чтобы выровняться по наклону пути (поэтому поверните на 90 градусов)

Я могу частично удовлетворить это требование.Переместить стрелку по заданному пути довольно просто.JS-скрипт устанавливает атрибут пути для элемента animateMotion.Я хотел использовать атрибут rotate, чтобы соответствовать изменениям rotate пути.Обратите внимание, что когда вы раскомментируете эту строку

animateMotion.setAttribute ("rotate", "auto");

в коде JS, происходит что-то странное.Вместо поворота на 90 градусов после достижения каждого угла стрелки неожиданно исчезают.Ты знаешь почему?

Большое спасибо заранее.

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

function getArrowSymbolXcoordinate(pathAttribute) {
  var commaIdx = pathAttribute.indexOf(',');
  return pathAttribute.substring(1,commaIdx);
}

function getArrowSymbolYcoordinate(pathAttribute) {
  var commaIdx = pathAttribute.indexOf(',');
  var lineCommandIdx = pathAttribute.indexOf('l');
  console.log(pathAttribute.substring(commaIdx, lineCommandIdx));
  return pathAttribute.substring(commaIdx+1, lineCommandIdx);
}


function getTopPathAttribute(element, xCoordinate) {
  var toTopRightCorrner = Math.abs(topRightCorrner.x - xCoordinate);
  var path = 'm0,0 ' + 'h' + toTopRightCorrner + ' v' + height + ' h-' + width + ' v-' + height + ' z';
  return path;
}


let topLeftCorrner = new Point(200,100);
let topRightCorrner = new Point(350,100);
let bottomLeftCorrner = new Point(200,150);
let bottomRightCorrner = new Point(350,150);

let topArrowSymbols = Array.from(document.getElementsByClassName('top'));

let width = Math.abs(topLeftCorrner.x - topRightCorrner.x);
let height = Math.abs(topLeftCorrner.y - bottomLeftCorrner.y);

topArrowSymbols.forEach( function(element) {
  var xCoordinate = getArrowSymbolXcoordinate(element.getAttribute('d'));
  var animateMotion = document.createElementNS('http://www.w3.org/2000/svg', "animateMotion");
  var pathAttribute = getTopPathAttribute(element, xCoordinate);
  animateMotion.setAttribute("dur", "7s");
  animateMotion.setAttribute("path", pathAttribute);
  //animateMotion.setAttribute("rotate", 'auto');
  element.appendChild(animateMotion);
});
body {
	height: 100vh;
}
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"/>
	<script src="main_home.js" defer="defer"></script>
</head>

<body>

  <figure >
  
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" viewbox="120 80 300 200">
        <g>
            <rect fill="none" height="50" stroke="black" stroke-width="2" width="150" x="200" y="100"/>
            <path class="arrow_symbol top" d="m215.21876,99.72372l-2.49741,-2.5l1.64474,0l2.49741,2.5l-2.49741,2.5l-1.64474,0l2.49741,-2.5z" fill="#ffffff" stroke="#ff0000" stroke-width="2"/>
        </g>
    </svg>
</figure>

</body>
</html>

1 Ответ

0 голосов
/ 14 сентября 2018

Ваша проблема в том, что ваша стрелка имеет большое смещение от начала координат SVG.Поэтому, когда он достигает конца первой кривой и поворачивается за угол, он исчезает за пределами экрана.

Вот упрощенный пример, который, мы надеемся, показывает, что происходит.

<svg viewbox="-100 -100 400 400" width="400">

  <!-- axes to show the origin -->
  <line x1="0" y1="-100" x2="0" y2="300" stroke="#cce" stroke-width="1"/>
  <line x1="-100" y1="0" x2="300" y2="0" stroke="#cce" stroke-width="1"/>
  
  <!-- the path that the arrow is actually following (ie the one in the animateMotion) -->
  <rect width="80" height="80" fill="none" stroke="#888" stroke-width="2"/>

  <!-- dashed line showing the offset from the animateMotionPath to the arrow -->
  <line x1="0" y1="0" x2="100" y2="100" fill="none" stroke="#ff0000" stroke-width="2" stroke-dasharray="10 10">
    <animateMotion dur="7s" rotate="auto"
                   path="M 0,0 L 80,0 L 80,80 L 0,80 Z"/>
  </line>

  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

  <!-- the pon-screen path that the arrow appears to be following -->
  <rect fill="none" x="100" y="100" width="80" height="80" stroke="black" stroke-width="2" />

  <!-- the arrow -->
  <path class="arrow_symbol top" d="M 110,100 L 100,110 L 100,90 Z" fill="#ffffff" stroke="#ff0000" stroke-width="2">
    <animateMotion dur="7s" rotate="auto"
                   path="M 0,0 L 80,0 L 80,80 L 0,80 Z"/>
  </path>

</svg>

Чтобы исправить SVG, вы должны убедиться, что ваша стрелка вращается вокруг своего центра.Не происхождение.

let topArrowSymbols = Array.from(document.getElementsByClassName('top'));

topArrowSymbols.forEach( function(element) {
  var animateMotion = document.createElementNS('http://www.w3.org/2000/svg', "animateMotion");
  animateMotion.setAttribute("dur", "7s");
  animateMotion.setAttribute("path", 'm 220,100 h 130 v 50 h -150 v -50 z');
  animateMotion.setAttribute("rotate", 'auto');
  animateMotion.setAttribute("fill", "freeze");
  element.appendChild(animateMotion);
});
body {
	height: 100vh;
}

svg {
  overflow: visible;
  position: absolute;
  top: 400px;
  left: 400px;
}
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"/>
	<script src="main_home.js" defer="defer"></script>
</head>

<body>

  <figure >
  
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" viewbox="120 80 300 200">
        <g>
            <rect id="my-path" fill="none" height="50" stroke="black" stroke-width="2" width="150" x="200" y="100"/>
            <path class="arrow_symbol top" d="m0.21876,0.72372l-2.49741,-2.5l1.64474,0l2.49741,2.5l-2.49741,2.5l-1.64474,0l2.49741,-2.5z" fill="#ffffff" stroke="#ff0000" stroke-width="2"/>
        </g>
    </svg>
</figure>

</body>
</html>
...