Canvas
Canvas概念
canvas 是h5提供的一个标签,帮我们创建一块画布。可以绘制任意图形,包括图片、动画等内容。当前主流浏览器均支持。
基本用法
<canvas id="canvas" width="500" height="500"></canvas>
注意:设置canvas画布大小时不能通过style样式调整,会造成画布内容模糊
绘制上下文
Canvas创建了一个画布,并提供了一个上下文对象getContext()获得渲染上下文和绘画功能
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
画布坐标系
Canvas坐标系采用笛卡尔坐标系,默认0,0坐标为右上角。遵循我们屏幕、报纸的阅读习惯,从上往下,从左往右

了解了坐标系后让我们开始绘制基本图形吧
绘制图形
通过上下文对象,我们可以绘制多种图形,例如直线、矩形、圆形等
直线
绘制直线的基本api
moveTo(x, y) 画笔移动到指定位置
lineTo(x, y) 从画笔指定位置绘制到x和y坐标
stroke() 绘制
ctx.moveTo(50, 50) // 将画笔移动到50,50
ctx.lineTo(150, 150) // 画直线
ctx.stroke() // 绘制

矩形
strokeRect(x,y,width,height) 绘制矩形边框
fillRect(x,y,width,height) 绘制填充矩形
clearRect(x, y, width, height) 清除指定矩形区域
// 矩形的边框 strokeRect(x,y,width,height)
ctx.strokeStyle = 'red' // 设置边框颜色
ctx.strokeRect(50, 50, 200, 100)
// 填充矩形 fillRect(x,y,width,height)
ctx.fillStyle = 'blue' // 设置填充颜色
ctx.fillRect(100, 100, 200, 100)
// clearRect(x, y, width, height) 清除指定矩形区域
ctx.clearRect(120, 100, 100, 70)
红色区域为矩形边框,蓝色部分为填充矩形,中间白色缺少部分则是清除的矩形区域

圆弧和圆
arc(x, y, radius, startAngle, endAngle, anticlockwise) x和y为圆心的坐标,radius为半径,startAngle为圆弧或圆的开始位置,endAngle为圆弧或圆的结束位置,anticlockwise是绘制的方向(不写默认为false,从顺时针方向)。
ctx.arc(60, 60, 50, 0, Math.PI, false)
ctx.stroke()

注意:startAngle和endAngle均为弧度,而不是角度。弧度转角度公式:弧度=(Math.PI/180)*角度 Math.PI*2 则是一个圆
ctx.arc(60, 60, 50, 0, Math.PI, false)
ctx.stroke()
ctx.arc(200, 60, 50, 0, Math.PI * 2, false)
ctx.stroke()

可以看到两个圆弧之间连接到了一起,这是因为每次绘制的时候没有开启关闭绘制路径
beginPath 开启新的路径绘制
closePath 关闭路径
ctx.beginPath() // 开启路径
ctx.arc(60, 60, 50, 0, Math.PI, false)
ctx.stroke()
ctx.closePath()
ctx.beginPath() // 开启路径
ctx.arc(200, 60, 50, 0, Math.PI * 2, false)
ctx.stroke()
ctx.closePath()

ctx.closePath()并非必须,只需要每次重新绘制时开启新的路径即可
fill可以为圆弧填充,填充时可以使用strokeStyle和fillStyle来调整边框颜色和填充颜色
ctx.beginPath() // 开启路径
ctx.arc(60, 60, 50, 0, Math.PI, false)
ctx.stroke()
ctx.beginPath() // 开启路径
ctx.arc(200, 60, 50, 0, Math.PI * 2, false)
ctx.stroke()
ctx.beginPath() // 开启路径
ctx.arc(60, 200, 50, 0, Math.PI * 2 / 4, false)
ctx.fill(); // 填充
ctx.stroke()
ctx.beginPath() // 开启路径
ctx.arc(200, 200, 50, 0, Math.PI * 2 / 6, false)
ctx.fill(); // 填充
ctx.stroke()
ctx.beginPath() // 开启路径
ctx.arc(400, 200, 50, 0, Math.PI * 2, false)
ctx.fill(); // 填充
ctx.stroke()

