canvas 2D炫酷动效的实现套路和需要的技术积累
张鑫旭-鑫空间-鑫生活 2017-03-18 0 阅读
by
zhangxinxu
from
?p=6017
本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随意。
我上学时候,06,07年的样子,总是情不自禁被炫酷的flash动效吸引。印象很深的是一个一堆线和球连在一起弹来弹去的效果,觉得还厉害,实现这个效果的人一定是大牛,然后,反编译工具去查看这些酷酷的动态是怎么实现的。我这一看里面的源代码,我勒个擦,洋洋洒洒,代码认得我,我不认识它。但是,通过改改元素,以及一些数值参数,也能实现了类似的效果,并沾沾自喜,以为自己学到了技术,还好,我没这么走下去。
其实现在很多前端小伙伴,跟我当时的做法很类似,去网上找插件,找工具,找现成代码,然后改改用用,也能满足项目需求,并认为自己学习能力很强,解决问题能力很强,实际上并没有什么竞争力,因为搬运工本质上就是一个体力劳动,一旦市场饱和,或者年龄上去搬运不动了,则职业生涯只能止步不前了。
后来为了以后更高的高度,断臂求生,置之死地,告别拿来主义,毕业后长达九个月的时间,都在一直系统学习基础知识,CSS基础,JS基础以及PHP基础,这是一段很多人都不理解的过程,但现在回过头来看看,虽然好像起步比别人晚了,但是至少从目前来看后劲要比大多数人都要足。因为万丈高楼平地起,万变不离其宗,你基础扎实了,任何场景,任何需求的实现其实都是手到擒来,即使你以前根本就没有做过这样的东西。
最近接了一个小需求,其中有个场景非常适合我早年见过那个弹来弹去的效果。10年过去了,我脑子里留下的只是那个动效的形,而代码一丁点的记不得。但是当我想实现类似的效果的时候,我脑子一瞬间就知道该如何实现它了,这种体验有一种说不出的感觉,就好像你这么多年一直辛辛苦苦地学那些枯燥的基础知识好像有了意义,有了价值!
我觉得自己上面这个小故事可以对一些小伙伴的学习关注点带来一些启示,不过话又说回来,自己的故事只适合自己,有些人说我就是想混口饭吃,我不想工作学习那么辛苦,我的建议可能就不适合你。
二、canvas动效眼见为实关于上面提到的小效果,您可以狠狠地点击这里: canvas实现的星星连线联动弹动动效demo
Gif截屏效果如下:
上面这个看上去还有点小酷,看上去比较有实现难度的动画效果,实际上都是由一些非常基础的知识累积而成,而且都是有套路可循的。
三、canvas 2D炫酷动效的实现的基本套路目前在web领域,基本上看到那些酷酷的2d动效,都是 canvas 实现的,flash已经基本上都被淘汰了, canvas 效果的实现,无需安装任何插件,IE9及其以上浏览器支持,至少在移动端,大家可以放心大胆使用,甚至webGL 3D效果都可以尝鲜。
无论是雪花飘,星星动还是粒子飞,其 canvas 实现都是一样的套路,这里就讲讲我的理解:
1. 了解canvas画布的工作原理实际上, canvas 的工作原理和我们的显示器是一样的,都是不断的刷新绘制,刷新绘制,只不过显示器的刷新是实时的,而 canvas 的刷新手手动触发的,当然如果我们只想在 canvas 上实现静态的效果,是没必要不断刷新的。
举个简单例子,如果我们希望一个圆圈圈从画布左边移到画布右边的效果,我们可以在第1秒的时候让圆圈圈在最左边,然后下一秒的时候,先用黑板擦把我们的圆圈圈擦掉,然后再重新画圆圈圈再往右偏一点的样子,就这样不断擦不断绘,我们肉眼看到的就是一个动画效果了,有点类似于放电影。
一般来讲,清除画布使用下面的代码:
var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); // 清除画布 context.clearRect(0, 0, canvas.width, canvas.height); 2. canvas画布的不断绘制在以前我们都是使用定时器进行绘制,但是现在建议 使用requestAnimationFrame来实现刷新绘制 ,为了向下兼容,我们一般会做类似下面的处理:
// requestAnimationFrame的向下兼容处理 if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(fn) { setTimeout(fn, 17); }; }于是,动效绘制大致路数会变成这样:
var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); // 画布渲染 var render = function () { // 清除画布 context.clearRect(0, 0, canvas.width, canvas.height); // 绘制 draw(); // 继续渲染 requestAnimationFrame(render); }; render();而上面的 draw() 就是在canvas画布上绘制图形的代码了,但如果仅仅上面代码还不够,如果是同一个位置不断刷新,我们看到的还是静止不动的效果,还差一个运动变量。
4. 需要一个运动坐标变量假设我们就有一个圆圈圈,同时 ball.x 就表示此圆圈圈的水平坐标位置,则,代码套路可以是这样:
var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); // 坐标变量 var x = 0; // 绘制方法 var draw = function () { ball.x = x; }; // 画布渲染 var render = function () { // 清除画布 context.clearRect(0, 0, canvas.width, canvas.height); // 位置变化 x++; // 绘制 draw(); // 继续渲染 requestAnimationFrame(render); }; render();然而,实际项目中,很少,就只有一个圆圈圈,而是一大波的圆圈圈,此时上面的变量设置就会有问题,哪有那么多变量让你设置呢!通常有两种处理方法,一种是变量管理,有一个大变量,变量里面放的都是小变量,类似于 [{},{},{},...] 这种数据结构;还有一种是走实例化对象,变量存储在实例对象上,很显然,后面一种对变量的管理要更加方便和易于理解。
5. 实例对象管理canvas图形颗粒变量假设圆圈圈实例名称是Ball,则有:
var Ball = function () { this.x = 0; this.draw = function () { // 根据此时x位置重新绘制圆圈圈 // ... }; };