让我们一起学Canvas API-CanvasRenderingContext2D(上)

256 阅读8分钟

1. 概述

Canvas API 提供了一个通过JavaScript的<canvas>元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。

Canvas API 主要聚焦于 2D 图形。而同样使用<canvas>元素的 WebGL API 则用于绘制硬件加速的 2D 和 3D 图形。

它与 SVG 图像的区别在于,<canvas>是脚本调用各种方法生成图像,SVG 则是一个 XML 文件,通过各种子元素生成图像。

使用 Canvas API 之前,需要在网页里面新建一个<canvas>元素。

<canvas id="myCanvas" width="400" height="250">
  您的浏览器不支持 Canvas
</canvas>

如果浏览器不支持这个 API,就会显示<canvas>标签中间的文字:“您的浏览器不支持 Canvas”。

每个<canvas>元素都有一个对应的CanvasRenderingContext2D对象(上下文对象)。Canvas API 就定义在这个对象上面。

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

上面代码中,<canvas>元素节点对象的getContext()方法,返回的就是CanvasRenderingContext2D对象。

注意,Canvas API 需要getContext方法指定参数2d,表示该<canvas>节点生成 2D 的平面图像。如果参数是webgl,就表示用于生成 3D 的立体图案,这部分属于 WebGL API。

2. CanvasRenderingContext2D可以绘制形状,文本,图像和其他对象。

Canvas 画布提供了一个作图的平面空间,该空间的每个点都有自己的坐标。原点(0, 0)位于图像左上角,x轴的正向是原点向右,y轴的正向是原点向下。

2.1 绘制形状

绘制矩形

以下是 3 个绘制矩形位图的方法。

  • clearRect()

    设置指定矩形区域内(以 点  (x, y)  为起点,范围是*(width, height)* )所有像素变成透明,并擦除之前绘制的所有内容。

  • fillRect()

    绘制填充矩形,矩形的起点在  (x, y)  位置,矩形的尺寸是 width 和 height

  • strokeRect()

    在 canvas 中,使用当前的笔触样式,描绘一个起点在  (x, y) 、宽度为 w、高度为 h 的矩形。

clearRect()

注:请确保在调用 clearRect()之后绘制新内容前调用beginPath()

void ctx.clearRect(x, y, width, height);

clearRect() 方法在一个矩形区域内设置所有像素都是透明的 (rgba(0,0,0,0))。这个矩形范围的左上角在 (x, y),宽度和高度分别由 width 和height确定。

参数:

x:矩形起点的x轴坐标。

y:矩形起点的y轴坐标。

width:矩形的宽度。

height:矩形的高度。

可以用该方法清除一部分画布内容。如下是清除整个画布内容。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);

也可以清除部分区域,如下:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

// 绘制黄色背景
ctx.beginPath();
ctx.fillStyle = '#ff6';
ctx.fillRect(0, 0, canvas.width, canvas.height);

// 绘制蓝色三角形
ctx.beginPath();
ctx.fillStyle = 'blue';
ctx.moveTo(20, 20);
ctx.lineTo(180, 20);
ctx.lineTo(130, 130);
ctx.closePath();
ctx.fill();

// 清除一部分画布
ctx.clearRect(10, 10, 120, 100);

被清除的区域是一个矩形,它的左上点坐标在 (10, 10),宽度和高度分别是 120 和 100 像素。 如图:

微信截图_20230510164957.png

fillRect()

Canvas 2D API 绘制填充矩形的方法。当前渲染上下文中的fillStyle 属性决定了对这个矩形对的填充样式。 这个方法是直接在画布上绘制填充,并不修改当前路径,所以在这个方法后面调用 fill() 或者stroke()方法并不会对这个方法有什么影响。

void ctx.fillRect(x, y, width, height);

fillRect()方法绘制一个填充了内容的矩形,这个矩形的开始点(左上点)在(x, y) ,它的宽度和高度分别由width 和 height 确定,填充样式由当前的fillStyle 决定。

参数:

x:矩形起点的x轴坐标。

y:矩形起点的y轴坐标。

width:矩形的宽度。

height:矩形的高度。

例子:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(20, 10, 150, 100);

以上绘制的矩形左上顶点在 (20, 10),宽高分别是 150 和 100 像素,颜色为绿色。 fillStyle属性可以为矩形填充颜色。

strokeRect()

使用当前的绘画样式,描绘一个起点在  (x, y) 、宽度为 w、高度为 h 的矩形的方法。 此方法直接绘制到画布而不修改当前路径,因此任何后续fill() 或stroke()调用对它没有影响。

void ctx.strokeRect(x, y, width, height);

参数:

x:矩形起点的x轴坐标。

y:矩形起点的y轴坐标。

width:矩形的宽度。正值在右侧,负值在左侧。

height:矩形的高度。正值在下,负值在上。