椭圆
ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
- x、y:椭圆的圆心位置
- radiusX、radiusY:x轴和y轴的半径
- rotation:椭圆的旋转角度,以弧度表示
- startAngle:开始绘制点
- endAngle:结束绘制点
- anticlockwise:绘制的方向(默认顺时针),可选参数。
ctx.beginPath();
ctx.ellipse(100, 100, 50, 100, 0, 0, 2 * Math.PI);
ctx.stroke()
ctx.beginPath();
ctx.ellipse(300, 100, 50, 100, Math.PI / 2, 0, 2 * Math.PI);
ctx.stroke()
ctx.beginPath();
ctx.ellipse(200, 350, 100, 100, Math.PI / 4, 0, 2 * Math.PI);
ctx.stroke()

当radiusX 和radiusY相等是绘制出来的就是圆形,同样可以使用strokeStyle和fillStyle来调整边框颜色和填充颜色
贝塞尔曲线
二次贝塞尔曲线
二次贝塞尔曲线由三个点组成,分别是起点、终点、控制点
quadraticCurveTo(controlX, controlY, x, y)
- controlX、controlY:控制点坐标
- x、y:结束点坐标
- 起点坐标为画笔坐标,如
moveTo()
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(200, 200, 350, 50);
ctx.stroke();// 绘制

三次贝塞尔曲线
三次贝塞尔曲线相较于二次贝塞尔曲线多了一个控制点
bezierCurveTo(control1X,control1Y, control2X,control2Y, x, y)
- control1X、control1Y:第一个控制点坐标
- control2X、control2Y:第二个控制点坐标
- x、y:结束点坐标
- 起点坐标为画笔坐标,如
moveTo()
ctx.moveTo(50, 200)
ctx.bezierCurveTo(150, 50, 250, 350, 350, 200)
ctx.stroke() // 绘制

样式
线条样式
lineWidth 设置绘制线条粗细,默认值1
// 绘制样式
// lineWidth 线宽
ctx.moveTo(50, 50)
ctx.lineTo(150, 50)
ctx.stroke()
ctx.beginPath();
ctx.moveTo(50, 100)
ctx.lineTo(200, 100)
ctx.lineWidth = 10
ctx.stroke()
ctx.beginPath();
ctx.moveTo(50, 150)
ctx.lineTo(250, 150)
ctx.lineWidth = 20
ctx.stroke()

lineCap 设置线段端点显示的样子,默认是 butt。可选值为:butt、round 、 square。
// lineCap 线帽
ctx.moveTo(50, 50)
ctx.lineTo(200, 50)
ctx.lineWidth = 10
ctx.lineCap = 'butt'
ctx.stroke()
ctx.beginPath();
ctx.moveTo(50, 100)
ctx.lineTo(200, 100)
ctx.lineWidth = 10
ctx.lineCap = 'round'
ctx.stroke()
ctx.beginPath();
ctx.moveTo(50, 150)
ctx.lineTo(200, 150)
ctx.lineWidth = 10
ctx.lineCap = 'square'
ctx.stroke()

lineJoin 设置线段之间连接处的样式,默认是 miter。可选值为:round、bevel 、 miter。
// lineJoin 线连接
ctx.moveTo(50, 50)
ctx.lineTo(100, 100)
ctx.lineTo(150, 50)
ctx.lineTo(200, 100)
ctx.lineTo(250, 50)
ctx.lineWidth = 10
ctx.lineJoin = 'miter'
ctx.stroke()
ctx.beginPath();
ctx.moveTo(50, 150)
ctx.lineTo(100, 200)
ctx.lineTo(150, 150)
ctx.lineTo(200, 200)
ctx.lineTo(250, 150)
ctx.lineWidth = 10
ctx.lineJoin = 'round'
ctx.stroke()
ctx.beginPath();
ctx.moveTo(50, 250)
ctx.lineTo(100, 300)
ctx.lineTo(150, 250)
ctx.lineTo(200, 300)
ctx.lineTo(250, 250)
ctx.lineWidth = 10
ctx.lineJoin = 'bevel '
ctx.stroke()

透明度
在之前绘制矩形时我们用到过fillRect来填充矩形,颜色支持rgba
ctx.fillStyle = "rgba(255,0,0,0.2)" // 设置填充颜色
ctx.fillRect(100, 100, 200, 100)
ctx.fillStyle = "rgba(255,0,0,0.7)" // 设置填充颜色
ctx.fillRect(100, 300, 200, 100)

