上篇主要是理论的概述,本篇会多些实践,来说讲canvas的基础用法,并包含一些基础三角函数的应用,推荐没有canvas基础的朋友阅读,熟悉的朋友能够跳过。
本人能力有限,欢迎牛人共同讨论,批评指正。javascript
canvas的API有不少,若是一一列举30分钟你是绝对看不完的,并且怎么流水帐还不如本身去看文档呢(笑),本教程的思路是用实例一步一步从无到有讲解基础用法。
canvas相关文档html
<canvas>
标签,添加canvas元素;<canvas>
标签的id,得到canvas对象;<canvas id="canvas" width="400" height="400"></canvas>
const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d');
首先咱们来画个红边黄底的箭头,使用面向对象的代码组织方式,所有代码以下。
类名为Arrow。它拥有x轴坐标、y轴坐标、底的颜色color、旋转弧度rotation四个属性。
实例方法是draw(),它须要一个context对象做为参数,就是准备工做里的context,它就至关因而画笔,这里实际上是相似依赖注入的过程,将canvas的画笔交给实例的draw()方法,实例用这个画笔去画出箭头,绘画过程见代码注释。特别注意如下几点:java
<canvas>
自己是透明的,可使用CSS给它个背景,例子中广泛使用白色背景。/** * 箭头类 * @class Representing a arrow. */ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "Arrow" }] */ class Arrow { /** * Create a arrow. */ constructor() { this.x = 0; this.y = 0; this.color = '#ffff00'; this.rotation = 0; } /** * Draw the arrow. * @param {Object} _context - The canvas context. */ draw(_context) { const context = _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.closePath(); // 填充路径包围区 context.fill(); // 绘制路径 context.stroke(); // 载入保存的笔信息 context.restore(); } }
同理咱们还能够画点其余的,好比一个圆ball.js,稍微多些参数,慢慢理解。
成品的效果能够先看这个(稍微剧透):一个会跟踪鼠标位置的箭头git
如今咱们已经掌握了画画的基本功,而且能够画箭头arrow.js和圆ball.js,然而这样只是静止画,接下来咱们须要一个循环,不断的执行擦除和重画的工做才能实现帧动画。
下面这段代码的中绘图函数drawFrame被当即执行,并递归调用自身,你将会在大部分例子中看到。
循环原理上一篇已经说明,再也不重复。这里要说明的是clearRect(),这个函数接受一个矩形坐标,也就是(x轴坐标,y轴坐标,矩形宽度,矩形高度),用于清除矩形区域内的画。
例子里直接是清除了整个画布,但这不是绝对的,刷不刷新,是局部刷新仍是所有刷新,都须要灵活处理。
这里有个不刷新的例子:鼠标画图工具github
(function drawFrame() { // 相似setTimeout的操做 window.requestAnimationFrame(drawFrame, canvas); // 将画布擦干净 context.clearRect(0, 0, canvas.width, canvas.height); // ...继续你的做画 }());
如今画面已是在不断的重绘,但为何仍是静止的呢?由于每一次刷新都没有改变要画的内容。
那咱们就给它一个目标吧,这样它才能动起来,好比就让箭头始终指向鼠标。
下面是核心代码,主要目的就是求出每帧arrow的旋转角度,这里使用的工具类mouse会实时返回鼠标的x,y轴坐标,封装原理上一篇已经讲过,根据这鼠标的坐标和arrow的坐标,便可获得鼠标的相对于arrow的距离dx和dy,以下图: canvas
而arrow的旋转角度便可以经过dx和dy使用反正切函数获得,这里须要注意几点:app
完整实例:一个会跟踪鼠标位置的箭头dom
window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const mouse = utils.captureMouse(canvas); const arrow = new Arrow(); arrow.x = canvas.width / 2; arrow.y = canvas.height / 2; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); const dx = mouse.x - arrow.x; const dy = mouse.y - arrow.y; arrow.rotation = Math.atan2(dy, dx); arrow.draw(context); }()); };
终于顺利过渡到三角函数的话题(笑)。三角函数不止有反正切一个应用,下面再看一个例子。
下面是一个ball在上下运动的核心代码,重点就是ball的y轴坐标改变,就是这句:函数
ball.y = clientY + Math.sin(angle) * range;
利用Math.sin(angle)的取值范围是-1到1,而且会随着angle增大而反复,使ball在必定范围上下运动。
完整例子:一个上下运动的球(可调参数版)工具
window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const ball = new Ball(); let angle = 0; // 运动中心 const clientY = 200; // 范围 const range = 50; // 速度 const speed = 0.05; ball.x = canvas.width / 2; ball.y = canvas.height / 2; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); ball.y = clientY + Math.sin(angle) * range; angle += speed; ball.draw(context); }()); };
只是上下运动不过瘾,那就让圆前进吧,其实就是每帧改变x轴的位置。
核心代码以下,相比前面的上下运动,多了x轴的速度,每帧移动一点就造成了波浪前进的效果。
完整实例:一个波浪运动的球
window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const ball = new Ball(); let angle = 0; const centerY = 200; const range = 50; const xspeed = 1; const yspeed = 0.05; ball.x = 0; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); ball.x += xspeed; ball.y = centerY + Math.sin(angle) * range; angle += yspeed; ball.draw(context); }()); };
其余的应用就不一一讲解,罗列出来一些: