悬停时对SVG进行动画处理-悬停时不要让别人微笑

问题描述

我有一个SVG文件,其直线成点。我想要实现的是,当用户将鼠标悬停在svg文件上时,点变成像附件图像一样的微笑。

过渡需要平稳。

这里最好的方法是什么?我可以只使用CSS还是可以使用JS?

enter image description here

谢谢

解决方法

使用SMIL animation,无需任何脚本即可实现。它使立方贝塞尔曲线路径从直线变为曲线,然后向后变形。动画是由位于该行顶部的透明矩形上的mouseovermouseout事件触发的。

该行本身使用了两个小技巧的组合:您可以将pathLength设置为属性,以便stroke-dasharray然后根据其计算短划线长度。对于stroke-dasharray: 0 1stroke-linecap的组合,零长度短划线显示为点,其笔划宽度为直径。只需玩pathLengthstroke-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删除笔画。