<animateMotion> 元素的 SVG 旋转属性设置为自动无法正常工作
SVG rotate attribute of the <animateMotion> element set to auto not working correctly
我对 svg 动画有疑问。请找到我的代码 here。使用 javascript 我将 animateMotion 元素添加到红色箭头符号。我想实现以下目标
- 箭头应在矩形指定的路径上移动并旋转以与路径的斜率对齐(因此旋转 90 度)
我可以部分满足这个要求。沿给定路径移动箭头非常简单。 JS 脚本正在为 animateMotion 元素设置路径属性。我想使用旋转属性来适应路径的旋转变化。
请看看当你取消注释这一行时
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>
你的问题是你的箭头与 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>
我对 svg 动画有疑问。请找到我的代码 here。使用 javascript 我将 animateMotion 元素添加到红色箭头符号。我想实现以下目标
- 箭头应在矩形指定的路径上移动并旋转以与路径的斜率对齐(因此旋转 90 度)
我可以部分满足这个要求。沿给定路径移动箭头非常简单。 JS 脚本正在为 animateMotion 元素设置路径属性。我想使用旋转属性来适应路径的旋转变化。 请看看当你取消注释这一行时
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>
你的问题是你的箭头与 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>