《每周一点canvas动画》是一个系列文章,本文并不对canvas的API作过多的介绍,我默认你已经了解基本的canvas绘图API,并在此告诉你如何使用简单的数学与物理知识建立至关酷炫的动画。一说到物理和数学知识各位骚年们是否是感受蛋疼(原谅我说脏话了),不过我要告诉你,咱们用到的数学和物理知识真的很简单,一点都不可怕。html
canvas做为H5中最为重要的新增特性,使开发者能够用它来创做各类使人惊叹的做品。但开发者最关心的问题确定是浏览器的支持状况(图片来自张鑫旭博客)!git
本系列文章主要介绍Canvas 2D动画原理,以及简单的如何在2D平面模仿3D效果的方法,中间可能会穿插一些与其余技术相结合的DEMO和项目。首先,咱们创做动画的基本文档结构以下。github
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>canvas动画序</title> </head> <body> <canvas id="canvas" width='500' height="500"> <P>you browser not support canvas!</P> </canvas> <script> window.onload = function(){ //咱们的代码 } </script> </body> </html>
在此咱们须要明白动画的基本概念:
动画实际上是由不一样的静态画面组成,每一幅静态画面咱们叫作一帧(frame),当众多的静态画面按照必定的规则快速运动时,咱们的眼睛就会欺骗咱们的大脑,从而造成物体运动的假象。在这里先给你们展现用Canvas创做的两个酷炫动画,看看它是否够简洁,够酷炫!web
第一个动画是一个用Canvas作的百分比加载动画(根据读者的建议,已经对错误的代码作了修改)。codePen地址canvas
var canvas = document.getElementById('canvas'), //获取canvas元素 context = canvas.getContext('2d'), //获取画图环境,指明为2d centerX = canvas.width/2, //Canvas中心点x轴坐标 centerY = canvas.height/2, //Canvas中心点y轴坐标 rad = Math.PI*2/100, //将360度分红100份,那么每一份就是rad度 speed = 0.1; //加载的快慢就靠它了 //绘制蓝色外圈 function blueCircle(n){ context.save(); context.beginPath(); context.strokeStyle = "#49f"; context.lineWidth = 12; context.arc(centerX, centerY, 100 , -Math.PI/2, -Math.PI/2 + n*rad, false); context.stroke(); context.restore(); } //绘制白色外圈 function whiteCircle(){ context.save(); context.beginPath(); context.strokeStyle = "#A5DEF1"; context.lineWidth = 12; context.arc(centerX, centerY, 100 , 0, Math.PI*2, false); context.stroke(); context.closePath(); context.restore(); } //百分比文字绘制 function text(n){ context.save(); context.fillStyle = "#F47C7C"; context.font = "40px Arial"; context.textAlign = "center"; context.textBaseline = "middle"; context.fillText(n.toFixed(0)+"%", centerX, centerY); context.restore(); } //动画循环 (function drawFrame(){ window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); whiteCircle(); text(speed); blueCircle(speed); if(speed > 100) speed = 0; speed += 0.1; }()); </script> </body> </html>
在上面的代码段中,咱们经过一个当即执行函数来执行咱们的动画循环,并在内部经过数组
window.requestAnimationFrame(drawFrame, canvas);
循环调用自身,requestAnimationFrame是一个新的API,做用与setTimeInterval同样,不一样的是它会根据浏览器的刷新频率自动调整动画的时间间隔。在循环中咱们每次执行都会从新绘制蓝色的圆弧,和白色的圆环和百分比加载的文字,因为每次绘制的时间间隔很小,只有十几毫秒(主要看电脑),因此咱们的肉眼是没法清楚地分别每一帧的画面,这样就造成了咱们看到的动画。该API的兼容处理以下:浏览器
if(!window.requestAnimationFrame){ window.requestAnimationFrame =(window.webkitRequestAnimationFrame|| window.mozRequestAnimationFrame|| window.oRequestAnimationFrame|| window.msRequestAnimationFrame|| function(callback){ return window.setTimeout(callback,1000/60); }); }
经典的黑客帝国效果,Geek们的最爱。目前,已经被我封装成插件,可供你们方便使用。codePen地址 | 插件地址bash
具体代码:dom
var canvas = document.querySelector('canvas'), context = canvas.getContext('2d'), w = canvas.width = window.innerWidth, h = canvas.height = window.innerHeight; //初始化 var clearColor = 'rgba(0, 0, 0, .1)', //用于绘制渐变阴影 wordColor = "#33ff33", //文字颜色 words = "0123456789qwertyuiopasdfghjklzxcvbnm,./;'\[]QWERTYUIOP{}ASDFGHJHJKL:ZXCVBBNM<>?", wordsArr = words.split(''), //将文字拆分进一个数组 font_size = 16, //字体大小 clumns = w / font_size, //文字降落的列数 drops = []; for(var i=0; i<clumns; i++){ drops[i] = 1; } function draw(){ context.save(); context.fillStyle = wordColor; context.font = font_size + "px arial"; //核心 for (var i = 0; i < drops.length; i++){ var text = wordsArr[Math.floor(Math.random() * wordsArr.length)]; context.fillText(text, i * font_size, drops[i] * font_size); if (drops[i] * font_size > h && Math.random() > 0.98){ drops[i] = 0; } drops[i]++; } context.restore(); } //动画循环 (function drawFrame(){ window.requestAnimationFrame(drawFrame, canvas); context.fillStyle = clearColor; context.fillRect(0, 0, w, h); //注意这 draw(); }())
这段代码有两个比较核心的地方:
1,在初始化部分,咱们定义了一个变量clearColor = 'rgba(0, 0, 0, .1)',用于绘制阴影。其原理是:每当动画绘制新的一帧,就在上面覆盖一个透明度为0.1的黑色矩形。随着层数的叠加,文字就会被逐渐遮盖造成了咱们看到的阴影。函数
2,在初始化的注释处和核心模块处。首先,设置了每一个字体的大小(font_size)。而后,用canvas的宽度除以字体的大小,就获得了须要绘制的列数(clumns), 而后建立了一个数组drops,数组的长度为clumns,而且每一个元素的值都为1(drops在这有什么用呢?继续往下看)。在绘制部分,咱们采起的思路是一行一行的绘制,首先在循环中随机的获取文字,在文字绘制API部分注意这行代码:
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...)。
依次类推,咱们就绘制了满屏的文字,经过渐变阴影咱们就能够看到文字彷佛是向下运动的效果。为了让他们看上去运动的速度不一致,加上了这行代码:
if (drops[i] * font_size > h && Math.random() > 0.98){ drops[i] = 0; }
这行代码判断的是当前绘制的这行文字的Y坐标是否超过了canvas的高度,若是超过又从第一行开始绘制,那么如何让他们出现差别性呢!小秘密在Math.random() > 0.98
这,if中的两个条件一个是判断文字高度,另外一个是判断一个随机数是佛大于0.98,只有当两个条件同时成立才能回到第一行从新绘制。因此,因为第二个条件是随机的,那么差别性就天然而然的出现了!
看看,只须要这么简单的代码就能写出这么酷炫的效果,是否是很赞!你也试试吧!不理解不要紧,这里只是让你看看canvas能作出多么酷炫的效果。
下一节,咱们就正式开始咱们的Canvas动画之旅!!!