Canvas 直线〡曲线路径
一、Canvas 元素
HTML5 <canvas>
元素用于图形的绘制,通过脚本来完成。
1、宽高设置
<canvas id="canvas" width="300" height="300"></canvas>
注意
如果不给 <canvas>
设置 width
、height
属性,则默认 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]);
参数:
x
Number:圆弧的圆心横坐标y
Number:圆弧的圆心纵坐标radius
Number:圆弧的半径startAngle
Number:圆弧开始角度,单位是弧度endAngle
Number:圆弧结束角度,单位是弧度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)
参数:
x1
Number:第 1 个控制点的横坐标y1
Number:第 1 个控制点的纵坐标x2
Number:第 2 个控制点的横坐标y2
Number:第 2 个控制点的纵坐标radius
Number:圆弧的半径大小
绘制过程:
- 连接当前位置(蓝点)和控制点 1(x1,y1)得到直线 A
- 连接控制点 1(x1,y1)和控制点 2(x2,y2)得到直线 B
- 以 radius 做为半径
- 以直线 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