Skip to main content

Canvas 直线〡曲线路径

Canvas API 大全

一、Canvas 元素

HTML5 <canvas> 元素用于图形的绘制,通过脚本来完成。

1、宽高设置

<canvas id="canvas" width="300" height="300"></canvas>
注意

如果不给 <canvas> 设置 widthheight 属性,则默认 width 为 300、height 为 150,单位都是 px

可通过 CSS 设置宽高,但如果宽高与画布比例不一致会出现扭曲。所以一般不使用 CSS 来设置 <canvas> 的宽高。

2、getContext

getContext() 返回一个对象,该对象提供了用于在画布上绘图的方法和属性。用法如下:

const ctx = canvas.getContext(contextType, contextAttributes?);

参数说明:

  • contextType:上下文类型
    • 2d:创建一个二维渲染上下文
    • webgl:创建一个三维渲染上下文(WebGL 版本 1)
    • webgl2:创建一个三维渲染上下文(WebGL 版本 2)
    • bitmaprenderer:创建一个只提供将 canvas 内容替换为指定 ImageBitmap 功能的 ImageBitmapRenderingContext
  • contextAttributes:上下文属性,点击查看可选参数

3、beginPath

beginPath() 用于清空子路径列表开始一个新路径。

示例:

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

// First path
ctx.beginPath();
ctx.strokeStyle = 'blue';
ctx.moveTo(20,20);
ctx.lineTo(200,20);
ctx.stroke();

// Second path
ctx.beginPath();
ctx.strokeStyle = 'green';
ctx.moveTo(20,20);
ctx.lineTo(120,120);
ctx.stroke();

二、直线

  • moveTo():将画笔移动到(x,y)位置上,然后开始绘图;
  • lineTo():绘制直线到(x,y)位置;
  • stroke():绘制当前路径。

举个例子:绘制一个箭头

// HTML
<canvas id="canvas" width="200" height="150" style="border: 1px dashed gray;"></canvas>

// JS
const cvs = document.getElementById('canvas')
const ctx = cvs.getContext('2d')

ctx.moveTo(40, 60)
ctx.lineTo(100, 60)
ctx.lineTo(100, 30)
ctx.lineTo(150, 75)
ctx.lineTo(100, 120)
ctx.lineTo(100, 90)
ctx.lineTo(40, 90)
ctx.lineTo(40, 60)
ctx.stroke()

效果如下:

三、曲线

绘制曲线或圆,可选择 arc() 或者 arcTo(),通常选择 arc(),因为更可控。

1、arc

ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);

参数:

  • xNumber:圆弧的圆心横坐标
  • yNumber:圆弧的圆心纵坐标
  • radiusNumber:圆弧的半径
  • startAngleNumber:圆弧开始角度,单位是弧度
  • endAngleNumber:圆弧结束角度,单位是弧度
  • anticlockwise(可选)Boolean:弧度的绘制是按顺时针还是逆时针,默认值 false 表示顺时针绘制

弧度 = ( Math.PI / 180 ) * 角度

1-1、绘制曲线

ctx.beginPath()
ctx.arc(50, 50, 50, 0, 90 * Math.PI / 180, false)
ctx.stroke()

效果如下:

1-2、绘制关闭路径的曲线

ctx.beginPath()
ctx.arc(50, 50, 50, 0, 90 * Math.PI / 180, false)
ctx.closePath()
ctx.stroke()

效果如下:

1-3、绘制半圆 -> 全圆

// HTML
<canvas id="canvas" width="600" height="50" style="border: 1px dashed gray;"></canvas>

// JS
const cvs = document.getElementById('canvas')
const ctx = cvs.getContext('2d')

for (i = 0; i < 12; i++) {
ctx.beginPath();
const x = 25 + i * 50;
const y = 25;
const radius = 20;
const startAngle = 0;
const endAngle = (1 + (i / 12)) * Math.PI; // 从半圆到全圆

ctx.arc(x, y, radius, startAngle, endAngle);
ctx.fill();
}

效果如下:

2、arcTo

ctx.arcTo(x1, y1, x2, y2, radius)

