查看原文
其他

每周一点canvas动画

zhouyufei 前端圈 2020-04-23

好吧!各位骚年们,《每周一点canvas动画》是一个系列文章,该系列文章并不对canvas的API做过多的介绍,我默认你已经了解基本的canvas绘图API,并在此告诉你如何使用简单的数学与物理知识创建相当酷炫的动画。一说到物理和数学知识各位骚年们是不是感觉蛋疼(原谅我说脏话了),不过我要告诉你,我们用到的数学和物理知识真的很简单。所以,给位骚年不要害怕,我们一起飞如何!


关于canvas是个什么东西,在这我就不做过多的介绍了,随便在度娘上搜一搜,关于canvas的概念啊,API什么的就都有了。那么我们接下来就要开始介绍,动画(animation)是怎样形成的?。动画其实是由不同的静态画面组成,每一幅静态画面我们叫做一帧(frame),当众多的静态画面按照一定的规则快速运动时,我们的眼睛就会欺骗我们的大脑,从而形成物体运动的假象。


canvas作为H5中最为重要的新增特性,使开发者可以用它来创作各种令人惊叹的作品。但开发者最关心的问题肯定是浏览器的支持情况啊!


另外需要知道的是本系列文章主要介绍Canvas 2D动画,关于 3D 动画(webGL)暂时还不涉及。好的接下来,进入重点内容。首先是我们创作动画的基本文档结构:

  1. <!DOCTYPE html> 

  2. <html lang="en"

  3. <head> 

  4.     <meta charset="UTF-8"

  5.     <title></title> 

  6. </head> 

  7. <body> 

  8.    <canvas id="canvas" width='500' height="500"

  9.        <P>you browser not support canvas!</P> 

  10.    </canvas> 

  11.    <script> 

  12.        window.onload = function(){ 

  13.        //我们的代码 

  14.        } 

  15.    </script> 

  16. </body> 

  17. </html>


以上代码就是我们创建动画的主要文档结构。那么为了对Canvas动画有个更加直观的认识,在这里先给大家展示用Canvas创作的两个酷炫动画,看看它是否够简洁,够酷炫!

1、百分比加载

第一个动画是一个用Canvas做的百分比加载动画,效果图如下:


具体代码:

  1. <!DOCTYPE html> 

  2. <html lang="en"

  3. <head> 

  4.     <meta charset="UTF-8"

  5.     <title>百分比加载</title> 

  6. </head> 

  7. <body> 

  8.  <canvas id="canvas" width="500" height="500" style="background:#000;"></canvas> 

  9.   <script> 

  10.      window.onload = function(){ 

  11.          var canvas = document.getElementById('canvas'),                //获取canvas元素 

  12.              context = canvas.getContext('2d'),                            //获取画图环境,指明为2d 

  13.              centerX = canvas.width/2,                //Canvas中心点x轴坐标 

  14.              centerY = canvas.height/2,               //Canvas中心点y轴坐标 

  15.              rad = Math.PI*2/100             //将360度分成100份,那么每一份就是rad度 

  16.              speed = 0.1             //加载的快慢就靠它了 

  17.  

  18.          //绘制蓝色外圈 

  19.          function blueCircle(n){ 

  20.             context.save(); 

  21.             context.strokeStyle = "#49f"//设置描边样式 

  22.             context.lineWidth = 5//设置线宽 

  23.             context.beginPath(); //路径开始 

  24.             context.arc(centerX, centerY, 100 , -Math.PI/2, -Math.PI/2 +n*rad, false); //用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针) 

  25.             context.stroke(); //绘制 

  26.             context.closePath(); //路径结束 

  27.             context.restore(); 

  28.          } 

  29.          //绘制白色外圈 

  30.          function whiteCircle(){ 

  31.              context.save(); 

  32.              context.beginPath(); 

  33.              context.strokeStyle = "white"

  34.              context.arc(centerX, centerY, 100 , 0Math.PI*2false); 

  35.              context.stroke(); 

  36.              context.closePath(); 

  37.              context.restore(); 

  38.          }  

  39.  

  40.          //百分比文字绘制 

  41.          function text(n){ 

  42.             context.save(); //save和restore可以保证样式属性只运用于该段canvas元素 

  43.             context.strokeStyle = "#49f"//设置描边样式 

  44.             context.font = "40px Arial"//设置字体大小和字体 

  45.             //绘制字体,并且指定位置 

  46.             context.strokeText(n.toFixed(0)+"%", centerX-25, centerY+10); 

  47.             context.stroke(); //执行绘制 

  48.             context.restore(); 

  49.          } 

  50.  

  51.          //动画循环 

  52.          (function drawFrame(){ 

  53.                 window.requestAnimationFrame(drawFrame, canvas); 

  54.                 context.clearRect(00, canvas.width, canvas.height); 

  55.  

  56.                 whiteCircle(); 

  57.                 text(speed); 

  58.                 blueCircle(speed); 

  59.  

  60.                 if(speed > 100) speed = 0

  61.                 speed += 0.1

  62.             }()); 

  63.      } 

  64.  </script> 

  65. </body> 

  66. </html>


