04 Canvas 基础用法

基础用法

属性介绍

<canvas> 标签只有两个可选的属性 widthheight。当没有设置宽度和高度的时候,canvas 会初始化宽度为 300 像素和高度为 150 像素。宽高属性会自动忽略单位,以像素展示,所以使用 em 或 rem 等单位无效。

在视觉表现上,CSS 的宽高属性权重要高于 <canvas> 标签的宽高权重。可以将 <canvas> 看作 <img> 元素,主要区别是 <canvas> 的等比例特性是强制的,会忽略 HTML 属性的设置,但 <img> 不会。

<img src="1.jpg" width="300" height="150" style="height:100px;" />
<canvas width="300" height="150" style="height:100px;"></canvas>

如上代码所示,此时 <img> 宽度不会随高度缩放,最终以 300x100 尺寸显示,而 <canvas> 宽度会按高度等比例缩放,以 200x100 尺寸显示。

需要注意:在使用 Canvas API 绘制图像时,是以 HTML 的宽高属性为原点,与 CSS 属性无关。

可以在 <canvas> 标签中提供替换内容。不支持的浏览器将会忽略容器并在其中渲染后备内容。

<canvas width="150" height="150">
  你的浏览器不支持 canvas,请升级你的浏览器
</canvas>

渲染上下文

<canvas> 标签创建画布,并公开渲染上下文(The rendering context),用来绘制内容。使用方法 getContext() 可以获取渲染上下文对象,该方法接受一个参数表示上下文格式,一般传入 2d,当然还有 3d 模式,这里不细谈。

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

绘制图形

绘制矩形

原生 canvas 只支持一种图形绘制:矩形。所有其他的图形的绘制都至少需要生成一条路径。canvas 提供了三种方法绘制矩形:

  • fillRect(x, y, width, height): 绘制一个填充矩形

  • strokeRect(x, y, width, height): 绘制一个矩形边框

  • clearRect(x, y, width, height): 清除指定矩形区域,使之变透明

三种方式示例如下:

ctx.fillStyle = "#fb618d"
ctx.fillRect(50, 50, 200, 200)
ctx.clearRect(70, 70, 160, 160)
ctx.strokeRect(90, 90, 120, 120)

绘制路径

图形的基本元素是路径,使用路径绘制图形的步骤如下:

  1. 创建路径起始点

  2. 画出路径

  3. 将路径封闭

  4. 描边或填充路径区域

整个步骤需要使用一下函数:

  1. beginPath():新建一条新路径

  2. closePath():闭合路径

  3. stroke():通过线条来绘制图形轮廓

  4. fill():通过填充路径的内容区域生成实心图形

  5. moveTo(x, y):移动笔触到指定坐标

  6. lineTo(x, y):绘制一条从当前位置到指定坐标的直线

  7. arc(x, y, radius, startAngle, endAngle, anticlockwise):绘制圆弧,anticlockwise 为 true 时逆时针,默认为顺时针。

当 canvas 初始化或者 beginPath() 调用后,通常会使用 moveTo() 函数设置起点。或者使用该方法绘制不连续的路径。

示例 1:绘制三角形

// 填充三角形
ctx.beginPath()
ctx.moveTo(40, 40)
ctx.lineTo(220, 40)
ctx.lineTo(40, 220)
ctx.fill()

// 描边三角形
ctx.beginPath()
ctx.moveTo(260, 260)
ctx.lineTo(260, 80)
ctx.lineTo(80, 260)
ctx.closePath()
ctx.stroke()

注意到填充三角形和描边三角形有些不同,当路径使用填充 fill() 时会自动闭合,而使用描边 stroke() 时则不会闭合路径,所以需要调用 closePath() 方法。

示例 2:绘制笑脸

ctx.beginPath()
ctx.moveTo(260, 150)
ctx.arc(150, 150, 110, 0, Math.PI * 2, true) // 脸
ctx.moveTo(220, 150)
ctx.arc(150, 150, 70, 0, Math.PI, false) // 嘴
ctx.moveTo(120, 110)
ctx.arc(110, 110, 10, 0, Math.PI * 2, false) // 左眼
ctx.moveTo(200, 110)
ctx.arc(190, 110, 10, 0, Math.PI * 2, false) // 右眼
ctx.stroke()

贝塞尔曲线

canvas 里使用二次贝塞尔曲线和三次贝塞尔曲线可以用来绘制复杂的图形。

canvas API quadraticCurveTo(cp1x, cp1y, x, y),用来绘制二次贝塞尔曲线,cp1x,cp1y 为控制点,x,y 为结束点。

canvas API bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y),用来绘制三次贝塞尔曲线,cp1x,cp1y 为控制点一,cp2x,cp2y 为控制点二,x,y 为结束点。

关于贝塞尔曲线的使用,这里不再细研究~~(看得头痛)~~,下次如有机会再说。

Path2D

之前所介绍的 canvas API 都是使用路径和绘画命令来把对象“画”在画布上,不能复用命令。较新的浏览器支持 Path2D 对象,用来缓存或记录绘画命令,这样可以复用路径,简化代码和优化性能。

Path2D() 会返回一个新初始化的 Path2D 对象,可能将某一个路径作为变量——创建一个它的副本,或者将一个包含 SVG path 数据的字符串作为变量。

new Path2D() // 空的Path对象
new Path2D(path) // 克隆Path对象
new Path2D("M10 10 h 80 v 80 h -80 Z") // 从SVG建立Path对象

之前介绍的所有 canvas API 都可以在生成的 Path2D 对象上使用。

const rectangle = new Path2D()
rectangle.rect(10, 10, 50, 50)

const circle = new Path2D()
circle.moveTo(125, 35)
circle.arc(100, 35, 25, 0, 2 * Math.PI)

ctx.stroke(rectangle)
ctx.fill(circle)

最后更新于