我想在SVG路径上为许多SVG对象设置动画。目标是为新兴技术创建Gartner HypeCycle的动画版本。我在powerpoint中有一个旧动画,但想要使它对Web友好。
每个对象(对于HypeCycle最终将是一种技术)需要根据一组不同的keyTime和keyPoints移动,例如他们需要以不同的速度移动。我在我发布的代码中工作,并且在世界上一切都很好,当我点击一个按钮然后连续循环时动画开始。快乐的时光。
但是,我想在页面中添加一个滑块,以便在我单击按钮时开始动画,而是由滑块控制,并根据定义的一组keyPoints移动路径上的所有点(可能在JSON文件中)。
所以我想做两件事(1)使用滑块控制动画(但仍然为每个圆圈定义了keyPoints / keyTimes,以便它们以不同的速度移动)(2)从每个JSON文件中获取keyTimes和keyPoints的对象。
谢谢
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG Tiny 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
<!-- style change colour on hover -->
<style>
circle.circle1 {fill: rgb(0,0,22);transition: fill 0.5s ease;}
circle.circle1:hover {fill: rgb(0,255,255);}
circle.circle2 {fill: rgb(0,100,0);transition: fill 0.5s ease;}
circle.circle2:hover {fill: rgb(0,255,255);}
circle.circle3 {fill: rgb(100,0,0);transition: fill 0.5s ease;}
circle.circle3:hover {fill: rgb(0,255,255);}
</style>
<svg width="400px" height="400px" viewBox="0 0 400 400"
xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="tiny"
xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- draw path and circles -->
<path id="hypecurve" d="M12.967,349.469c15.107-87.283,25.932-180.142,54.214-264.61c31.17-93.095, 54.138, 17.688,65.096,53.934c11.354,37.558,23.177,74.976,34.309,112.6c26.534,89.679,79.275-25.286,92.183-45.57c11.749-18.462,20.938-43.699,69.798-48.289c70.298-6.604,177.054-4.848,224.858-5.774" fill="none" stroke="#444" stroke-width="3"/>
<circle class= "circle1" id="c1" cx="0" cy="0" r="5" fill="#004" />
<circle class= "circle2" id="c2" cx="0" cy="0" r="6" fill="#66f" />
<circle class= "circle3" id="c3" cx="0" cy="0" r="7" fill="#00f" />
<!-- button to start animation -->
<rect id="startButton" style="cursor:pointer;"x="20" y="350" rx="5" height="25" width="80"fill="#EFEFEF" stroke="black" stroke-width="1" />
<text x="60" y="370" text-anchor="middle" style="pointer-events:none;">Click me</text>
<animateMotion xlink:href="#c1"
begin="startButton.click"
dur="10s"
calcMode="linear"
repeatDur="indefinite">
<mpath xlink:href="#hypecurve" />
</animateMotion>
<!-- these are the attributes I want to update dynamically -->
<animateMotion xlink:href="#c2"
begin="startButton.click"
dur="10s"
calcMode="linear"
keyPoints="0.3;0.35;0.375;0.4;0.45;0.5;0.6;0.61;0.7;0.8;1"
keyTimes="0;0.19;0.36;0.51;0.64;0.75;0.84;0.91;0.96;0.99;1"
repeatDur="indefinite">
<mpath xlink:href="#hypecurve" />
</animateMotion>
<animateMotion xlink:href="#c3"
begin="startButton.click"
dur="10s"
calcMode="linear"
keyPoints="0.0;0.1;0.2;0.3;0.4;0.5;0.6;0.7;0.8;0.9"
keyTimes="0;0.19;0.36;0.51;0.64;0.75;0.84;0.91;0.96;0.99"
repeatDur="indefinite">
<mpath xlink:href="#hypecurve" />
</animateMotion>
</svg>
在下一个例子中,我使用滑块在路径上移动一个圆圈。我只是为第一个圈子做这件事。为此,我使用getTotalLength()
方法计算路径的长度,并使用getPointAtLength()
方法计算圆的新位置。
我不明白你想如何组合动画和滑块。请编辑您的问题来解释这一点。
如果需要动态更改某些animateMotion
属性,可以使用setAttributeNS
方法完成。
let trackLength = hypecurve.getTotalLength();
c1.setAttributeNS(null,"transform", "translate(12.967,349.469)")
itr1.addEventListener("input",()=>{
let val = (itr1.value * trackLength)/ 100;
let poz = hypecurve.getPointAtLength(val)
//console.log(poz)
c1.setAttributeNS(null,"transform", `translate(${poz.x},${poz.y})`)
})
svg{width:100vh; display:block;}
circle.circle1 {fill: rgb(0,0,22);}
circle.circle1:hover {fill: rgb(0,255,255);}
circle.circle2 {fill: rgb(0,100,0);}
circle.circle2:hover {fill: rgb(0,255,255);}
circle.circle3 {fill: rgb(100,0,0);}
circle.circle3:hover {fill: rgb(0,255,255);}
<svg viewBox="0 0 550 400" >
<!-- draw path and circles -->
<path id="hypecurve" d="M12.967,349.469c15.107-87.283,25.932-180.142,54.214-264.61c31.17-93.095,54.138,17.688,65.096,53.934c11.354,37.558,23.177,74.976,34.309,112.6c26.534,89.679,79.275-25.286,92.183-45.57c11.749-18.462,20.938-43.699,69.798-48.289c70.298-6.604,177.054-4.848,224.858-5.774" fill="none" stroke="#444" stroke-width="3"/>
<circle class= "circle1" id="c1" cx="0" cy="0" r="5" fill="#004" />
<circle class= "circle2" id="c2" cx="0" cy="0" r="6" fill="#66f" />
<circle class= "circle3" id="c3" cx="0" cy="0" r="7" fill="#00f" />
</svg>
c1: <input type="range" id="itr1" min="0" max="100" value="0" step="1" />
OP更新了他们的问题,我不太清楚我理解他们想要什么
在下面的例子中,我使用输入类型范围#itr
来改变keyTimes
* 100的值.keyTimes
值从0到1,#itr
取值从0到100。
对于每个时间点,我都在计算曲线上圆的位置并将其保存在数组中。
请阅读我的代码中的注释。我希望这就是你所要求的。
let trackLength = hypecurve.getTotalLength();
c1.setAttributeNS(null, "transform", "translate(12.967,349.469)");
// the position on the track at the key times: 11 values
let values = [];
// the position on the track at the key times: 101 values
let values1 = [0];
let keyTimes = [0, 19, 36, 51, 64, 75, 84, 91, 96, 99, 100]; //keyTimes * 100
let keyPoints = [0, 0.35, 0.375, 0.4, 0.45, 0.5, 0.6, 0.61, 0.7, 0.8, 1];
// create the values array
keyPoints.map(p => {
values.push(trackLength * p);
});
// create the values1 array
for (let time = 0; time <100; time++) {
//for every value that the #itr can take
for (let k = 0; k < keyTimes.length - 1; k++) {
//the current value
let curr = values[k];
//the target value
let target = values[k + 1];
// the distance between the current value and the target value
let dist = target - curr;
// detect the interval of time we are in
if (time >= keyTimes[k] && time < keyTimes[k + 1]) {
// the increment for this time interval
let increment = dist / (keyTimes[k + 1] - keyTimes[k]);
// add a new value to the values1 array
values1.push(values1[time]+increment);
// break the loop
break;
}
}
}
itr1.addEventListener("input", () => {
let val = itr1.value;
// get the new position on the curve
let pos = hypecurve.getPointAtLength(values1[val]);
c1.setAttributeNS(null, "transform", `translate(${pos.x},${pos.y})`);
});
svg{width:90vh; display:block;border:1px solid;overflow:visible}
#itr1{width:90vh;}
circle.circle1 {fill: rgb(0,0,22);}
circle.circle1:hover {fill: rgb(0,255,255);}
<svg viewBox="0 0 550 400" >
<!-- draw path and circles -->
<path id="hypecurve" d="M12.967,349.469c15.107-87.283,25.932-180.142,54.214-264.61c31.17-93.095,54.138,17.688,65.096,53.934c11.354,37.558,23.177,74.976,34.309,112.6c26.534,89.679,79.275-25.286,92.183-45.57c11.749-18.462,20.938-43.699,69.798-48.289c70.298-6.604,177.054-4.848,224.858-5.774" fill="none" stroke="#444" stroke-width="3"/>
<circle class= "circle1" id="c1" cx="0" cy="0" r="5" fill="#004" />
</svg>
<p>c1:<br><input type="range" id="itr1" min="0" max="100" value="0" step="1" /></p>