打造高大上的Canvas粒子动画

首先来看下我们准备要做的粒子动画效果是怎么样的~

是这样:

或者是这样:

甚至是这样:

很酷炫!

那如何去实现类似上面的粒子动画甚至根据自己的喜好去做更多其他轨迹的动画呢~请看下面详细的讲解。

技术选择

因为粒子数量很多,而且涉及到图像像素处理,所以这里使用Canvas是不二选择。

注意,以下演示的代码只是关键代码,重点在于解决思路。

一、绘制粒子轮廓图

首先要在canvas画布上绘制一个由粒子组成的轮廓图,记录下每一个粒子的坐标,这样才能有后续的动画。

1.创建一个<canvas>元素,并获取Canvas画布渲染上下文

< canvas>是一个双标签元素,通过width和height的值来设置画布的大小。至于ctx(画布渲染上下文),可以理解为画布上的画笔,我们可以通过画笔在画布上随心所欲的绘制图案。如果浏览器不支持canvas会直接显示<canvas>标签中间自己设定的文字。当然<canvas>标签中间也可以是一张当不支持canvas时需要替换显示的图片。

2. 使用canvas的图像操作API绘制图像

绘制图像的关键API及参数说明:

引用MDN上的一张图会比较清晰的看出每个参数的作用:

drawImage就是把一个image对象或者canvas上(甚至是video对象上的的每一帧)指定位置和尺寸的图像绘制到当前的画布上。而在我们的需求中,是要把整个图像绘制到画布中。

对应浏览器看到的效果:

3.获取图像的像素信息,并根据像素信息重新绘制出粒子效果轮廓图

canvas有一个叫getImageData的接口,通过该接口可以获取到画布上指定位置的全部像素的数据:

把获取的imageData输出到控制台可以看到,imageData包含三个属性:

其中,width、height是读取图像像素信息完整区域的宽度和高度,data是一个Uint8ClampedArray类型的一维数组,包含了整个图片区域里每个像素点的RGBA的整型数据。这里必须要理解这个数组所保存像素信息的排序规则,请看下图描述的data数组:

每一个色值占据data数组索引的一个位置,一个像素有个4个值(R、G、B、A)占据数组的4个索引位置。根据数列规则可以知道,要获取第n个位置(n从1开始)的R、G、B像素信息就是:Rn = (n-1)*4 ,Gn = (n-1)*4+1 ,Bn = (n-1)*4+2  ,so easy~  当然,实际上图像是一个包括image.height行,image.width列像素的矩形而不是单纯的一行到结束的,这个n值在矩形中要计算下:

由于一个像素是带有4个索引值(rgba)的,所以拿到图像中第i行第j列的R、G、B、A像素信息就是 Rij = [(j-1)*imageData.width + (i-1)]*4 ,Gij = [(j-1)*imageData.width + (i-1)]*4 + 1,Bij = [(j-1)*imageData.width + (i-1)]*4 + 2,Aij = [(j-1)*imageData.width + (i-1)]*4 + 3 。每个像素值都可以拿到了!

接下来就要把图像的粒子化轮廓图画出来了。那么,怎么做这个轮廓图呢,我们先读取每个像素的信息(用到上面的计算公式),如果这个像素的色值符合要求,就保存起来,用于绘制在画布上。另外,既然是做成粒子的效果,我们只需要把像素粒子保存一部分,展示在画布上。

具体做法是,设定每一行和每一列要显示的粒子数,分别是cols和rows,一个粒子代表一个单元格,那么每个单元格的的宽高就是imageWidth/cols和imageHeight/rows,然后循环的判断每个单元格的第一个像素是否满足像素值的条件,如果满足了,就把这个单元格的坐标保存到数组里,用作后续绘制图案用。

关键参考代码:

用完整代码做出的demo及效果:

至此,粒子轮廓图已经制作完成。

二、制作粒子动画

制作粒子动画分两种:

一种是粒子漂浮类,这种比较简单,只需要随机的改变每个粒子的位置值,然后一直执行setInterval或者requestAnimationFrame重绘画布即可,具体的效果因人喜好而去设定,就不具体讲解了,做了个简单的粒子漂浮的例子。

另一种是粒子的轨迹动画,这个相对复杂一些。这里要介绍的是每个粒子按照指定的轨迹在指定的时间内做位移,最终汇聚成指定图案的动画效果(也就是文章一开始的动效),要做成这类动画效果需要解决两个问题:一个是动画轨迹,另外一个是每个粒子执行动画的时机。

粒子动画轨迹

动画位移的轨迹,最常见的就是单位时间内改变固定的位移值,从而达到动画效果。但要做到炫酷的效果依赖这种单调固定的位移肯定是不行的。所以位移可以依赖缓动函数去做到单位时间内改变不一样的位移值,从而达到特别的效果。

制作缓动效果有两种方法:

一种是自己设定好控制点,然后通过贝塞尔曲线公式来计算每个单位时间的坐标值。

引用了wikipedia里面的图:

