JavaScript canvas

本文将介绍 canvas ,用于在 HTML 中绘图的标签。

一、什么是 canvas?

canvas 可以在网页上绘制图像、制作简单的动画、甚至进行实时视频处理和渲染。

HTML5 中新增了 canvas 标签,该标签用于定义图形容器。定义容器后使用 JavaScript 在容器之中绘制图像。

二、初始化 canvas

1
2
3
4
5
6
7
8
// 定义容器
<canvas id="myCanvas"></canvas>

// 找到容器
var canvas = document.getElementById('myCanvas');

// 创建context对象
var cx = canvas.getContext("2d");

三、canvas 标签

canvas 标签有两个可选属性:width、height,用于为 canvas 容器设置高度和宽度。

1
<canvas id="myCanvas" width="300" height="300"></canvas>

如果不给 canvas 设置 width 和 height,则默认 width 为 300,height 为 150。

此外,也可以通过 CSS 设置容器的高度和宽度。

需注意:

  • 标签中的 width 和 height 是画布的实际尺寸
  • CSS 中的 width 和 height 是画布在页面上放置的尺寸

因此,

如果标签中的尺寸更大,则画布会进行压缩;

如果 CSS 中的尺寸更大,则画面会进行拉伸。

非必要时,不必设置 CSS 尺寸。如果设置,应该使两对 width 和 height 的比例相等,防止出现拉伸/压缩变形。

四、常用命令

1. beginPath()

表明要开始一个新的路径,用于和之前绘制的路径相分隔。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 开始路径
context.beginPath();
context.strokeStyle = 'blue';
context.moveTo(60, 20);
context.lineTo(220, 20);
context.stroke();
// 开始路径 again
context.beginPath();
context.strokeStyle = 'green';
context.moveTo(60, 20);
context.lineTo(160, 120);
context.stroke();
// 登录状态下不会出现这行文字,点击页面右上角一键登录

执行了 2 次 beginPath(),实时效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
// 开始路径
context.beginPath();
context.strokeStyle = 'blue';
context.moveTo(60, 20);
context.lineTo(220, 20);
context.stroke();

context.strokeStyle = 'green';
context.moveTo(60, 20);
context.lineTo(160, 120);
context.stroke();
// 登录状态下不会出现这行文字,点击页面右上角一键登录

执行了 1 次 beginPath(),实时效果如下:

只要是非连续路径绘制,都应该在绘制新路径时调用 beginPath() 。

2. moveTo(x, y)

移动路径绘制的起始点至指定位置,即移动绘制起始点

3. lineTo(x, y)

用于绘制直线,表示从绘制起始点移动至指定点。

4. arc()

用于绘制圆弧。

5. rect()

用于绘制矩形。

6. fillText(text, x, y)

用于以填充方式绘制文本。

7. strokeText(text, x, y)

用于以描边方式绘制文本。

8. drawImage()

用于绘制图像。

9. fill()

用于对路径进行填充。

10. stroke()

用于对路径进行描边。

11. closePath()

用于闭合路径,会将路径的最后位置与起始位置用直线相连。

四、绘制

1. 画线

1
2
3
4
cxt.moveTo(10,10);
cxt.lineTo(150,50);
cxt.lineTo(10,50);
cxt.stroke();

2. 画圆

1
2
3
4
5
cxt.fillStyle="#FF0000";
cxt.beginPath();
cxt.arc(70,18,15,0,Math.PI*2,true);
cxt.closePath();
cxt.fill();

3. 画图像

(1) 创建图片并绘制

1
2
3
var img = new Image()
img.src = "URL"
ctx.drawImage(img, 10, 10);

(2) 将已有图片放置到画布之上

1
2
3
4
5
<img id="scream"src="URL" alt="">
<canvas id="myCanvas"></canvas>


ctx.drawImage(document.getElementById("scream"), 10, 10);

五、 canvas 模糊问题

1. 问题

小屏幕设备和高分辨率屏幕往往会对屏幕进行缩放,这意味着浏览器会将多个像素渲染为一个像素。假设缩放比例为 1.5,则屏幕中的 1 个像素点将由 1.5 个像素点渲染而成,在浏览器进行渲染时,它会拿到 1.5 倍大小的元素,缩放至 1 倍后显示在屏幕上。但 canvas 在绘制时并不会因缩放比例而进行放大绘制(放大以便之后的缩放),而是严格按照标签的尺寸进行绘制,又因为 canvas 并不是矢量图,因此会在缩放中产生模糊。

2. 解决方法

有一个简单粗暴的解决方式:检测设备的像素比,并绘制对应倍数比例的 canvas 元素。如此一来,canvas 元素便可以被缩放而不产生模糊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 将画布显示尺寸赋给css样式
<canvas id="myCanvas" style="width: 宽度;height: 高度"></canvas>

// 初始化 canvas
this.canvas = document.getElementById('canvas')
this.ctx = this.canvas.getContext('2d')
// 获取渲染比例
this.backingStore = this.ctx.backingStorePixelRatio
|| this.ctx.webkitBackingStorePixelRatio
|| this.ctx.mozBackingStorePixelRatio
|| this.ctx.msBackingStorePixelRatio
|| this.ctx.oBackingStorePixelRatio
|| this.ctx.backingStorePixelRatio
|| 1
this.ratio = (window.devicePixelRatio || 1) / backingStore
// 计算画布实际尺寸,并赋给元素
this.canvas.width = 宽度 * this.ratio
this.canvas.height = 高度 * this.ratio
// 将canvas绘制中的尺寸都乘以对应倍率
尺寸 * this.ratio

六、 vue 中使用 canvas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div>
<canvas id="canvas">
your browser does not support the canvas tag
</canvas>
</div>
</template>

<script>
export default {
name: '',
data() {
return {
// canvas
canvas: '',
// 用于在画布上绘图的环境
ctx: {},
}
},
mounted() {
// 初始化canvas
this.canvas = document.getElementById('canvas')
this.ctx = this.canvas.getContext('2d')
}
</script>

<style scoped>
</style>

参考