【发布时间】:2021-02-24 09:55:39
【问题描述】:
我有一个 SVG 文件,其中点在直线上。我想要实现的是当用户将鼠标悬停在 svg 文件上时,点会变成像附加图像一样的微笑。
过渡需要平滑。
这里最好的方法是什么?我可以只使用 css 还是应该使用 js?
谢谢
【问题讨论】:
标签: javascript css svg svg-animate
我有一个 SVG 文件,其中点在直线上。我想要实现的是当用户将鼠标悬停在 svg 文件上时,点会变成像附加图像一样的微笑。
过渡需要平滑。
这里最好的方法是什么?我可以只使用 css 还是应该使用 js?
谢谢
【问题讨论】:
标签: javascript css svg svg-animate
使用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 中删除笔触。
【讨论】: