UI设计师SVG动画进阶篇——路径变形动画(下篇)

上篇:juejin.im/post/591272…
中篇:juejin.im/post/591514…浏览器

在前面两篇文章中,虽然完整描述了任意图形的变形动画实现方法,但最大的局限性显而易见,那就是都是一个图形变造成另外一个图形,那若是是一变多或者多变一怎么实现呢?下面就来解决这个问题。bash

8.不一样数量之间图形的变形动画

以最简单的例子来讲明,我要作个一个水珠裂变成两个水珠的动画效果,裂变过程毫无疑问属于图形的变形过程。可是裂变以后分开成两个的时候怎么办?这是咱们首要解决的问题。先说一下各类实现思路,而后进行对比。svg

8.1 方法1——分割法(断开路径)

咱们在前面说过用剪刀断开锚点,使闭合路径转换成开放路径,因此聪明的设计师小伙伴应该能够想到,既然能够断开一个锚点,那就能够再断开一个,让一条路径变成两条路径,两条路径分别实现本身的动画效果,换句话说,就是半个小水珠变成一个小水珠的变形动画,以下图所示工具

分割法实现变形动画思路
分割法实现变形动画思路

剩下的工做就循序渐进,给半水珠增长锚点,调整全部路径的手柄,本身定义起点和路径方向。


这里须要注意一点,对于咱们前面的起点和终点重合的开放路径,锚点数=路径数,但当水珠分割成两条路径后,因为 起点与终点不重合,因此锚点数+1=路径数,也就是说,咱们要给半个小水珠的开放路径多增长一个锚点,此外,对于这种起点终点不重合的开放路径,AI导出的SVG的d值是以小c结尾的,不一样于起点终点重合的大C结尾,处理方法仍然很简单,只须要 断开路径的地方让起点与终点错开一点就能够了,视觉上是没有影响的。下图就是我处理的变形后的水珠的顶部。

处理后错开的起点终点
处理后错开的起点终点

同时咱们动画模板那里要改一下,多增长一个变形动画,而且两个 <path>各调用一个变形动画,代码以下:

<svg>
<style>
@keyframes deform1{
0% {d:path('');}       /*变形前左半个水滴的路径*/
100% {d:path('');}     /*变形后左边水滴的路径*/
}
@keyframes deform2{
0% {d:path('');}     /*变形前右半个水滴的路径*/
100% {d:path('');}   /*变形后右边水滴的路径*/
}
#animate1 {animation: deform1 2s ease;}
#animate2 {animation: deform2 2s ease;}
</style>
 <path id="animate1"/>
<path id="animate2"/>
  </svg>复制代码

那看一下这种实现思路获得的效果如何post

虽然表面上看实现了1变2,但一分为二的过程极其生硬,主要缘由是咱们实现思路就是半个水滴到一个水滴,因此动画过程彻底复现了咱们的思路。优化

8.2 方法2——重叠法(“一变一”+“一变一”)

上面方法实现的效果并很差,并且设想一下,这是变成2个,那若是是变成3个,4个呢,要把变形前的图形切的稀碎么……
既然咱们前面两篇都是一变一的实现方法,那么咱们不妨变通一下,好比变形前的水滴实际上有两个彻底重合的图形,一个变成左边的,一个变成右边的。实现思路以下:动画

重叠法变形动画思路
重叠法变形动画思路

虽然两个水滴是重合的,可是路径方向那里,向左变形和向右变形的原始路径方向必定要是相反的,不然你将获得下面这种效果(你甭说,就这种误打误撞的错误效果,作个打开的门啊,书啊的,竟然还不错):url


那即便是对称变换,看下效果又如何呢:

重叠法实现的裂变更画
重叠法实现的裂变更画

看上去彻底不像变形动画对不对,明明是两个位移动画的拼接。并且改来改去的辣么麻烦,早知道这种位移动画,直接来个按X轴移动的动画就行了。

先不要把这个方法一棍子打死,那是由于咱们变形先后的图形形状没有变化,才会产生位移效果,若是是作一个圆形变成两个水滴,变形效果仍是有的,以下:spa

圆形变水滴的动画
圆形变水滴的动画

并且变成3个甚至更多,也毫无违和感:

圆形变成多个水滴的动画
圆形变成多个水滴的动画

重叠法也是种 “障眼法”,当你的形状是实色填充时,OK,没有问题,但当你填充的是半透明色或者是描边呢,你将获得下面这种:

重叠法实现的描边效果的变形动画
重叠法实现的描边效果的变形动画

效果一点都不欢乐,直接暴露了咱们妄图掩盖的事实真相。
固然了,方法2虽然不是最佳,但某些情景下也是适用的。
不过咱们重磅推出的是下面这个方法。设计

8.3 方法3——拼接法(找到裂变的临界点)

此方法堪称方法1和方法2的结合,咱们方法1是把原始形状生生的切成两半,那这个方法是咱们找变形后图形一分为二的那一瞬间,好比针对这个变形效果,就是两个变形后水滴仍然相连的刹那,此时,仍然是一个图形,动画分解成两个阶段,第一阶段,藕断丝连,第二阶段,快刀斩下。但在瞬间,运用了“障眼法”,来实现两个过程的完美拼接。
那咱们要作的,就是在AI里用路径查找器,把临界点的两个形状进行合并。我用图示表示一下

拼接法变形动画思路
拼接法变形动画思路

2和3,看上去是彻底同样的,但放大来看,2是一个图形但3是两个图形叠放在一块儿,第一阶段就是1→2,这个咱们很轻松就能实现,无非给1补充锚点,第二阶段3→4,这个实现方法多样,你用位移动画也行,用变形动画也行,利用2和3的彻底一致性,把握好时间拼接点,无缝对接。
为了省事,位移的那里我也直接用定义路径变形动画来实现,代码以下:

<svg>
<style>
@keyframes deform1{
0% {d:path('');} /*原始水滴*/
100% {d:path('');}/*临界点水滴*/
}
@keyframes deform2{
0% {d:path('');} /*重叠效果的左边水滴*/
100% {d:path('');} /*移动位置后的左边水滴*/
}
@keyframes deform3{
0% {d:path('');} /*重叠效果的右边水滴*/
100% {d:path('');} /*移动位置后的右边水滴*/
}
#animate1 {animation: deform1 1.5s cubic-bezier(0.8, 0, 0.85,0.5);}
#animate2 {animation: deform2 0.5s cubic-bezier(0.15, 0.5, 0.2, 1) 1.5s;}
#animate3 {animation: deform3 0.5s cubic-bezier(0.15, 0.5, 0.2, 1) 1.5s;}
</style>
<path id="animate1"/>
<path id="animate2"/>
<path id="animate3"/>
</svg>复制代码

简单解释一下,2s的动画效果我拆分红2部分,前一部分变形效果1.5s,第二部分位移0.5s,但要延迟1.5s后执行,以实现时间上的无缝对接。
修改运动速率,是由于ease表示慢-快-慢,若是拼接动画都使用这个运动速率,整个流程下来就是慢-快-慢-慢-快-慢,在临界点那里会有明显的停顿感,所以我修正了运动速率以消除停顿效果。原本用了预约义的值,变形动画为ease-in(慢—快),而位移动画为ease-out(快-慢)。但发现衔接部分仍然不够顺滑,索性本身从新写了速率曲线,说着吓人,方法掌握以后其实很简单,正好借这个案例说一下:

运动速率曲线分割方法
运动速率曲线分割方法

首先我绘制了一个ease曲线,而后在中间位置一分为二,分别做为两个动画的速率曲线,cubic-bezier值对应的是控制曲率的手柄的两组坐标点(正常坐标系且X和Y最大为1,非笛卡尔坐标系),即我在图中用红点标出来的部分,而后就能够轻松的获取坐标值了。

来看下效果如何:

拼接后的变形动画
拼接后的变形动画

为了证实咱们这个效果是有效的,我改为描边效果,来看一下:

描边效果
描边效果

做为设计师的你,仍然会对这个效果不满意,理由很简单,咱们都知道水的表面是有张力的,且是柔性的,这种动效则缺乏一分为二的那种粘连感。
咱们从新定义一下临界点的形状,在AI中操做起来极为便利,不过向两侧移动下左侧和右侧的锚点

从新定义临界点形状
从新定义临界点形状

获得这么辣眼睛的效果纯属意外……
而后对这个形状进行分割,什么工具均可以,剪刀,刻刀,随意,分割成两个部分以后,再变造成最后的左右水滴,获得效果以下:

完美的水滴裂变效果
完美的水滴裂变效果

通过层层分析(分明就是我本身不停的掉坑里,爬出来,继续……),终于获得了理想的变形效果。

小总结,之因此没有从一开始就直接来方法3,是由于方法3费时最长,其实咱们须要的是越简单的方法实现越理想的效果越好(拗口),因此在一些场景中,能用方法1和方法2(尤为方便)来实现实则再好不过。
对于方法3这种寻找临界点的图形,则更适合精细化制做。

小技巧:因为这类变形动画涉及的形状及位置比较多,为了方便本身查看SVG代码,实际展示的色值信息因为是定义在CSS样式中,因此建议做图时定义成方便识别的颜色,或者建在不一样图层上,(AI导出的SVG会根据不一样图层进行分组)。

9.镂空图形的变形动画

截止到这里,咱们已经能够实现无穷的变形效果了,裂变,组合,玩到嗨起来。但还有一种常见的图形,须要单独说一下实现变形动画的方法,就是下面这种镂空的图形,此次的案例是从一把钥匙变成一把锁,只须要这一个案例作基础,掌握方法以后,一通百通,原始图片以下:

有镂空的图形
有镂空的图形

若是没有钥匙孔和锁孔,这种变形动画实现起来可谓简单无比,但多了孔以后,貌似有点棘手,别急,先来看这种图形(AI中须要合并形状)d值的面目。因为案例图形太过复杂,咱们仍是从最简单的入手。

最简单的镂空形状的d值分析
最简单的镂空形状的d值分析

从d值中能够看出来,AI在导出SVG时生成了两个路径,上面对应底层路径,下面对应镂空形状的路径,这不就是AI里减去底层形状的意思嘛,SVG对于这种包含多个路径的形状自动解读成第一个路径为底层形状,其余形状都执行 减去底层形状的操做。了解规则后,再来完成这种有镂空图形的变形动画天然水到渠成。
对图形的改造套用咱们最基础的动画模板,而后把含有两个路径的d值对应填进去,会获得下面这种效果:

钥匙变成锁
钥匙变成锁

从最终效果中能明显看出来,镂空部分和底图部分分别执行了两个变形动画。那最大的问题也在这里。变形动画的过程当中填充色会超出正常的变形区域。那如何来改善呢?

10.使用变形蒙版的变形动画

这里借用之前提到的蒙版来试一下。
UI设计师对于蒙版丝绝不陌生,SVG蒙版的原理是同样的,镂空部分我用黑色蒙版来处理,达到一样的效果。
思路以下:动画拆解成两部分,一部分是无镂空部分的图形的变形动画,另外一部分我把变形动画附加给蒙版黑色部分,即咱们要镂空的区域。

蒙版变形动画
蒙版变形动画

与上面简单的利用d值里包含的两个路径对应变形到另外两个路径不一样,咱们把镂空部分单独用一个蒙版变形动画来实现,首先,根据蒙版的原理,绝对不会有填充色超出变形区域的状况,其次,这样赋予了这类变形动画更多的自由度,好比能够设置不一样的时间和动效等等。
我把代码和注释贴上来简单解释一下:

<svg>
<style>
@keyframes deform1{
0% {d:path('');}/*变形前底图*/
100% {d:path('');}/*变形后底图*/
}
@keyframes deform2{
0% {d:path('');}/*变形前蒙版黑色部分*/
100% {d:path('');/*变形后蒙版黑色部分*/
}
}
#animate1 {animation: deform1 3s ease;}/*
底图变形动画*/
#animate2 {animation: deform2 3s ease ;fill:#000000;}/*
蒙版黑色区域变形动画*/
</style>
<mask id="hollow"><rect x="0" y="0" fill="#ffffff" width="" height=""/><path id="animate2" /></mask><!--定义一个白色矩形为底,黑色为变形动画的蒙版hollow-->
<path  id="animate1" mask="url(#hollow)"/><!--底图变形动画上附加一个蒙版变形动画-->
</svg>复制代码

看到这里,没有任何SVG蒙版基础的UI设计师或许会有些发憷,但仍是但愿了解一下,由于蒙版动画很强大,后面会开单独的专题。
来看一下利用蒙版变形结合底图变形的动画效果如何:

蒙版变形+底图变形
蒙版变形+底图变形

很明显的,不会出现填充色超出区域的问题,我取两个不一样实现方法动画的同步一帧对好比下:

两种方法对比
两种方法对比

前面提到过,把蒙版动画单独定义自由度更高,好比,我再给蒙版变形动画增长一个50%的关键帧,而后缩小成极小的一个点,动画效果就变成了下面这种:

蒙版变形改进后的动画
蒙版变形改进后的动画

彷佛更改进了一些。
对比得出的结论是蒙版变形来实现更优化,但实际使用时,尽可能采用两个路径同步变形这种,为何?简单呐,先看效果,不满意再采用蒙版变形动画。

12.路径曲线值的转换

咱们对图形的操做一直说的都是锚点手柄部分处理,一直想避开这部分,主要是考虑到UI设计师毕竟对AI软件更熟悉,操做起来更方便,而是我在作案例的实际操做过程当中,发现对于锚点较少的状况还好,找对应路径也能顺利找到,而在我上面钥匙和锁变形动画中(20个锚点),即便经过d值看出来有些曲线时非小c开头的,但数起来真的很困难,因此额外增长这一部分,能够直接经过修改d值实现同一成小c曲线转换的方法。只说方法,不说原理哦。

12.1小s→小c

先说最容易出现的小s,看过上篇的设计师们已经知道产生小s的方法是由于转换点直接拖拽,并且s后面只有四个值,转化方法以下:
sA,B,C,D←→c前一组倒数第二个数减去倒数第四个数,前一组倒数第一个数减去前一组倒数第三个数,A,B,C,D
啊啊啊,头晕了对不对,这仍是仅限于前面是正常一组小c开头的曲线的转换公式,因此除非你只有极个别小s出现,不然多算伤身啊。

12.2小l→小c

设计师小伙伴们必定擦亮眼睛,由于小l与数字1太像,但只要记得咱们的d值只支持一位小数,而出现相似3.51这样的数据时,那必定是3.5和小l。小l是绘制直线的命令,后面只有两个值,转换方法以下:
lA,B←→c0,0,A,B,A,B
前面补两个0,后面复制一组小l后面的两个值。
小l和小s最多见,下面这两个则出现的状况少一些,一点出现,建议改一下图形,为什么,来看转化方法。

12.3小h→小c

h为水平直线绘制命令,后面只有一个值,转换方法以下:
hA←→c0,0,A,前一组路径曲线小c的最后一个值,A,前一组路径曲线小c的最后一个值

12.4小v→小c

v为垂直直线绘制命令,同上同理,转换方法以下:
vA←→c0,0,前一组路径曲线小c的倒数第二个值,A,前一组路径曲线小c的倒数第二个值,A
看,诚不欺你,因此为了避免给本身制造困难,稍微挪挪锚点,不要那么水平垂直的直来直去嘛。
还有出现的状况是绝对定位大写字母开头的,这个转换起来,啧啧,反正不借助工具,我是不能接受手动计算的。
就酱。
借助公式,顺便作个动画效果看看。

拔地而起的小蘑菇
拔地而起的小蘑菇

想作个拔地而起的小蘑菇,我只须要AI导出的SVG里对应的蘑菇的d值就能够了,直线呢?有了上面的公式,我来手动改造,连锚点都懒得在AI里加了,反正也不会导出咱们须要的d值,还要一通调整,太麻烦。那怎么改呢?先数数,蘑菇一共6段曲线组成,好了,我只须要知道直线路径的起点坐标,个人是(60,490),那我经过手动,把直线的d值改形成下面这种:

d:path('M60,490,c0,0,50,0,50,0,c0,0,100,0,100,0,c0,0,50,0,50,0,c0,0,50,0,50,0,c0,0,50,0,50,0,c0,0,50,0,50,0')复制代码

这就是相对坐标的好处,c0,0,50,0,50,0,表示一根水平的宽度50的直线,对应蘑菇的6段曲线,重复6次就OK了。

蘑菇动画
蘑菇动画

虽然说一副软趴趴的样子,但好歹站起来了。
原来这种调整方法也蛮好用嘛,妈妈不再用担忧我调整手柄拖拽到吐血了。

13.关于添加虚拟曲线

再来一根直线变飞鸟与鱼的,哦,不是飞鸟,是肥鸟。把前面的知识点借机再唠叨一遍。顺便带出来压箱底的技能,虚拟曲线。先卖个关子。


看到这三者之间的变化,内心先抖一抖,每一个形状都不一样。先来最复杂的吧,肥鸟先断开闭合路径,而后起点终点错开,以便生成小c结尾的相对坐标绘制的曲线。鱼原来只有4段曲线,肥鸟有9段,按理说应该哒哒哒给鱼补上锚点,停停停,就是这里。如今插播一个重磅武器, 虚拟曲线c0,0,0,0,0,0。虚拟曲线是我给它的命名(怎么,不可嘛),这货实际是不存在的,它存在的价值,聪明的设计师小伙伴必定能够猜出来,就是来补充缺失的曲线的。并且至关具备跟随性,你把它放在哪里,它就是前面曲线的终点。
这个例子中,鱼有4段曲线,好了,咱们的虚拟曲线该上场了,因此我把直线里面塞进3三段虚拟曲线即增长3个c0,0,0,0,0,0,d值变成了下面这个样子:

d:path('M40,130,c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,280,0,280');复制代码

其实这个效果和

d:path('M40,130,c0,0,0,280,0,280');复制代码

是同样的,咱们只是在欺骗浏览器,制造一些不存在的曲线以便弥补变形先后图形曲线数量的不一样。
动画能够拆成两部分,衔接起来,也能够像我这样在一个动画里完成,因为最终小胖鸟的曲线数量最多,多以最终我给直线补充了8段虚拟曲线,给小鱼补充了5段(所有放到鱼嘴的位置),而后看一下效果

直线-鱼-肥鸟变形动画
直线-鱼-肥鸟变形动画

是否是感受太简单了,并且很愤怒的指出来,为何到最后才说这种简单好用的方法?!勿燥,理由很简单,加锚点是为了让变形的过程变得均匀。好比个人小鸟变成鱼,若是是经过分散添加锚点来实现,效果是下面这样的:

均匀添加锚点后的变形效果
均匀添加锚点后的变形效果

因此,即便你用这种偷懒的方法,若是不是为了某种特殊效果,也最好把c0,0,0,0,0,0散布开,穿插在其余曲线之间。但有时候,你能够利用这种虚拟曲线为所欲为的实现但愿达到的效果。刚才作的拔地而起的蘑菇,咱们说它软趴趴,是由于直线被均匀分割成6段宽50的直线,每一个直线对应向组成蘑菇的曲线变换。那怎么才能让变形效果变得“刚硬”起来,好比从中心点拔地而起。这时,要换种思路对直线进行改造。

直线改造计划
直线改造计划

既然须要中心点,那么第一步,从中间一分为二是少不了的,至关于从起点开始,有2条宽150的水平直线,此时直线的d值以下:

d:path('M60,490c0,0,150,0,150,0c0,0,150,0,150,0')复制代码

而后把须要增长的4条虚拟曲线塞进去,位置就是中心点,也就是第一段路径后面。

