canvas 基本使用 原创
canvas
-
基本用法
<canvas width="300" height="300"></canvas>
canvas
看起来和img
元素非常相似,唯一不同的就是它没有src
和alt
属性,实际上canvas
标签上只width
和height
这两个可选属性(没有设置两个属性时,画布默认是 300 * 150 的大小)。如果使用css
定义大小,绘制图形时会自适应它的框架尺寸(当css
尺寸与原始画布不一致时,会出现扭曲,导致绘制的图形模糊)。与
img
标签不同的时,canvas
元素需要结束标签</canvas>
。如果结束标签不存在,则文档的其余部分会被认为是替代内容,将不会显示出来。 -
绘制基本形状
栅格
在我们开始画图之前,我们需要了解一下画布栅格(canvas grid)以及坐标空间。上一页中的HTML模板中有个宽 300 像素, 高 300 像素的
canvas
元素。如右图所示,canvas
元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas
元素中的一像素。栅格的起点为左上角(0, 0)。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(X轴)x 像素,距离上边(Y轴)y 像素矩形
const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') // 绘制一个填充的矩形 fillRect(x, y, width, height) // x: 矩形起始点的 x 轴坐标,y: 矩形起始点的 y 轴坐标。 // width: 矩形的宽度, height: 矩形的高度。 ctx.fillRect(0, 0, 100, 100) ctx.fill() // 绘制一个矩形的边框 strokeRect(x, y, width, height),参数说明同上 ctx.strokeRect(200, 200, 100, 100) ctx.stroke() // 绘制一个矩形的边框 rect(x, y, width, height),参数说明同上 ctx.beginPath() ctx.rect(100, 100, 50, 50) ctx.stroke() // 绘制一个矩形的边框 ctx.beginPath() ctx.rect(150, 150, 50, 50) ctx.fill()
例子输出如下图所示
路径
图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。一个路径,甚至一个子路径,都是闭合的。使用路径绘制图形需要一些额外的步骤:
- 创建路径起始点
beginPath()
- 使用画图命令去画出路径
moveTo()
或者lineTo
… - 路径封闭
closePath()
- 通过描边或填充路径区域来渲染图形
stroke()
或者fill()
const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') // beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。 ctx.beginPath() // moveTo(x, y) 将一个新的子路径的起始点移动到(x,y)坐标 ctx.moveTo(0, 0) // lineTo(x, y) 使用直线连接子路径的终点到x,y坐标 ctx.lineTo(300, 300) // stroke() 根据当前的画线样式,绘制当前或已经存在的路径的方法 ctx.stroke() // closePath() 从当前点到起始点绘制一条直线, //如果图形已经是封闭的或者只有一个点,那么此方法不会做任何操作。 ctx.closePath()
例子输出如下图所示
绘制三角形
const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') // 绘制一个填充的三角形 // fill() 填充当前或已存在的路径,带参数的不做介绍 // 当使用 fill() 时,图形会自动闭合路径,所以不需要 closePath 闭合 ctx.beginPath() ctx.moveTo(0, 0) ctx.lineTo(300, 75) ctx.lineTo(0, 150) ctx.fill() // 绘制一个三角形边框 ctx.beginPath() ctx.moveTo(0, 150) ctx.lineTo(300, 225) ctx.lineTo(0,300) // stroke() 不会自动闭合路径, 需要 closePath 闭合 ctx.closePath() ctx.stroke()
例子输出如下图所示
圆弧
绘制圆弧或者圆,我们使用
arc()
方法。当然可以使用arcTo()
,不过这个的实现并不是那么的可靠,所以我们这里不作介绍。const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') // arc(x, y, radius, startAngle, endAngle, anticlockwise), // 圆弧路径的圆心在 (x, y) 位置,半径为 r ,根据anticlockwise (默认为顺时针) // 指定的方向从 startAngle 开始绘制,到 endAngle 结束。 // 绘制圆弧 0 - 90° 顺时针, // anticlockwise 可选,可选的Boolean值 ,如果为 true,逆时针绘制圆弧,反之,顺时针绘制 // strokeStyle 绘制图形颜色或者样式的 ctx.beginPath() ctx.arc(150, 150, 50, 0 ,Math.PI / 2 ) ctx.strokeStyle = "red" ctx.stroke() // 绘制圆弧 0 - 90° 逆时针 ctx.beginPath() ctx.arc(150, 150, 70, 0 ,Math.PI / 2, true ) ctx.strokeStyle = "yellow" ctx.stroke() // 绘制圆 ctx.beginPath() ctx.arc(150, 150, 100, 0 , Math.PI * 2) ctx.strokeStyle = "#3498db" ctx.stroke()
例子输出如下图所示
二次贝塞尔曲线及三次贝塞尔曲线
二次贝塞尔曲线 ,
quadraticCurveTo(cp1x,cp1y,x,y)
, 其中参数cp1x
和cp1y
是控制点的坐标,x 和 y 是终点坐标 三次贝塞尔曲线,
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
,其中参数cp1x,cp1y
为控制点一,cp2x, cp2y
为控制点二,x, y
为结束点。
- 创建路径起始点
const canvas = document.querySelector('.canvas')
const ctx = canvas.getContext('2d')
// 绘制一个矩形边框
ctx.strokeRect(0, 0, 300, 300)
// 控制点 1 (200, 30)
ctx.beginPath()
ctx.arc(200, 30, 5, 0, Math.PI * 2)
ctx.fill()
// 控制点 2 (30, 200)
ctx.beginPath()
ctx.arc(30, 200, 5, 0, Math.PI * 2)
ctx.fill()
ctx.beginPath()
ctx.moveTo(30, 200)
ctx.quadraticCurveTo(30, 30, 200, 30)
ctx.stroke()
// 控制点 1 (20, 260)
ctx.beginPath()
ctx.arc(20, 260, 5, 0, Math.PI * 2)
ctx.fillStyle = "red"
ctx.fill()
// 控制点 2 (200, 260)
ctx.beginPath()
ctx.arc(200, 260, 5, 0, Math.PI * 2)
ctx.fillStyle = "red"
ctx.fill()
ctx.beginPath()
ctx.moveTo(20, 180)
ctx.bezierCurveTo(20, 260, 200, 260, 200, 180)
ctx.strokeStyle = "red"
ctx.stroke()
例子输出如下图所示
-
颜色和样式
色彩 Colors
到目前为止,我们只看到过绘制内容的方法。如果我们想要给图形上色,有两个重要的属性可以做到:
fillStyle
和strokeStyle
。 一旦设置了
strokeStyle
或者fillStyle
的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置fillStyle
或strokeStyle
的值。
color
可以是表示css
颜色值的字符串,渐变对象或者图案对象。我们迟些再回头探讨渐变和图案对象。默认情况下,线条和填充颜色都是黑色(CSS
颜色值#000000
)。const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') // fillStyle = color 设置图形的填充颜色 // strokeStyle = color 设置图形轮廓的颜色 // 这些 fillStyle 的值均为 '橙色' // ctx.fillStyle = "orange"; // ctx.fillStyle = "#ffa500"; // ctx.fillStyle = "rgb(255,165,0)"; // ctx.fillStyle = "rgba(255,165,0,1)"; const rectArray = new Array(10).fill(0) // 绘制 10 * 10 个矩形 rectArray.forEach((row, rowIndex) => { rectArray.forEach((col, colIndex) => { ctx.fillStyle = `rgb(${255 - 42 * rowIndex},${255 - 42 * colIndex}, 0 )` ctx.fillRect(rowIndex * 30, colIndex * 30, 30, 30) ctx.fill() }) })
例子输出如下图所示
线型
可以通过一系列属性来设置线的样式。常用几个属性 :
-
设置线条宽度 :
lineWidth = value
,value
描述线段宽度的数字。 0、 负数、Infinity和
NaN
会被忽略 -
设置线条末端样式 :
lineCap = type
, 可取值 : -
butt
: 线段末端以方形结束 -
round
: 线段末端以圆形结束 -
``square` : 线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域
-
设定线条与线条间接合处的样式 :
lineJoin = type
,可取值(这里不做演示) :bevel
: 通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度round
: 在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角miter
: 通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。这个设置可以通过miterLimit
属性看到效果。
const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') const lineCapArray = [ { type: 'butt', width: 10, color: 'red' }, { type: 'round', width: 10, color: 'black' }, { type: 'square', width: 10, color: 'blue' } ] // 绘制基线 ctx.strokeStyle = '#2ecc71' ctx.lineWidth = 2 ctx.beginPath() ctx.moveTo(50, 0) ctx.lineTo(50, 250) ctx.stroke() ctx.beginPath() ctx.moveTo(250, 0) ctx.lineTo(250, 250) ctx.stroke() lineCapArray.forEach(({ type, width, color }, index) => { ctx.beginPath() ctx.moveTo(50, (index + 1) * 50) ctx.lineTo(250, (index + 1) * 50) ctx.lineWidth = width ctx.lineCap = type ctx.strokeStyle = color ctx.stroke() })
例子输出如下图所示
渐变颜色
就好像一般的绘图软件一样,我们可以用线性或者径向的渐变来填充或描边。我们用下面的方法新建一个
canvasGradient
对象,并且赋给图形的fillStyle
或strokeStyle
属性。创建出canvasGradient
对象后,我们就可以用addColorStop
方法给它上色了。 线性渐变 :
createLinearGradient(x1, y1, x2, y2)
, 此方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。 线性渐变 :
createRadialGradient(x1, y1, r1, x2, y2, r2)
, 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。const canvas = document.querySelector('.canvas') const ctx = canvas.getContext('2d') const lGradient = ctx.createLinearGradient(0, 0, 100, 100) lGradient.addColorStop(0, 'red') lGradient.addColorStop(1, 'blue') const rGradient = ctx.createRadialGradient(250, 250, 20, 250, 250, 30) rGradient.addColorStop(0, 'red') rGradient.addColorStop(1, 'blue') ctx.fillStyle = lGradient ctx.fillRect(0, 0, 100, 100) ctx.fillStyle = rGradient ctx.fillRect(200, 200, 100, 100)
例子输出如下图所示
-
-
绘制文本
在指定的位置填充指定的文本,绘制的最大宽度是可选的。
fillText(text, x, y [, maxWidth])
在指定的位置填充指定的文本边框,绘制的最大宽度是可选的。strokeText(text, x, y [, maxWidth])
const canvas = document.querySelector('.canvas')
const ctx = canvas.getContext('2d')
// 符合CSS font 语法的DOMString 字符串。默认字体是 10px sans-serif
ctx.font = '50px 宋体'
// 描述绘制文本时,文本的对齐方式的属性
// ctx.textAlign = "left" || "right" || "center" || "start" || "end";
ctx.textAlign = 'center'
// ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom"
// 绘制文本时,当前文本基线的属性
ctx.textBaseline = 'middle'
// ctx.direction = "ltr" || "rtl" || "inherit"
// 制文本时,描述当前文本方向的属性
// ctx.direction = "ltr"
ctx.fillText('fill', 150, 100)
ctx.strokeText('stroke', 150, 200)
例子输出如下图所示
常用画布 赞一个~
可以,快速入门 canvas 不错!
学到了