问题描述
我有一个SVG文件,其直线成点。我想要实现的是,当用户将鼠标悬停在svg文件上时,点变成像附件图像一样的微笑。
过渡需要平稳。
这里最好的方法是什么?我可以只使用CSS还是可以使用JS?
谢谢
解决方法
使用SMIL animation,无需任何脚本即可实现。它使立方贝塞尔曲线路径从直线变为曲线,然后向后变形。动画是由位于该行顶部的透明矩形上的mouseover
和mouseout
事件触发的。
该行本身使用了两个小技巧的组合:您可以将pathLength
设置为属性,以便stroke-dasharray
然后根据其计算短划线长度。对于stroke-dasharray: 0 1
与stroke-linecap
的组合,零长度短划线显示为点,其笔划宽度为直径。只需玩pathLength
和stroke-width
的值即可更改点的距离及其大小。
#line {
fill: none;
stroke: black;
stroke-width: 4;
stroke-dasharray: 0 1;
stroke-linecap: round;
}
#overlay {
opacity: 0;
}
<svg viewBox="0 0 100 100" width="150">
<path id="line" d="M 10 50 C 35 50 65 50 90 50" pathLength="15">
<animate attributeName="d" begin="overlay.mouseover" dur="0.3s"
fill="freeze" restart="whenNotActive"
from="M 10 50 C 35 50 70 50 90 50"
to="M 15 30 C 20 70 80 70 85 30"/>
<animate attributeName="d" begin="overlay.mouseout" dur="0.3s"
fill="freeze" restart="whenNotActive"
from="M 15 30 C 20 70 80 70 85 30"
to="M 10 50 C 35 50 65 50 90 50"/>
</path>
<rect id="overlay" width="100%" height="100%" />
</svg>
,
在下一个示例中,我将计算路径上点的位置,每个点的位置都是使用getTotalLength计算的路径总长度的十分之一。对于每个圆圈,我都设置了初始cx的值(在这种情况下,因为初始cy == 0,所以我没有设置它。
还在每个圆圈内添加2个<animate>
元素,这些元素将使cx和cy动画到限制路径上的下一个位置。
动画将在点击时开始。
const SVG_NS = "http://www.w3.org/2000/svg";//svg namespace
const dur = .5;// the animation duration
let circles = Array.from(document.querySelectorAll("circle"))
let la = a.getTotalLength();
let lb = b.getTotalLength();
let start = {x:-100,y:0}
circles.forEach((c,i) =>{
let da = i*la/10;
let db = i*lb/10;
let pa = a.getPointAtLength(da);
let pb = b.getPointAtLength(db);
c.setAttribute("cx",pa.x);
let a1 = document.createElementNS(SVG_NS,"animate");
a1.setAttribute("attributeName","cx");
a1.setAttribute("from",pa.x);
a1.setAttribute("to",pb.x);
a1.setAttribute("dur",dur);
a1.setAttribute("begin","svg.click");
c.appendChild(a1);
let a2 = document.createElementNS(SVG_NS,"animate");
a2.setAttribute("attributeName","cy");
a2.setAttribute("from",pa.y);
a2.setAttribute("to",pb.y);
a2.setAttribute("dur",dur);
a2.setAttribute("begin","svg.click");
c.appendChild(a2);
})
svg.addEventListener("click",()=>{
circles.forEach((c,i) =>{
let db = i*lb/10
let pb = b.getPointAtLength(db);
c.setAttribute("cx",pb.x)
c.setAttribute("cy",pb.y)
})
})
svg{border:solid}
path{fill:none; stroke:black;}
<svg id="svg" viewBox="-150 -50 300 150" width="300">
<path id="a" d="M-100,0 A15000,15000 0 0 0 100,0"/>
<path id="b" d="M-100,0 A150,150 0 0 0 100,0"/>
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
<circle r="5" />
</svg>
在示例中,绘制了用于计算圆的位置的路径。您可以从CSS删除笔画。