d:path('M60,490c0,0,150,0,150,0c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0,0,0c0,0,150,0,150,0')复制代码

好了,看看是否是从中心点长出的蘑菇:

补钙后的蘑菇~
补钙后的蘑菇~

看这硬朗的变形效果,完美!

14.利用路径变形动画实现“描边”动画

svg描边动画效果在别的文章里介绍过,利用路径变形动画依旧能够完成,只不过这只是种“伪描边”,更像是从某个点辐射出去的效果,看一下下面这个动画:

一株怒放的花
一株怒放的花

这就是我用变形动画实现的。

动画思路拆解
动画思路拆解

边看图边说,既然咱们说过能够添加虚拟曲线,那么再延伸一下,当一段路径只有起点M值,剩下全是c0,0,0,0,0,0组成,那么无论有多少段虚拟曲线,实际这只是一个虚拟点,但这个点看不见,倒是有坐标的,坐标就是M值。
因此咱们这个动画制做过程就简单多了,主要获取我图中红圈圈出的四个点的坐标就能够了。我实际绘图的颜色是左上角那个“绝美”的配色,理由很简单,为了方便本身区分啊,左边叶子色值#FF0000,中间花茎#00FF00,右边叶子#0000FF,只看FF值就能够轻松分辨出对应的路径了。
好比咱们左边叶子的绽开点坐标值为(X1,Y1),叶子有2段曲线路径,那变形前的虚拟点d值对应为MX1,Y1c0,0,0,0,0,0c0,0,0,0,0,0,就能轻松实现变形效果了。
代码的简化版即注释以下:

<svg>
<style>
@keyframes deform1{
0% {d:path('');} /*花茎变形前虚拟点*/
100% {d:path('');}/*花茎曲线路径*/
}
@keyframes deform2{
0% {d:path('');}/*左边叶子变形前虚拟点*/
100% {d:path('');}/*左边叶子曲线路径*/
}
@keyframes deform3{
0% {d:path('');}/*右边叶子变形前虚拟点*/
100% {d:path('');}/*右边叶子曲线路径*/
}
@keyframes deform4{
0% {d:path('');}/*花朵变形前虚拟点*/
100% {d:path('');}/*花朵曲线路径*/
}
#animate1 {animation: deform1 1s ease forwards;}/*长出花茎时间1s,forwards表示动画状态停留在结束状态*/
#animate2 {animation: deform2 1s ease 1s forwards;}/*长出左边叶子时间1s,延迟1s(即花茎动画时间)开始*/
#animate3 {animation: deform3 1s ease 2s forwards;}/*长出右边叶子时间1s,延迟2s(即花茎+左边叶子动画时间)开始*/
#animate4 {animation: deform4 1s ease 3s forwards;}/*开花时间1s,延迟3s(即花茎+左边+右边叶子动画时间)开始*/
</style> 
<path  id="animate1"/>
<path  id="animate2"/>
<path  id="animate3"/>
<path  id="animate4"/>
</svg>复制代码

这里再提供一个转换方法,就是关于绝对位置大C绘制路径。若是你导出的d值中有大C开头的曲线,关于这种经过虚拟点变形的话,就没有必要再去调整路径了。
c0,0,0,0,0,0等同于CX1,Y1,X1,Y1,X1,Y1。X1和Y1就是你的起始点M值的坐标。关于SVG路径path的贝塞尔曲线绘制方法的介绍网上不少,耐心看一遍就知道转换的缘由了。

实际使用过程当中,必定要把握的思路是尽可能用最简单的方法来实现动效,已经开始着手准备写一篇SVG微动效的文章,毕竟SVG结合CSS3实现的动画不可与真正的动画制做软件同日而语,应用最多的场景,应该是一些微动效。这篇做为变形动画的进阶篇,涉及的知识点比较杂,包括拼接动画临界点的定义及自定义速率曲线实现无缝拼接的方法,结合蒙版变形动画实现变形动画,非小c开头的路径曲线的转化,添加虚拟曲线。变形动画全篇终。有问题单独留言。

相关文章
相关标签/搜索