文章目录
  1. 1. 动画
    1. 1.1. 动画的原理
    2. 1.2. 过渡算法
    3. 1.3. 高阶动画
    4. 1.4. SVG动画
    5. 1.5. D3动画
  2. 2. 裁切
  3. 3. 蒙版
  4. 4. 小结

动画

与用户合理自然的交互,肯定是少不了动画的存在的,好的产品就是需要遵循人类的习惯,把数据以合理的方式一步一步展现出来,给与用户顺畅、自然的体验。

动画的原理

其实SVG的动画还是很丰富的,但这里只罗列一些基础。主要原因:

  1. 我目前实现SVG动画主要是靠d3,而不是SVG原生动画。
  2. SVG原生动画与d3动画并不冲突,可以结合起来一起使用,各司其职。
  3. 如果大部分动画交给d3,那SVG的原生动效只需要了解即可,使用时Google参考资料就行。
  4. 我想传达一些编程的思想,编程时要靠自己的判断技术的优缺点和适用性。

原理上来讲很简单,做前端的动画很多都是这种方式,比如这样一个SVG:

1
<rect x="0" y="0" width="0" height="200" />

因为宽度是0,什么都看不到,如果我在一定的时间里面将 width 从0 变到 1000,那就可以看到宽度慢慢加长的一个变化了,如果频率够高的话,人类的眼睛就几乎感觉不到这个过程中间有停顿了,所以就称为动画。一般来说一秒60帧,就是相当流畅了。

过渡算法

首先要设定时间和帧数:比如这个宽度在2秒钟的时间从0到1000,按每秒50帧(也是很流畅的)。那么2秒钟,就有100帧,相当于每20毫秒,这这个矩形的宽度会进行一次变化!

如果按照我们最常匀速变化,那相当于每20毫秒,宽度就会增加10,到第2000毫秒(2秒)结束时,宽度刚好到达1000。

那么,我们就称这个匀速计算每个时间点宽度的算法是过渡算法。这个匀速过度也称为线性过渡。

过渡的算法还有很多种,实际上就是通过对过渡过程中的快慢的控制,达到更好更炫的效果。常用的过渡算法在SVG, D3,还有各种工具包里面都有内置。个人好几年前也自己写的玩过: https://runjs.cn/code/fswjwdu7 。有兴趣可以参考。

高阶动画

通常我们做比较高级的动画时,就不是做个过渡比较简单了。比如:

  1. 为动画指定关键的时间点。
  2. 一个动画的运动结果做为另一个动画的触发条件。
  3. 在动画的过程中,进行各种交互。
  4. 延时、倒退、重复,反向,等等都有不同的算法。

SVG动画

实际上,SVG动画是基于一个称为 SMIL 的规制定的。

先看一下上面DEMO的SVG动画的实现,仅需要在元素内部加入 animate 标签即可

1
2
3
4
5
6
7
8
9
10
11
<rect x="0" y="0" width="0" height="200">
<animate
attributeName="width"
attributeType="XML"
from="0"
to="1000"
begin="0s"
dur="2s"
fill="freeze"
/>
</rect>

animate 标签的主要属性如下:

attributeName 属性名称
attributeType 属性类型 auto
from,to 开始结束值
begin,dur 开始时间、持续时间
fill 结束后的动作 freeze

(请原谅我的一笔带过)关于更加详细的SVG的动画说明:可以移步: 超级强大的SVG SMIL animation动画详解

D3动画

关于D3的基本使用,请参考 SVG之七:D3入门 。在这里,我先说下SVG的动画在D3里面的实现。

在d3里面,使用动画变得简单了很多,对于上面的功能,代码如下:

1
2
3
4
5
d3.select('rect')                //选中矩形
.transition() //开始动画
.duration(2000)   //设定时间
.ease("linear") //过渡算法
.attr('width', 1000); //改变宽度

除了代码行数比SVG里面的少之外,它并没有使用SVG增加DOM节点的方式来定义动画,而是在JavaScript里面进行,所以灵活性要比SVG动画要强很多。

当然之所以推荐D3用来实现动画,是因为D3具备了更强大的API及算法,不仅可以变换属性,CSS,还可以支持各种style,text,自定义插值等等,和自身提供的比例尺API相结合,非常强大。

实际上SVG动画也有它的优点,比如说可以支持PATH运动等,请根据适用性来选择具体的实现方式。

裁切

在一些网站,上传一个正方形的头像后,会展示成一个图形,或是有圆角的方块来显示。而裁切就比类似,它只保留了图像的一部分后,把多余的内容丢掉。

在SVG里定义标签为 ,通常放在 里面,包含一个ID,定义后通过 css的 clip-path:url(#clipId) 进行引入。

里面需要把裁切的图像形状作为子元素定义进去,可以是基础图形标签或是标签,另外裁切通常需要配合 来一起使用,即使用 use = 裁切路径(clip-path) + 被裁切的对象(xlink:href)

利用好裁切,也可心搞一些炫酷的事情,比如可以很容易的将一个图形的各个部分拆开显示在不同的地方,分别进行不同的组装进行展示。

基础的裁切代码:

1
2
3
4
5
6
7
8
9
10
<defs>
<!-- 把对象中间的圆形剪出来 -->
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<circle cx="0.5" cy="0.5" r="0.5">
</clipPath>
<symbol id="symbol">
<rect x="0" y="0" width="100" height="100" fill="#999"/>
</symbol>
</defs>
<use xlink:href="symbol" style="clip-path:url(#clip)"/>

蒙版

与裁切不同,裁切是把多余的切掉,保留选中的部分,而蒙版则是把选中的部分蒙住,多余的部分不变。

在SVG里面,蒙版是 定义方法和较像,但可以直接使用在元素上,不需要使用use来进行内容与路径的组合,而且将mask直接运用于图像。

mask通常使用半透明效果,使用一些颜色结合而做出比较不错的特效,比如:

1
2
3
4
5
6
7
8
9
10
11
12
<svg width="400" height="300">
<defs>
<linearGradient id='white2black'>
<stop offset="0" stop-color="white"></stop>
<stop offset="100%" stop-color="black"></stop>
</linearGradient>
<mask id="small-rect">
<rect x="0" y="0" width="400" height="300" fill="url(#white2black)"></rect>
</mask>
</defs>
<rect id="back" x="0" y="0" width="400" height="300" fill="#d4fcff"></rect>
<rect id="front" x="0" y="0" width="400" height="300" fill="#fcd3db" mask="url(#small-rect)"></rect>

小结

动画是一个非常重要的概念,是用户体验极其重要的一部分,动画的原理简单,但要做出好的动画,需要依赖于产品水平的发挥。

而裁切和蒙板,使用频率没那么高,加上自身API非常固定(主要是依赖于path),所以没做详细说明。

文章目录
  1. 1. 动画
    1. 1.1. 动画的原理
    2. 1.2. 过渡算法
    3. 1.3. 高阶动画
    4. 1.4. SVG动画
    5. 1.5. D3动画
  2. 2. 裁切
  3. 3. 蒙版
  4. 4. 小结