Canvas API 提供了经过 JavaScript 绘制图形的能力 。它普遍用于动画、游戏图形、数据可视化、照片处理和实时视频处理领域。本文将会简单介绍下 canvas 。文章的大部份内容来源于 MDN 的 canvas 教程,想深刻了解 canvas 的能够去看一下。javascript
// 栗子 1
<canvas id="tutorial" width="150" height="150"></canvas>
复制代码
这就是一个 canvas 标签,看起来和普通的 html 标签没什么不一样,重要的经过 canvas 标签咱们能够获取其渲染上下文,canvas 的全部API都经过这个渲染上下文暴露出来,如下讲解的 API 也都基于此上下文。html
canvas 翻译过来是画布的意思,因此接下来咱们会对照画布来介绍 canvas 的API。java
var canvas = document.getElementById("tutorial");
var ctx = canvas.getContext("2d");
复制代码
canvas 坐标系统中,元素的左上角为坐标原点,向右下延伸坐标轴,全部图形相对于原点绘制,默认 1 网格单位对应 1 像素,好比栗子1 中的 canvas 元素就造成一个 150X150 的坐标系。 上图中的矩形坐标即为 (x, y)。
和 svg 不一样,canvas 只提供了一种基本图形:矩形,不过借助路径咱们能够绘制想要的任意图形。 git
canvas 提供了三种矩形 API,咱们能够经过渲染上下文获取到它们。全部 API 接受四个参数: x, y, width, height。github
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.fillRect(25, 25, 100, 100);
ctx.clearRect(45, 45, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
}
}
复制代码
fillRect 和 strokeRect 分别会 “填充” 和 “描边“ 一片矩形区域。调用它们会当即绘制到画布上。
clearRect 会像橡皮擦同样清除特定的矩形区域。
结果如图:编程
路径由一系列的点组成,经过路径的组合咱们能够绘制须要的任何图形。绘制一条路径步骤以下:canvas
beginPath
建立路径,并建立一个路径缓存区,当前坐标为起点。closePath
会在当前坐标和起点连起一条直线(可选), 最后能够 填充 或 描边 路径。这个绘制步骤和画画差很少,落笔、描边到填充和真实世界的心智模型是相同的。其中的重头戏就是步骤2的绘制命令:lineTo
、 arc
、[bezierCurveTo()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/bezierCurveTo)
等命令分别绘制直线、弧线和贝塞尔曲线路径。而 moveTo
命令接受 x、y 两个参数,调用其会将画笔移动到指定的 x,y 坐标。
好比这里有个稍微复杂的栗子,绘制一个吃豆人。缓存
在吃豆人的栗子里,咱们反复调用 roundedRect
函数来生成圆角矩形, canvas 提供了路径复用的方法,这就是 Path2D,经过 Path2d 咱们能够建立路径对象,调用绘制命令、甚至合并两个路径对象。以吃豆人中的圆角矩形函数为栗,使用Path2D 后的代码:dom
// A utility function to draw a rectangle with rounded corners.
function roundedRect(ctx, x, y, width, height, radius) {
const path = new Path2D();
path.moveTo(x, y + radius);
path.lineTo(x, y + height - radius);
path.arcTo(x, y + height, x + radius, y + height, radius);
path.lineTo(x + width - radius, y + height);
path.arcTo(x + width, y + height, x + width, y + height - radius, radius);
path.lineTo(x + width, y + radius);
path.arcTo(x + width, y, x + width - radius, y, radius);
path.lineTo(x + radius, y);
path.arcTo(x, y, x, y + radius, radius);
ctx.stroke(path);
}
复制代码
canvas 经过状态机来保持 画笔 和 画布的状态,咱们能够经过 API 来改变画笔的状态来绘制不一样样式的图形。好比经过 fillStyle 和 strokeStyle 改变填充和描边的样式,经过 lineWidth 改变画笔的尺寸等。经过 createLinearGradient
、[createPattern(image, type)](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern)
来绘制渐变色和图片背景,这里再也不赘述。svg
canvas 动画的限制在于:图形绘制结束后没法再更改图形的状态(尺寸、颜色、坐标等)。这和咱们熟悉的 html 元素不同,dom 元素在渲染后还能够进行作位移、缩放等动画。因为以上缘由,在 canvas 中作动画须要遵循如下步骤:
这里有一个时钟动画的栗子,咱们将不一样的图形封装为对象,绘制图形时只须要调用对象的 draw
方法,这样统一了编程模型。
class Hour {
constructor(ctx) {
this.ctx = ctx;
}
draw() {
this.ctx.lineWidth = 14;
this.ctx.beginPath();
this.ctx.moveTo(-20, 0);
this.ctx.lineTo(80, 0);
this.ctx.stroke();
}
}
复制代码
绘制的每一帧咱们会不断更新画布的状态,为了避免污染下一帧的画布状态,咱们须要不断调用 save
和 restore
来保存和回退画布状态。
这一章简单介绍了 canvas的基本知识,下篇文章会涉及 canvas 内的事件处理、碰撞检测等内容,并利用这些实现一些炫酷的效果,敬请期待。
本人正在编写数据可视化之路系列文章,输出一些可视化方面的教程和经验,你能够经过如下途径阅读它们。