在上面的代码段中,我们通过一个立即执行函数来执行我们的动画循环,并在内部通过

  1. window.requestAnimationFrame(drawFrame, canvas);


循环调用自身,requestAnimationFrame是一个新的API,作用与setTimeInterval一样,不同的是它会根据浏览器的刷新频率自动调整动画的时间间隔。在循环中我们每次执行都会重新绘制蓝色的圆弧,和白色的圆环和百分比加载的文字,由于每次绘制的时间间隔很小,只有十几毫秒(主要看电脑),所以我们的肉眼是无法清楚地分别每一帧的画面,这样就形成了我们看到的动画。试一试吧!看看够不够酷炫!

2、黑客帝国(Matrix)

好吧!这个动画效果,就如标题所示,是一个绝对的酷炫动画效果,具体是不是在黑客帝国里出现过我也忘了,因为实在是比较早的电影。废话不多说,上效果图:


具体代码:

  1. <!DOCTYPE html> 

  2. <html lang="en"

  3. <head> 

  4.     <meta charset="UTF-8"

  5.     <title>Martrix</title> 

  6.     <style> 

  7.         body{ 

  8.             padding: 0

  9.             margin: 0

  10.             overflow: hidden; 

  11.         } 

  12.     </style> 

  13. </head> 

  14. <body> 

  15.    <canvas id="canvas" style="background:#000;"></canvas> 

  16.    <script> 

  17.        window.onload = function(){ 

  18.            var canvas = document.querySelector('canvas'), 

  19.                context = canvas.getContext('2d'), 

  20.                w, h; 

  21.                w = canvas.width = window.innerWidth; 

  22.                h = canvas.height = window.innerHeight; 

  23.  

  24.            //初始化 

  25.            var clearColor = 'rgba(0, 0, 0, .1)'//用于绘制渐变阴影 

  26.                wordColor = "#33ff33"//文字颜色 

  27.                words = "0123456789qwertyuiopasdfghjklzxcvbnm,./;'\\[]QWERTYUIOP{}ASDFGHJHJKL:ZXCVBBNM<>?"

  28.                wordsArr = words.split(''), //将文字拆分进一个数组 

  29.                font_size = 16,  //字体大小 

  30.                clumns = w / font_size, //文字降落的列数 

  31.                drops = []; 

  32.  

  33.            for(var i=0; i<clumns; i++){ 

  34.                  drops[i] = 1

  35.                } 

  36.  

  37.            function draw(){ 

  38.                context.save(); 

  39.                context.fillStyle = wordColor; 

  40.                context.font = font_size + "px arial"

  41.                //核心 

  42.                for (var i = 0; i < drops.length; i++){ 

  43.                         var text = wordsArr[Math.floor(Math.random() * wordsArr.length)]; 

  44.                         context.fillText(text, i * font_size, drops[i] * font_size); 

  45.                         if (drops[i] * font_size > h && Math.random() > 0.98){ 

  46.                             drops[i] = 0

  47.                         } 

  48.                         drops[i]++; 

  49.                     } 

  50.                context.restore(); 

  51.            } 

  52.  

  53.            //动画循环 

  54.            (function drawFrame(){ 

  55.                window.requestAnimationFrame(drawFrame, canvas); 

  56.                context.fillStyle = clearColor; 

  57.                context.fillRect(00, w, h); 

  58.  

  59.                draw(); 

  60.            }()) 

  61.  

  62.            //resize 

  63.            function resize(){ 

  64.                w = canvas.width = window.innerWidth; 

  65.                h = canvas.height = window.innerHeight;`` 

  66.            } 

  67.            canvas.addEventListener("resize", resize); 

  68.        } 

  69.    </script> 

  70. </body> 

  71. </html>

这段代码有两个比较核心的地方:

1,在初始化部分,我们定义了一个变量clearColor = ‘rgba(0, 0, 0, .1)’,用处就和注释一样,用于绘制阴影,它的主要用处在动画循环部分。原理可以这样理解:我们每画新的一帧,就在上面覆盖一个透明度为0.1的矩形模块,这样就形成了我们看到的阴影,是不是很简单呢?

2,在初始化的注释处和核心模块处,这部分的原理是这样:首先我们设置了每个字体的大小(font_size),然后,用canvas的宽度除以字体的大小,我们就得到了需要绘制的列数(clumns), 然后创建了一个数组drops,数组的长度为clumns,并且每个元素的值都为1(drops在这有什么用呢?继续往下看)。

在绘制部分,我们采取的思路是一行一行的绘制,首先在循环中随机的获取文字,在文字绘制API部分注意这行代码:

  1. context.fillText(text, i * font_size, drops[i] * font_size);


我们知道该API有三个参数,第一个是绘制的文字,第二,三是文字的坐标。在X坐标部分为i * font_size,也就是说在循环完成后每个文字的X轴坐标是(0, 16, 32,48…), 而Y坐标为drops[i] * font_size由于drops内元素的初始值都为1,所以文字的Y坐标为(16, 16, 16, …),这样我们就相当于先绘制了第一行的文字。那么紧接着我们绘制第二行只需要将drops中的元素加1即可,即(第二行的Y轴坐标为(32,32,32…))。


依次类推,我们就绘制了满屏的文字,通过渐变阴影我们就可以看到文字似乎是向下运动的效果。为了让他们看上去运动的速度不一致,我们加上了这行代码:

  1. if (drops[i] * font_size > h && Math.random() > 0.98){ 

  2.     drops[i] = 0

  3. }

这行代码我们,判断的是当前绘制的这行文字的Y坐标是否超过了canvas的高度,如果超过又从第一行开始绘制,那么如何让他们出现差异性呢!小秘密在Math.random() > 0.98这,if中的两个条件一个是判断文字高度,另一个是判断一个随机数是佛大于0.98,只有当两个条件同时成立才能回到第一行重新绘制。所以,由于第二个条件是随机的,那么差异性就自然而然的出现了!

看看,只需要这么简单的代码就能写出这么酷炫的效果,是不是很赞!你也试试吧!不理解没关系,这里只是让你看看canvas能做出多么酷炫的效果。如果,有什么不懂的地方可以,评论哦。

下一节,我们就正式开始我们的Canvas动画之旅!!!

【您可能感兴趣的文章】

一、新手向:Vue 2.0 的建议学习顺序

二、最少知识原则之模式的黄金原则

三、[活动]第三期读书会之程序员节迟来的礼物

四、单一职责原则之模式的黄金法则

五、js中的一对多 - 订阅发布模式

六、谈谈js属性的纠结往事

七、移动端h5开发相关内容总结(四)

八、移动端h5开发相关内容总结(三)

九、[CSS篇]移动端 h5开发相关内容总结

十、[JavaScript 篇]移动端h5开发相关内容总结



前端圈--打造专业的前端技术会议

为web前端开发者提供技术分享和交流的平台

打造一个良好的前端圈生态,推动web标准化的发展

官网:http://fequan.com

微博:fequancom | QQ群:41378087


长按二维码关注我们

投稿:content@fequan.com

赞助合作:apply@fequan.com

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存