我正在研究类似的事情并遇到了这个答案。 @Alexandr_TT 的回答让我想到了一种更灵活的方法来做到这一点,而无需使用图形编辑器(如 Inkscape 等)
我想出了以下想法:
- 将
<AnimateMotion/> 用于第一个循环。
- 每隔 X 毫秒触发一次 setInterval,每次触发以捕获圆的中心点(来自
circle.getBoundingClientRect() 和 svg.matrixTransform())
- 将这些 x 和 y 值推送到两个数组以捕获它们
- 当 AnimateMotion 结束时,清除当前的 setInterval 并将第一个元素也推到每个数组的末尾(以关闭循环)
- 从 DOM 中删除
<AnimateMotion/> 标记
- 将这些数组推送到
<animate id="cx" attributeName="cx" values="" .../> 和 <animate id="cy" attributeName="cy" values="" .../> 标签的 values 属性
- 这两个动画标签都以
cx.beginElement() 和cy.beginElement() 开头
您可以对这种性能感到满意,或者您可以复制粘贴带有 values="..." 属性的 DOM 元素并将其保存为您的新主文件,基本上实现了 @Alexandr_TT 使用图形编辑器所做的事情。当然,如果您决定更改路径等,我展示的这种方法很灵活。
演示:https://codepen.io/Alexander9111/pen/VwLaNEN
HTML:
<circle id="circle" class="circle" cx="0" cy="00" r="125">
<animateMotion
path="M162.9,150c6.8-0.2,12.1-5.7,12.1-12.5c0-6.9-5.6-12.5-12.5-12.5c-6.8,0-12.3,5.4-12.5,12.2v25.7 c-0.2,6.8-5.7,12.2-12.5,12.2c-6.9,0-12.5-5.6-12.5-12.5c0-6.8,5.4-12.3,12.1-12.5L162.9,150z"
dur="4s" begin="0s"
epeatCount="1" fill="freeze"
calcMode="linear"
fill="freeze">
</animateMotion>
<animate id="cx" attributeName="cx" values="" dur="4s" repeatCount="indefinite" begin="indefinite"/>
<animate id="cy" attributeName="cy" values="" dur="4s" repeatCount="indefinite" begin="indefinite"/>
</circle>
JS:
const svg = document.querySelector('svg');
const animateElem = document.querySelector('animateMotion');
const circle = document.querySelector('#circle');
const cx = document.querySelector('#cx');
const cy = document.querySelector('#cy');
let myInterval;
let valuesX = [];
let valuesY = [];
function startFunction() {
const box = circle.getBoundingClientRect();
var pt = svg.createSVGPoint();
pt.x = (box.left + box.right) / 2;
pt.y = (box.top + box.bottom) / 2;
var svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
console.log(svgP.x,svgP.y)
valuesX.push(svgP.x);
valuesY.push(svgP.y);
}
function endFunction() {
animateElem.parentNode.removeChild(animateElem);
clearInterval(myInterval)
valuesX.push(valuesX[0]);
valuesY.push(valuesY[0]);
cx.setAttribute('values', valuesX.join('; '));
cy.setAttribute('values', valuesY.join('; '));
circle.setAttribute('cx', 0);
circle.setAttribute('cy', 0);
cx.beginElement();
cy.beginElement();
}
animateElem.addEventListener('beginEvent', () => {
console.log('beginEvent fired');
myInterval = setInterval(startFunction, 50);
})
animateElem.addEventListener('endEvent', () => {
console.log('endEvent fired');
endFunction();
})