为之漫笔

使用SVG画线

为之漫笔 · 2017-05-09翻译 · 1107阅读 原文链接

这个位置应该有一个示例,因为JavaScript不可用或者浏览器不支持SVG而没有显示(译者注:关于这个示例,建议大家用Chrome浏览器去看原文)。

我喜欢使用图示来展示信息流或者浏览器行为,但大型图示光听听就让人皱眉头了。在讲Application Cache渲染性能的时候,我从空白屏幕开始,然后出现图示,随着我的讲解一点一点绘制。以下就是我的做法。

SVG中的路径

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"
/>

这个人类看不懂的SVG是我用Inkscape画的。虽然Inkscape有点笨重,但它可以在你编辑文档时让你看到SVG DOM,而不像Adobe Illustrator那样使用自己的格式,而且只能导出才能得到SVG。

d属性的每一部分是告诉渲染引擎如何移动特定的点、开始画线,以及向另一个点画一条贝塞尔曲线,等等。

要利用这些数据实现动画,渐进地画出一条线来,想想都头疼。好在,我们可以做点弊。除了颜色和宽度,我们还可以把SVG路径设置为虚线,然后控制这条虚线的偏移。

<path stroke="#000" stroke-width="4.3" fill="none" d="…"
  stroke-dasharray=""
  stroke-dashoffset=""
/>

dasharray: (这里是一个滑块,可以拖动以增大stroke-dasharray中的值,请参见原文)

dashoffset:这里是一个滑块,可以拖动以增大stroke-dashoffset中的值,请参见原文)

这个位置应该有一个示例,因为JavaScript不可用或者浏览器不支持SVG或input[type=range]而没有显示(译者注:关于这个示例,建议大家用Chrome浏览器去看原文)。

stroke-dasharray用于指定线条可渲染部分的长度,然后是间隙的长度。stroke-dashoffset用于控制绘制虚线起始的位置。

把上面示例中的两个滑块向右拖到最大值,然后慢慢缩小dashoffset。哇,你刚刚就是在画线啊!998.01是从DOM中可以获得的线条的大致长度:

var path = document.querySelector('.squiggle-container path');
path.getTotalLength(); // 988.0062255859375

让它动起来

制作SVG动画最简单的方法是使用CSS动画或过渡。缺点是IE不支持,如果想让IE支持,得用requestAnimationFrame ,并且要通过脚本逐帧更新相应的值。

不能使用SMILIE同样不支持,而且在Chrome & Safari中表现也不好(这个话题我会单独写一篇文章)。

我打算使用CSS变换,因而在IE中是不行了。然而,我找不到一种可靠的方法对SVG元素的过渡做特性检测:IE是什么属性都有,但就是不工作。

在第一个例子中,我使用了SVG属性定义虚线,不过你在CSS里也可以做同样的事。大多数SVG的表现性属性都有对应的CSS属性。

var path = document.querySelector('.squiggle-animated path');
var length = path.getTotalLength();
// Clear any previous transition
path.style.transition = path.style.WebkitTransition =
  'none';
// Set up the starting positions
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
path.getBoundingClientRect();
// Define our transition
path.style.transition = path.style.WebkitTransition =
  'stroke-dashoffset 2s ease-in-out';
// Go!
path.style.strokeDashoffset = '0';

(原文这里有一个示例,请大家看原文。——译者注)

这个位置应该有一个示例,因为JavaScript不可用或者浏览器不支持SVG而没有显示(译者注:关于这个示例,建议大家用Chrome浏览器去看原文)。

使用getBoundingClientRect 触发布局有点歪门邪道的意味,但有用。可惜的是,如果在同一次JavaScript执行流中修改同一个样式两次而不在中间帧强制同步布局,则只有最后一个才算数。关于这个问题的详细情况,以及Web Animations API为什么能大幅提高效率,可以看我在Smashing Magazine写的文章。

一般来说,我都用offsetWidth来触发布局,但好像这个方法在Firefofx中对SVG元素不起作用。

虚线还能玩出更多花样

Lea Verou使用类似的技术实现了与Chrome中类似的加载动画Josh MatzEl Yosh在此基础上实现了这个时髦的魔方动画

我们这篇文章只是利用stroke-dasharray画了一条后面带一截间隙的线,大家可以发挥想象力,实现更复杂的模式,添加更多数值。比如,下面这Justin Bieber(贾斯汀·比伯)的亲笔签名,其中的线条是一组摩尔斯电码,意思是:Christ our saviour。(SVG图请移步到原文观看。——译者注)

扩展阅读

相关文章