参数:

  • x1Number:第 1 个控制点的横坐标
  • y1Number:第 1 个控制点的纵坐标
  • x2Number:第 2 个控制点的横坐标
  • y2Number:第 2 个控制点的纵坐标
  • radiusNumber:圆弧的半径大小

绘制过程:

  1. 连接当前位置(蓝点)和控制点 1(x1,y1)得到直线 A
  2. 连接控制点 1(x1,y1)和控制点 2(x2,y2)得到直线 B
  3. 以 radius 做为半径
  4. 以直线 A 和直线 B 作为切线,画出两条切线之间的弧线路径

四、贝塞尔曲线

1、二次贝塞尔曲线

quadraticCurveTo(cp1x, cp1y, x, y)

绘制二次贝塞尔曲线,当前位置为开始点(蓝点),(cp1x, cp1y) 为一个控制点(红点),(x,y) 为结束点(蓝点)

示例-渲染对话气泡:

ctx.beginPath();
ctx.moveTo(75, 25);
ctx.quadraticCurveTo(25, 25, 25, 62.5);
ctx.quadraticCurveTo(25, 100, 50, 100);
ctx.quadraticCurveTo(50, 120, 30, 125);
ctx.quadraticCurveTo(60, 120, 65, 100);
ctx.quadraticCurveTo(125, 100, 125, 62.5);
ctx.quadraticCurveTo(125, 25, 75, 25);
ctx.stroke();

效果如下:

点击打开二次贝塞尔曲线调试器

2、三次贝塞尔曲线

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

绘制三次贝塞尔曲线,当前位置为开始点(蓝点),(cp1x,cp1y) 为控制点 1(红点),(cp2x,cp2y) 为控制点 2(红点),(x,y) 为结束点(蓝点)

示例-心形:

ctx.beginPath();
ctx.moveTo(75, 40);
ctx.bezierCurveTo(75, 37, 70, 25, 50, 25);
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
ctx.bezierCurveTo(20, 80, 40, 102, 75, 120);
ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5);
ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25);
ctx.bezierCurveTo(85, 25, 75, 37, 75, 40);
ctx.fill();

效果如下:

点击打开三次贝塞尔曲线调试器

五、路径创建及拷贝

Path2D 可用于缓存或记录绘画命令,常用于路径复用。

示例:

// HTML
<canvas id="canvas" width="200" height="150" style="border: 1px dashed gray;"></canvas>

// JS
const cvs = document.getElementById('canvas')
const ctx = cvs.getContext('2d')

const path1 = new Path2D()
path1.rect(10, 10, 60, 60)

const path2 = new Path2D(path1)
path2.arc(50, 50, 50, 0, 90 * Math.PI / 180, false)

ctx.stroke(path2)

效果如下:

除此之外,Path2D API 还可以使用 SVG path,这意味着可以将 SVG 搬上 Canvas。举个例子,使用 SVG path 绘制矩形:

// 移动到点 (M10 10)
// 向右侧水平移动 80 个点 (h 80)
// 向下 80 个点 (v 80)
// 向左 80 个点 (h -80)
// 回到起始点 (z)
const path = new Path2D("M10 10 h 80 v 80 h -80 Z");
ctx.fill(path);

六、状态的存储和恢复

ctx.save() 用于保存当前 Canvas 画布状态并放在栈的最上面,可以使用 ctx.restore() 方法依次取出。

示例:

// 保存初始 Canvas 状态
ctx.save()
ctx.fillStyle = 'aquamarine'
ctx.fillRect(20, 20, 60, 60)

// 恢复保存的 Canvas 状态
ctx.restore()
ctx.fillRect(120, 20, 60, 60)

效果如下:

注意绘制效果不会被存储,例如:
  • transform()
  • clip()
  • setLineDash()
  • strokeStyle
  • fillStyle
  • globalAlpha
  • lineWidth
  • lineCap
  • lineJoin
  • miterLimit
  • lineDashOffset
  • shadowOffsetX
  • shadowOffsetY
  • shadowBlur
  • shadowColor
  • globalCompositeOperation
  • font
  • textAlign
  • textBaseline