上面两个图都是在绘制一条特定曲线,可以看出二次曲线需要一个特定控制点P1,三次曲线需要两个特定控制点P1和P2来确定一条曲线,高阶曲线甚至需要更多的控制点来确定曲线轨迹。

求曲线的公式是根据德卡斯特里奥算法计算得来的,直接上公式。

二次曲线对应的公式:

三次曲线对应的公式:

从公式可以看出,只要确定控制点坐标、起始坐标和终点坐标后,就可以确定了一条曲线,然后就可以根据曲线公式求出每个时刻t对应的位置值B(t)。

当然使用这种方法需要自己去制定控制点坐标,计算也比较复杂,实现起来很繁琐。没事,我们还有别的办法确定曲线。

另外一种方法就是使用已有的缓动函数,不需要自己制定控制点,这里推荐出名的Tween算法的缓动函数,用其中一个缓动函数来介绍下参数值,其他缓动函数所传的参数值是一样的:

是不是觉得很熟悉?对没错,jquery用的动画扩展插件easing.js就是Tween算法的缓动函数。有了这现成的缓动函数,就可以制定粒子的起始点、终点(终点就是图案本身的坐标位置)以及动画执行持续时间来做我们要的效果。

关键参考代码:

根据参考代码做出一个效果:

嗯,动画效果是有了,但总感觉不太对劲。。。唔,仔细观察一下,是图案动画执行太过整体了,没有明显的颗粒动画效果,这就引出粒子动画的另一个关键点,粒子执行动画的时机。

粒子执行动画的时机

要让粒子效果比较明显,那就不能让动画效果执行太过整体了,需要让图案上每个粒子有不同的时间间隔启动,根据一定的规律交错的执行动画。这里的粒子启动间隔有两种,一种是每一行粒子执行时间间隔,要让每一行的粒子启动时间有规律错开;另外一种是每一行粒子之间启动时间随机的错开,这样执行的粒子动画才会有一种层次感和每个粒子有独立动画的颗粒感。看下加了粒子启动时间间隔之后的效果对比:

比上面不加粒子启动时间间隔的效果好多了。

嗯,介绍差不多就是这样了,如果上面介绍的方法还是解决不了问题的话,还有办法。。。我把粒子动画效果和Tween的缓动函数一起封装了一下。直接配置一下就可以用了。 用法就是创建一个带有id的canvas,设定好宽度和高度,引入particle.min.js,然后配置一下参数即可, demo:

只有canvasId、imgUrl、cols、rows是必填的,其他参数都是根据需要自己选填。  ( ͡° ͜ʖ ͡°)✧

本文部分图片引用来自

感谢你的阅读,本文由 腾讯ISUX 版权所有,转载时请注明出处,违者必究,谢谢你的合作。

注明出处格式:腾讯ISUX (https://isux.tencent.com/card-design-thinking.html)

原文发布于微信公众号 - 腾讯ISUX(tencent_isux)

原文发表时间:2016-09-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏WOLFRAM

把图像结合到画图当中

1273
来自专栏九彩拼盘的叨叨叨

学习概要:前端该会的 Photoshop 使用

564
来自专栏Young Dreamer

canvas绘图不清晰的解决方案

现象描述   同样大小的图片(60x60px)用canvas和DOM绘制,结果发现canvas的画面质量要差很多。结果如下图所示。 ?   上图中,左侧红框中的...

18310
来自专栏柠檬先生

SVG 使用

SVG即Scalable Vector Graphics可缩放矢量图形,使用XML格式定义图形, 主要优势在于可缩放的同时不会影响图片的质量。 SVG 在htm...

1919
来自专栏从零开始学 Web 前端

从零开始学 Web 系列教程

在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。现在就让我们一起进入 Web 前端学习的冒险之旅吧!

1134
来自专栏ytkah

怎么采集dedecms自定义内容模型

  有时我们需要用到dedecms提供的自定义内容模型功能去添加自定义内容模型来满足需求,那么dedecms自定义内同模型怎么添加采集规则呢?打开“/dede/...

2686
来自专栏菜鸟计划

CSS布局(一) 盒子模型基础

一、盒子模型 标准盒子模型  从下图可以看到标准 w3c 盒子模型的范围包括 content、padding、border、margin,并且 content ...

3365
来自专栏机器学习从入门到成神

image的srcset属性

介绍 响应式页面中经常用到根据屏幕密度设置不同的图片。这个时候肯定会用到image标签的srcset属性。srcset属性用于设置不同屏幕密度下,imag...

701
来自专栏王二麻子IT技术交流园地

热点图像的制作

其实这个功能主要是用在地图的制作上啊!    你见过“联想”机器上联想公司赠送的“我的办公室”软件的界面吗?在那幅办公室的图片上用鼠标点一下办公桌上的键盘,就...

18910
来自专栏iKcamp

微信小程序教学第四章第三节(含视频):小程序中级实战教程:详情-功能完善

增加 下一篇 的功能,我们需要在视图中绑定一个事件,来触发代码中的响应函数,此函数会调用接口,返回下一篇文章内容数据。

820

扫码关注云+社区