一起画画吧。canvas中有很多API。如果30分钟一一罗列,你肯定是看不完的,还不如自己去看看至于文档(笑),本教程的思路是用示例从头开始逐步解释基本用法。Canvas相关文档准备整理画布:通过添加标签添加canvas元素;获取画布:通过标签的id获取画布对象;获取画笔:获取canvas对象2D环境的getContext("2d")方法。代码示例:constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');画一个箭头首先我们画一个红边黄底的箭头,使用面向对象的代码组织方式。整个代码如下。类名是Arrow。它有四个属性:x轴坐标、y轴坐标、底部颜色和旋转。实例方法是draw(),需要一个context对象作为参数,也就是准备工作中的context,相当于画笔。这其实就是一个类似依赖注入的过程,将canvas画笔交给实例的draw()方法处理。本例使用该笔刷绘制箭头,绘制过程见代码注释。需要特别注意以下几点:调用beginPath()方法后,moveTo()和lineTo的移动坐标是相对于beginPath()时画笔坐标的。可以理解为画笔自带坐标系,可以在画布上旋转移动。绘图作品的坐标属于该坐标系;beginPath()是绘图设置状态的起点,在绘图方法stroke()、fill()或closePath()结束后由代码设置的绘图状态范围;save()的作用是保存画笔的状态,因为画布中只有一支画笔,不同对象之间会传递。为了不污染后面的画,应该先保存,再用restore()恢复;本身是透明的,可以用CSS给它加个背景,例子一般用白色背景。/***箭头类*@class代表一个箭头。*//*eslintno-unused-vars:["error",{"varsIgnorePattern":"Arrow"}]*/classArrow{/***创建一个箭头。*/constructor(){this.x=0;这个.y=0;this.color='#ffff00';this.rotation=0;}/***绘制箭头。*@param{Object}_context-画布上下文。*/draw(_context){constcontext=_context;//会先保存画笔的状态context.save();//移动画笔context.translate(this.x,this.y);//旋转画笔context.rotate(this.rotation);//设置线宽context.lineWidth=2;//设置线条颜色context.strokeStyle='#ff0000';//设置填充颜色context.fillStyle=this.color;//开始路径context.beginPath();//将画笔移动到相对位置context.moveTo(-50,-25);//画线到相对位置context.lineTo(0,-25);context.lineTo(0,-50);context.lineTo(50,0);context.lineTo(0,50);context.lineTo(0,25);context.lineTo(-50,25);context.lineTo(-50,-25);//闭合路径context.clo路径();//填充路径的包围区域context.fill();//绘制路径context.stroke();//加载保存的笔信息context.restore();}}同样的,我们可以画别的东西对,比如圆球.js,参数多一点,慢慢了解成品的效果,可以先看这篇(略剧透):一个可以跟踪的箭头鼠标位置加入循环移动现在我们已经掌握了画图的基本技巧,可以画箭头arrow.js和圆圈ball.js了,但是这只是一张静止的图,接下来还需要一个循环不断的进行擦除并重绘实现帧动画。下面代码中的绘图函数drawFrame会立即执行并递归调用自身,正如您将在大多数示例中看到的那样。(见代码)(functiondrawFrame(){//类似于setTimeout操作window.requestAnimationFrame(drawFrame,canvas);//擦除画布context.clearRect(0,0,canvas.width,canvas.height);//...继续你的绘画}());循环原理在上一篇文章中有讲解,不再赘述。这里要说明的是clearRect()。该函数接受一个矩形坐标,即(x轴坐标,y轴坐标,矩形宽度,矩形高度),用于清除矩形区域的绘图。例子中直接清空了整个画布,但这不是绝对的。是否刷新,部分刷新还是全部刷新,都需要灵活处理。这里有一个不刷新的例子:给鼠标绘图工具一些权力。现在屏幕在不断的重绘,但是为什么还是静止的呢?因为每次刷新都不会改变要绘制的内容。然后我们给它一个目标,让它可以移动,比如让箭头一直指向鼠标。下面是核心代码,主要目的是求箭头在每一帧中的旋转角度。这里使用的鼠标会实时返回鼠标的x轴和y轴坐标。打包原理在之前的文章中已经提到。根据鼠标的坐标和箭头鼠标的坐标可以得到鼠标相对于箭头的距离dx和dy。(如下图所示)箭头的旋转角度可以通过dx和dy的反正切函数得到。这里有几点需要注意:仔细看上面代码中箭头的绘制过程,可以看到它的原点在中心,所以旋转角度正好是画笔的旋转角度;dx和dy是鼠标相对于箭头的坐标,所以把坐标系移到图中箭头的中心没有错;使用atan2而不是atan是因为tan值可能会重复,比如-1/2和1/(-2)都是-0.5,不能区分象限,而atan2可以区分。完整示例:跟踪鼠标位置的箭头(参见下面的代码)window.onload=function(){constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');constmouse=utils.captureMouse(canvas);constarrow=newArrow();arrow.x=canvas.width/2;arrow.y=canvas.height/2;(functiondrawFrame(){window.requestAnimationFrame(drawFrame,canvas);context.clearRect(0,0,canvas.width,canvas.height);constdx=mouse.x-arrow.x;constdy=mouse.y-arrow.y;arrow.rotation=Math.atan2(dy,dx);arrow.draw(context);}());};三角函数的上下运动终于顺利过渡到三角函数的话题上了(笑)。三角函数的反正切应用不止一种。让我们看另一个例子。下面是一个小球上下移动的核心代码。关键是小球y轴坐标的变化。这是句子:ball.y=clientY+Math.sin(angle)*range;使用Math.sin(angle)的取值范围是-1到1,随着角度的增大会不断重复,让小球在一定范围内上下移动。完整示例:一个上下移动的球(可调参数版本)window.onload=function(){constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');常量球=新球();让角度=0;//运动中心constclientY=200;//范围常量范围=50;//速度常数speed=0.05;ball.x=canvas.width/2;ball.y=画布。高度/2;(functiondrawFrame(){window.requestAnimationFrame(drawFrame,canvas);context.clearRect(0,0,canvas.width,canvas.height);ball.y=clientY+Math.sin(angle)*range;angle+=速度;ball.draw(上下文);}());};向前移动只是上下移动不好玩,那就让圆向前移动,其实就是每一帧改变x轴的位置。核心代码如下。与之前的上下移动相比,x轴的速度有所提高,每一帧移动一点点,形成波浪前进的效果。完整的例子:一个波浪球(见下面的代码)window.onload=function(){constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');常量球=新球();让角度=0;constcenterY=200;const范围=50;constxspeed=1;const速度=0.05;球.x=0;(functiondrawFrame(){window.requestAnimationFrame(drawFrame,canvas);.clearRect(0,0,canvas.width,canvas.height);ball.x+=xspeed;ball.y=centerY+Math.sin(angle)*range;angle+=yspeed;ball.draw(context);}());};其他例子其他应用就不一一解释了,只列举几个:两个轴同时变化的圆被连续放大。随机块中心点到鼠标的距离
[Fes]基于canvas的前端动画-游戏介绍(二)相关文章