渐变
线性渐变
createLinearGradient(x1, y1, x2, y2),参数分别为 起点的坐标和终点的坐标。
在渐变的设置中还需要一个方法来添加渐变的颜色,语法为:gradient.addColorStop(offset, color),其中color就是颜色,offset 则是颜色的偏移值,只为0到1之间的数。
let gradient = ctx.createLinearGradient(10, 200, 400, 200)
gradient.addColorStop(0, '#00ff00')
gradient.addColorStop(1, '#ff0000')
ctx.fillStyle = gradient
ctx.fillRect(10, 10, 400, 400)

addColorStop 可以添加渐变颜色
let gradient = ctx.createLinearGradient(10, 200, 400, 200)
gradient.addColorStop(0, 'rgb(255, 0, 0)')
gradient.addColorStop(0.5, 'rgb(0, 255, 0)')
gradient.addColorStop(1, 'rgb(0, 0, 255)')
ctx.fillStyle = gradient
ctx.fillRect(10, 10, 400, 400)

createLinearGradient创建渐变时可以设置颜色渐变方向,比如我们想让颜色从左上角到右下角渐变
let gradient = ctx.createLinearGradient(10, 10, 400, 400)

径向渐变
createRadialGradient(x0, y0, r0, x1, y1, r1),参数分别为开始圆的坐标和半径以及结束圆的坐标和半径。
let gradient = ctx.createRadialGradient(250, 250, 50, 250, 250, 200)
gradient.addColorStop(0, 'rgb(255, 0, 0)')
gradient.addColorStop(0.5, 'rgb(0, 255, 0)')
gradient.addColorStop(1, 'rgb(0, 0, 255)')
ctx.fillStyle = gradient
ctx.arc(250, 250, 200, 0, Math.PI * 2, false)
ctx.fill() // 填充

图案填充
createPattern(image, type),参数分别为:Image 参数可以是一个 Image 对象,也可以是一个 canvas 对象,Type 为图案绘制的类型,可用的类型分别有:repeat、repeat-x、repeat-y 和、no-repeat
let img = new Image()
img.src = 'https://img0.baidu.com/it/u=147381800,3591524360&fm=253&fmt=auto&app=138&f=JPEG?w=371&h=194'
img.onload = function () {
let pattern = ctx.createPattern(img, 'no-repeat')
ctx.fillStyle = pattern
ctx.fillRect(0, 0, 500, 500)
}

可以看到,我们绘制的矩形大小为500x500,当我们设置no-repeat时不会铺满。让我们改成repeat试试,repeat为x轴和y轴均平铺,可以自己尝试一下repeat-x和repeat-y。
let pattern = ctx.createPattern(img, 'repeat')

绘制文本
strokeText 文字描边
ctx.strokeText(text, x, y, maxWidth) 参数:text:文本内容、x,y :坐标、maxWidth:最大宽度
ctx.font = "50px serif"; // 设置字体大小和文字样式
ctx.strokeText("Canvas", 50, 50);

fillText 填充字体
ctx.fillText("Canvas", 50, 50);

文本样式
font 修改文本字体大小及文字样式,默认值:10px sans-serif
textAlign 文本对齐方式,参数为:left、right、center、start、end,默认值:start
direction 文本方向,参数为:ltr(文本方向从左向右)、rtl(文本方向从右向左)、inherit(根据情况继承 Canvas元素或者 Document ),默认值是: inherit
ctx.font = "30px serif"; // 设置文案大小和字体
ctx.direction = "ltr"; // 文本方向从左向右
ctx.textAlign = "left"; // 左对齐
ctx.strokeText("Hi Canvas !", 250, 100);
ctx.direction = "ltr"; // 文本方向从左向右
ctx.textAlign = "center"; // 右对齐
ctx.strokeText("Hi Canvas !", 250, 150);
ctx.direction = "ltr"; // 文本方向从左向右
ctx.textAlign = "right"; // 右对齐
ctx.strokeText("Hi Canvas !", 250, 200);
ctx.direction = "rtl"; // 文本方向从左向右
ctx.textAlign = "left"; // 左对齐
ctx.strokeText("Hi Canvas !", 250, 250);
ctx.direction = "rtl"; // 文本方向从左向右
ctx.textAlign = "center"; // 右对齐
ctx.strokeText("Hi Canvas !", 250, 300);
ctx.direction = "rtl"; // 文本方向从左向右
ctx.textAlign = "right"; // 右对齐
ctx.strokeText("Hi Canvas !", 250, 350);

后续内容待补充…
文章内容借鉴:原文连接

6879

被折叠的 条评论
为什么被折叠?



