SVG技术入门:如何画出一条会动的线
如果你看不到这个演示,说明你的浏览器不支持SVG,请使用最新版的谷歌浏览器或火狐浏览器。
我喜欢用图画、图表来演示流程信息或浏览器的操作过程,但大量的图片有时候也会很不方便。在我的一个关于应用缓存和缓存方法的演讲中,我让屏幕首先空白,然后各种图表按照我的演讲内容自己一点一点的画出来。下面就是我如何用SVG技术在浏览器里实现这种效果的。
SVG里的路径(path)
SVG里用来定义路径的格式堪比正则表达式的怪异:
<path fill="none" stroke="deeppink" stroke-width="14" stroke-miterlimit="0"
d="M11.6 269s-19.7-42.4 6.06-68.2 48.5-6.06 59.1 12.1l-3.03 28.8 209-227s45.5-21.2 60.6 1.52c15.2 22.7-3.03 47-3.03 47l-225 229s33.1-12 48.5 7.58c50 63.6-50 97-62.1 37.9"
/>
我通常是使用Inkscape软件来画SVG图,但它产生的SVG文件完全不可读,而且有很多冗余代码,但在你编辑的时候,它会提供一个SVG DOM视图。相比起Adobe Illustrator使用自己的格式、仅提供SVG格式导出,我更愿意使用前者。
属性d
里的每一部分都是告诉浏览器生成一个动作——移动到某一个点,开始画一条线,画一个贝齐尔弧线,等等。
关于这些数据是如何变成动画,变成一条慢慢画出的线,这是个非常复杂的问题,幸运的是,我们不用考虑这些。我可以使用颜色和设置点的宽度,让SVG路径变成一段一段的点线,并控制点的偏移量:
<path stroke="#000" stroke-width="4.3" fill="none" d="…"
stroke-dasharray=""
stroke-dashoffset=""
/>
如果你看不到这个演示,说明你的浏览器不支持SVG,请使用最新版的谷歌浏览器或火狐浏览器。
属性stroke-dasharray
是让你指定画出的线段每段的长度,第二个值是各段之间空隙的长度。属性stroke-dashoffset
是让你指定每个小段的起始偏移量。
请将两个游标都拖到最大值,然后缓慢的减少dashoffset属性值。哇塞,线被动态的画出来了!线的长度你可以从DOM里获取:
var path = document.querySelector('.squiggle-container path');
path.getTotalLength();
让线自动画出
在SVG里运用动画的最简单的方法是使用CSS animations或transition。但有一点问题,在IE里不好用,如果你想在IE里实现,你需要使用requestAnimationFrame
,并用JavaScript一帧一帧的修改里面的值。
最好别使用SMIL,IE不支持它而在谷歌浏览器和Safari里也有性能问题。
我打算使用CSS transitions,所以,这个演示无法在IE里运行。而且我无法找到一个好用的方法检测你的IE是否已经支持了这些SVG元素上的动画,因为IE里能检测到所有的SVG属性,但就是不能用。
在前面的例子中,我们用SVG里的属性定义了小短线,其实我们可以用CSS做相同的事情。SVG里各种属性在功能上是和CSS属性完全相同的。
var path = document.querySelector('.squiggle-animated path');
var length = path.getTotalLength();
// 清除之前的动作
path.style.transition = path.style.WebkitTransition =
'none';
// 设置起始点
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// 获取一个区域,获取相关的样式,让浏览器寻找一个起始点。
path.getBoundingClientRect();
// 定义动作
path.style.transition = path.style.WebkitTransition =
'stroke-dashoffset 2s ease-in-out';
// Go!
path.style.strokeDashoffset = '0';
如果你看不到这个演示,说明你的浏览器不支持SVG,请使用最新版的谷歌浏览器或火狐浏览器。
使用getBoundingClientRect
来获取一个区域,虽然不是很好的做法,但好用。但有个问题是,如果你在同一个JavaScript执行里修改一个样式两次而没有强制更新这个区域,那只有最后一次有效。
我通常通过获取offsetWidth
来找到SVG范围,但在火狐里好像不灵。
更多有趣的实现
Lea Verou使用相同的技术创建了一个加载动画。Josh Matz 和 El Yosh 在他的基础上创建了这个有趣的立方体动画。
我们已经使用stroke-dasharray
属性创建了虚线动画,实际上我们可以使用这种技术创建出更复杂的效果。例如,下面是贾斯汀比伯的签名,看起来有点像莫尔斯电码:
历害呀!!
nc111
nc111nc111
不明觉厉
楼主画一根DJB 搞我们