例子:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.strokeStyle = 'green';
ctx.strokeRect(20, 10, 160, 100);

矩形的左上角是(20,10)。它的宽度为 160,高度为 100。线条颜色是绿色。 strokeStyle属性可以为矩形线条添加颜色。

画矩形相关属性

  • fillStyle:图形内部的颜色和样式。默认 #000 (黑色).
  • strokeStyle:图形边线的颜色和样式。默认 #000 (黑色).

2.2 绘制文本

相关属性

以下是文本样式相关的属性。

  • font: 字体设置。默认值 10px sans-serif。字体大小和字体种类

  • textAlign:文本对齐设置。允许的值: start (默认), endleftright 或 center.

    left:文本左对齐。

    right:文本右对齐。

    center:文本居中对齐。

    start:文本对齐界线开始的地方(左对齐指本地从左向右,右对齐指本地从右向左)。

    end:文本对齐界线结束的地方(左对齐指本地从左向右,右对齐指本地从右向左)。

  • textBaseline:基线对齐设置。允许的值: tophangingmiddlealphabetic (默认), ideographicbottom.

    top:文本基线在文本块的顶部。

    hanging:文本基线是悬挂基线。

    middle:文本基线在文本块的中间。

    alphabtic:文本基线是标准的字母基线。

    ideographic:文字基线是表意字基线;如果字符本身超出了 alphabetic 基线,那么 ideograhpic 基线位置在字符本身的底部。

    bottom:文本基线在文本块的底部。与 ideographic 基线的区别在于 ideographic 基线不需要考虑下行字母。

  • direction:文本的方向。允许的值: ltrrtlinherit (默认).

    ltr:文本方向从左向右。

    rtl:文本方向从右向左。

    inherit:根据情况继承 <canvas>元素或者 Document 。

相关方法

下面是绘制文本的方法。

  • fillText():在 (x,y) 位置绘制(填充)文本。
  • strokeText():在 (x,y) 位置绘制(描边)文本。
  • measureText():会返回一个TextMetrics 对象。

fillText()

在  (x, y)  位置填充文本的方法。如果选项的第四个参数提供了最大宽度,文本会进行缩放以适应最大宽度。

void ctx.fillText(text, x, y, [maxWidth]);

参数:

text:文本内容。

x:文本起点的x轴坐标。

y:文本起点的y轴坐标。

maxWidth:绘制的最大宽度。如果指定了值,并且经过计算字符串的值比最大宽度还要宽,字体为了适应会水平缩放(如果通过水平缩放当前字体,可以进行有效的或者合理可读的处理)或者使用小号的字体。

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

ctx.font = "50px serif";
ctx.fillText("Hello world", 50, 90);

以上,font属性,可以设置当前字体样式的属性。

measureText()

返回一个关于被测量文本TextMetrics 对象包含的信息(例如它的宽度)。

ctx.measureText(text);

参数:

text:是需要测量的字符串。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;

2.3 绘制线条

线条相关的属性

  • lineWidth:线条的宽度。

  • lineCap:线末端的类型。允许的值: butt (默认), roundsquare

    butt: 线段末端以方形结束。

    round: 线段末端以圆形结束。

    square: 线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。

  • lineJoin:定义两线相交的拐点类型。允许的值:roundbevelmiter(默认)。

    round: 通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。圆角的半径是线段的宽度。

    bevel: 在相连部分的末端填充一个额外的以三角形为底的区域,每个部分都有各自独立的矩形拐角。

    miter: 通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。这个设置可以通过 miterLimit 属性看到效果。

  • miterLimit:斜接面限制比例。默认 10

  • lineDashOffset:描述在哪里开始绘制线段。

线条相关的方法

getLineDash():返回当前线段样式的数组,数组包含一组数量为偶数的非负数数字。

一个 Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。如果数组元素的数量是奇数,数组元素会被复制并重复。例如,设置线段为 [5, 15, 25] 将会得到以下返回值 [5, 15, 25, 5, 15, 25]

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

ctx.setLineDash([10, 20]);
console.log(ctx.getLineDash()); // [10, 20]

// Draw a dashed line
ctx.beginPath();
ctx.moveTo(0, 50);
ctx.lineTo(300, 50);
ctx.stroke();

以上代码,画布获得间隔20,画10的虚线。从(0,50)到(300,50)。

如下图所示:

微信截图_20230510204232.png

setLineDash(): 设置当前的线段样式。

setLineDash()  方法在填充线时使用虚线模式。它使用一组值来指定描述模式的线和间隙的交替长度。

setLineDash(segments);

参数:

segments: 一个Array数组。一组描述交替绘制线段和间距(坐标空间单位)长度的数字。如果数组元素的数量是奇数,数组的元素会被复制并重复。例如, [5, 15, 25] 会变成 [5, 15, 25, 5, 15, 25]

这方法画一些虚线很有用。