Canvas的基本用法

canvas系列

canvas元素

  • 当不使用元素属性设置canvas的宽高时,默认初始化宽度300px和高度150px
  • 可以通过css定义canvas的大小,但css指定的尺寸和canvas初始比例不一致时,会出现扭曲,因此建议始终通过width和height属性来指定canvas大小
1
2
3
<canvas id="demo" width="300" height="150">
您使用的浏览器不支持canvas,请升级浏览器
</canvas>

获取渲染上下文

  • canvas元素创造了一个固定大小的画布
  • 并提供了一个渲染上下文,用来绘制或处理需要展示的内容
  • 如何获取渲染上下文
1
2
let demo = document.getElementById('demo')
let ctx = demo.getContext('2d')
  • 检查浏览器支持情况
1
2
3
4
if(demo.getContext){
ctx = demo.getContext('2d')
}else{
}

绘制图形

  • 坐标原点:左上角
  • X轴向右为正方向
  • Y轴向下为正方向

矩形

canvas唯一支持的不通过路径进行绘制的图形

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

绘制填充的矩形

  • x: x轴坐标
  • y: y轴坐标
  • width: 矩形的宽度
  • height: 矩形的高度
1
2
ctx.fillStyle = 'green'
ctx.fillRect(10, 10, 100, 100) // 在坐标(0, 0)的位置开始绘制一个宽高都是100px的矩形

矩形

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

绘制一个矩形的边框

  • 参数同fillRect()
1
2
ctx.strokeStyle = 'blue'
ctx.strokeRect(10, 10, 100, 100) // 为前面绘制的矩形用蓝色进行描边

xx

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

清除指定矩形区域,让清楚的部分完全透明

  • 参数同fillRect()
1
ctx.clearRect(15, 15, 90, 90)

xx

路径

图形的基本元素是路径
创建路径需要如下步骤

  • 创建路径的起点
  • 使用画图命令画出路径
  • 把路径封闭(非必需)
  • 通过路径来渲染图形
ctx.beginPath()

开始绘制路径

ctx.moveTo(x, y)

将🖌️移动到指定的坐标点
准备开始绘制路径
可以在绘制路径过程中不断执行此方法,从而绘制出不连续的路径

1
2
3
4
5
6
7
8
9
10
ctx.beginPath()
ctx.arc(75, 75, 50, 0, Math.PI * 2, true) // arc方法请往下看
ctx.moveTo(110, 75)
ctx.arc(75, 75, 35, 0, Math.PI, false)
ctx.moveTo(65, 65)
ctx.arc(60, 65, 5, 0, Math.PI * 2, true)
ctx.moveTo(95, 65)
ctx.arc(90, 65, 5, 0, Math.PI * 2, true)
ctx.strokeStyle = 'green'
ctx.stroke()

xx

ctx.lineTo(x, y)

绘制一条从当前位置到指定坐标点的直线

  • x, y: 结束位置的坐标点
1
2
3
4
5
6
7
8
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(110, 110)
ctx.lineTo(110, 10)
ctx.closePath()
ctx.fillStyle = 'red'
ctx.fill()
ctx.stroke()

xx

ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise)
  • x, y: 圆弧的圆心的坐标
  • radius: 圆弧的半径
  • startAngle: 从startAngle的弧度开始,以x轴为基准
  • endAngle: 到endAngle的弧度结束,以x轴为基准
  • anticlockwise: 绘制的方向,默认顺时针。true 逆时针false 顺时针
1
2
3
4
5
6
7
8
9
10
11
12
13
for(let i = 0; i < 6; i++){
for(let j = 0; j < 6; j++){
let raduis = 10
let x = (raduis + 2) * (j + 1) * 2
let y = (raduis + 2) * (i + 1) * 2
let startAngle = 0
let endAngle = (Math.PI / 180) * (i + 1) * (j + 1) * 10
ctx.beginPath()
ctx.arc(x, y, raduis, startAngle, endAngle)
ctx.strokeStyle = 'green'
ctx.stroke()
}
}

xx

ctx.quadraticCurveTo(cp1x, cp1y, x, y)
  • 从当前位置开始绘制二次贝赛尔曲线
  • cp1x, cp1y: 控制点的坐标
  • x, y: 结束点的坐标
1
2
3
4
ctx.moveTo(50, 50)
ctx.quadraticCurveTo(0, 30, 50, 100)
ctx.quadraticCurveTo(100, 30, 50, 50)
ctx.fill()

xx

ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
  • 绘制三次贝赛尔曲线
  • 三次贝赛尔曲线有两个控制点(cp1x, cp1y)/(cp2x, cp2y)
ctx.rect(x, y, width, height)
  • 绘制一条矩形的路径
  • 和fillRect和strokeRect的区别是: rect画的仅仅是一条路径,没有渲染!!!
  • 绘制圆角矩形
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function roundedRect(ctx, x, y, width, height, radius){
ctx.beginPath()
ctx.moveTo(x, y + radius)
ctx.lineTo(x, y + height - radius)
ctx.quadraticCurveTo(x, y + height, x + radius, y + height)
ctx.lineTo(x + width - radius, y + height)
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius)
ctx.lineTo(x + width, y + radius)
ctx.quadraticCurveTo(x + width, y, x + width - radius, y)
ctx.lineTo(x + radius, y)
ctx.quadraticCurveTo(x, y, x, y + radius)
ctx.stroke()
}
roundedRect(ctx, 10, 10, 100, 100, 10)

xx

ctx.path2D()

用于缓存或记录绘画命令
方便快速的回顾路径
所有的路径方法都可以在path2D的实例中使用

1
2
3
4
5
6
7
8
9
let rectangle = new Path2D()
rectangle.rect(10, 10, 50, 50)
let circle = new Path2D()
circle.moveTo(125, 35)
circle.arc(100, 35, 25, 0, 2 * Math.PI)
ctx.stroke(rectangle)
ctx.fill(circle)

xx

样式和颜色

色彩

ctx.fillStyle
  • 设置填充颜色
1
2
3
4
ctx.fillStyle = 'green'
ctx.fillStyle = '#00ff00'
ctx.fillStyle = 'rgb(0, 255, 0)'
ctx.fillStyle = 'rgba(0, 255, 0, 0.5)'
ctx.strokeStyle
  • 设置描边颜色

透明度

ctx.globalAlpha
  • 设置图形和图片的透明度
  • 取值在0-1之间,默认值为1,即不透明
1
2
3
4
5
ctx.fillStyle = 'blue'
ctx.fillRect(10, 10, 100, 100)
ctx.globalAlpha = 0.5
ctx.fillStyle = 'green'
ctx.fillRect(50, 50, 100, 100)

xx

线型

ctx.lineWidth
  • 设置或获取线段的粗细
  • 取值正数,默认为1
1
2
3
4
ctx.lineWidth = 5
ctx.fillStyle = 'gray'
ctx.fillRect(10, 10, 100, 100)
ctx.strokeRect(10, 10, 100, 100)
ctx.lineCap
  • 设置线段末端的样式
  • 枚举值:butt(默认) round square
  • 绘制相同长度的线段时,不同lineCap的长度不同,roundsquarebutt长出lineWidth/2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ctx.lineWidth = 10
// 绘制lineCap为butt的线段
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(10, 100)
ctx.stroke()
// 绘制lineCap为round的线段
ctx.lineCap = 'round'
ctx.beginPath()
ctx.moveTo(40, 10)
ctx.lineTo(40, 100)
ctx.stroke()
// 绘制lineCap为square的线段
ctx.lineCap = 'square'
ctx.beginPath()
ctx.moveTo(80, 10)
ctx.lineTo(80, 100)
ctx.stroke()
ctx.lineJoin
  • 指定两个相连路径的连接部分的样式
  • 枚举值: bevel round miter(默认)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ctx.lineWidth = 10
ctx.beginPath()
ctx.moveTo(10, 10)
ctx.lineTo(60, 60)
ctx.lineTo(110, 10)
ctx.stroke()
ctx.lineJoin = 'round'
ctx.beginPath()
ctx.moveTo(150, 10)
ctx.lineTo(200, 60)
ctx.lineTo(250, 10)
ctx.stroke()
ctx.lineJoin = 'bevel'
ctx.beginPath()
ctx.moveTo(300, 10)
ctx.lineTo(350, 60)
ctx.lineTo(400, 10)
ctx.stroke()
ctx.miterLimit
  • 当lineJoin被设置为miter时,两条线段的外侧会延伸,直至相交
  • miterLimit是设置向外延伸的最大值,一旦超过这个最大值,这不再延伸,而是lineJoin变为bevel模式

虚线

ctx.setLineDash(arr)
  • 设置虚线样式
  • arr: 虚线线段长度和间距长度的数组,数组长度可为2或者3。如[10, 20] [10, 20, 30]
  • 如果数组元素的数量是奇数,数组元素会被复制并重复一次
1
2
3
4
5
6
ctx.lineWidth = 10
ctx.setLineDash([10, 2030])
ctx.beginPath()
ctx.moveTo(20, 20)
ctx.lineTo(500, 500)
ctx.stroke()
ctx.getLineDash()
  • 返回值:一组描述交替绘制线段和间距(坐标空间单位)长度的数字
ctx.lineDashOffset
  • 设置虚线偏移量

渐变

ctx.createLinearGradient(x0, y0, x1, y1)
  • 创建沿参数坐标指定的直线的渐变
  • x0, y0: 起点坐标
  • x1, y1: 重点坐标
1
2
3
4
5
6
let gradient = ctx.createLinearGradient(0, 0, 200, 200)
gradient.addColorStop(0, 'red')
gradient.addColorStop(0.5, 'green')
gradient.addColorStop(1, 'blue')
ctx.fillStyle = gradient
ctx.fillRect(0, 0, 200, 200)
ctx.createRadialGradient(x1, y1, r1, x2, y2, r2)
  • 根据参数确定两个圆的坐标,绘制放射性渐变
  • r1: 第一个圆的半径
  • r2: 第二个圆的半径
1
2
ctx.addColorStop(position, color)
  • 设置渐变过程中某个位置的颜色
  • postion: 位置。取值0-1之间
  • color: 有效的颜色的字符串,如'#fff' 'rgba(255, 255, 255, 0.1)'

图案样式

ctx.createPattern(image, type)
  • 创建模式
  • image: 如下类型的元素
    • HTMLImageElement(img)
    • HTMLVideoElement(video)
    • HTMLCanvasElement(canvas)
    • ImageBitmap
    • ImageData
    • Blob
  • type: 枚举值repeat(默认) repeat-x repeat-y no-repeat
ctx.shadowOffsetX / ctx.shadowOffsetY
  • 设置阴影在水平和垂直方向的偏移距离
ctx.shadowBlur
  • 设置阴影模糊的程度
  • 取值:非负数,默认值为0
ctx.shadowColor
  • 设置阴影的颜色
1
2
3
4
5
ctx.shadowOffsetX = 10
ctx.shadowOffsetY = 10
ctx.shadowBlur = 10
ctx.shadowColor = 'green'
ctx.strokeRect(10, 10, 100, 100)

文本

绘制文本

ctx.fillText(text, x, y[, maxWidth])
  • 以填充的方式绘制文字
  • text: 被绘制的文字
  • x, y: 绘制的起点
  • maxWidth: 最大宽度,可选
1
ctx.fillText('Canvas', 50, 50)
ctx.strokeText(text, x, y[, maxWidth])
  • 以描边的方式绘制文字
  • 参数同fillText
1
ctx.strokeText('Canvas', 50, 50)

设置样式

ctx.font
  • 设置文字字体。默认:10px sans-serif
1
ctx.font = '50px 微软雅黑'
ctx.textAlign
  • 设置文字的对齐方式
  • 对齐是指当执行fillText或者strokeText时,相对于参数X的位置,如取值为center时,文本的开始位置将是x - 文字的长度 * 50%
  • 取值: 枚举start(默认) end left right center
1
2
3
ctx.textAlign = 'end' // 从文字的结束位置开始绘制文字
ctx.textAlign = 'left' // 文本左对齐
ctx.textAlign = 'center' // 绘制文字时,从中间向两边绘制
ctx.textBaseline
  • 设置文字的基线,即文字垂直方向的绘制基准
  • 取值: 枚举top hanging middle alphabetic(默认) ideographic bottom
1
2
3
4
ctx.textBaseline = 'top' // 文本基线位于文本的顶部
ctx.textBaseline = 'hanging' // 文本基线是悬挂基线?
ctx.textBaseline = 'middle' // 基线位于文本中间
ctx.textBaseline = 'alphabetic' // 基线位于文字的基线
ctx.direction
  • 设置文字的方向
  • 取值: ltr 从左向右(默认) / rtl 从右向左

文本测量

ctx.measureText(text)
  • 测量文本并获取当前文本相关属性的对象
  • 测量相同文本的返回值会根据前期设置的不同而返回值不同
1
2
3
4
5
ctx.font = '20px 微软雅黑'
ctx.measureText('Canvas') // {width: 74.61994934082031}
ctx.font = '50px 微软雅黑'
ctx.measureText('Canvas') // {width: 186.54995727539062}

图片

绘制图片

drawImage(image, x, y, width, height)
  • 绘制图片到画布上
  • x, y: 绘制的起点
  • width, height: 绘制的宽高(压缩图片)
drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, distX, distY, distWidth, distHeight)
  • 对图片进行切片之后绘制到画布上
1
2
3
4
5
6
let img = new Image()
// img.setAttribute('crossOrigin', '')
img.onload = () => {
ctx.drawImage(img, 0, 0, 500, 500, 10, 10, 100, 100)
}
img.src = 'http://i1.piimg.com/574382/0cf50444001a3184.jpg'