# canvas文档
canvas画布通过getContext(2d)获取2D上下文来对画布进行绘图,2D上下文提供基础的方法来绘制一些简单的图形,如矩形、弧线、路径和文本,然后通过填充、描边来指定样式,然后通过变换、渐变、阴影、合成(透明度)、模式来改变和丰富绘制的图形。还可以通过一些方法把图片、视频绘制到画布上,并且能对齐进行操作和改变。绘制好的画布还可以把它转换成图片来进行保存。
# 基本用法
画布宽高的设置,可以在元素上直接设置,或者通过js设置。canvas的宽高和css设置的宽高是不一样的,css设置的大小是设置的画布窗口显示的大小,但是底层画布的大小是没有改变的,默认是300*150的,所以有时只设置的css宽高绘制是变形的,只有设置画布的大小和css设置的窗口大小一样才不会变形。
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
// 真实宽高
canvas.width = 300;
canvas.height = 300;
// 获取2d上下文
var ctx = canvas.getContext("2d");
</script>
# 填充和描边
canvas 2d上下文的两种基本操作是填充fillStyle
和描边strokeStyle
,都是设置颜色的属性,可以进行重复设置。填充和描边要依据绘制的图形进行设置,否则就会没有用。
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle ="blue"
ctx.strokeStyle = "red";
</script>
# 绘制矩形
绘制矩形相关的方法有三个,fillRect
/strokeRect
/clearRect
,fillRect()结合fillStyle绘制实心的,strokeRect()结合strokeStyle绘制描边矩形,clearRect()用来清除指定矩形区域的内容。
绘制描边或者线条还可以通过lineWidth
/lineCap
/lineJoin
来设置宽度接头等样式。
fillRect(x, y, w, h) 起点(x, y),宽高(w, h)
strokeRect(x, y, w, h) 起点(x, y),宽高(w, h)
clearRect(x, y, w, h) 清除某个矩形区域 起点(x, y),宽高(w, h)
lineWidth 设置宽度,整数
lineCap 设置线条末端形状,butt<平头>、round<圆头>、square<方头>
lineJoin 设置线条相交方式,round<圆交>、bevel<斜交>、miter<斜接>
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 填充实心矩形
ctx.fillStyle ="red"
ctx.fillRect(0, 0, 100, 100);
// 描边样式
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.lineJoin = "round";
// 矩形边框
ctx.strokeStyle = "blue";
ctx.strokeRect(50, 50, 100, 100);
// 清除某个区域
ctx.clearRect(60, 60, 30, 30);
</script>
# 绘制路径
绘制路径可以在画布上进行画线,比如,直线、曲线、圆形的线,矩形的线,然后再调用其他方法对画的线进行描边、填充和首位连接。
绘制路线必须先调用beginPath()
方法开始,使用moveTo()
设置路线起点,如果不设置新的起点,每画一段线都会相互连接,除非使用moveTo再设置新的起点来画就不会相连接了。
每绘制完成后,使用closePath()
来让路线首位相连,这个自己设置结束点和起点一样也能相连。 使用stroke()
来对路径进行描边,然后先使用strokeStyle
对路线进行设置颜色、宽度等。使用fill()
来对路线区域进行填充,最好先使用closePath()
让路线闭合,然后先使用fillStyle
设置填充颜色。
绘制路线方法:
- moveTo(x, y) 设置起点
- lineTo(x, y) 画一条直线
- rect(x, y, w, h) 画一条矩形路线
- arc(x, y, radius, startAngle, endAngle, clock) 起点(x, y),半径(radius),角度(startAngle, endAngle),是否顺时针(clock)
- arcTo(x1, y1, x2, y2, radius) 从上一点开始到(x1,y1)为直线,然后从(x1,y1)到(x2,y2)画一条半径为radius的曲线
- quadraticCurveTo(cx, cy, x, y) 从一点到(x, y)为结束点画一条不规则曲线, 通cx,cy点来控制弯曲度
1、描边三角形
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "red"; // 线的颜色
ctx.beginPath();
// 画一个三角形
ctx.moveTo(50, 0);
ctx.lineTo(100, 100);
ctx.lineTo(0, 100);
ctx.lineTo(50, 0);
// 自动闭合三角形
ctx.moveTo(200, 0); // 新起点,要不然线会连在一起
ctx.lineTo(250, 100);
ctx.lineTo(150, 100);
ctx.closePath();
ctx.stroke(); // 描边,把线绘制到画布上
</script>
2、填充三角形
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red"; // 填充颜色
ctx.beginPath();
// 画一个三角形
ctx.moveTo(50, 0);
ctx.lineTo(100, 100);
ctx.lineTo(0, 100);
ctx.lineTo(50, 0);
// 自动闭合三角形
ctx.moveTo(200, 0);
ctx.lineTo(250, 100);
ctx.lineTo(150, 100);
ctx.closePath();
ctx.fill(); // 填充路径
</script>
3、矩形
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(50, 50, 100, 100);
ctx.stroke();
</script>
4、圆形、弧线
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(150, 100);
// 圆形
ctx.arc(100, 100, 50, 0, 2 * Math.PI, false);
// 半圆
ctx.arc(100, 100, 50, 0, 2 * Math.PI / 2, false);
// 不规则曲线
ctx.moveTo(150, 100);
ctx.quadraticCurveTo(100, 50, 100, 200);
ctx.stroke();
</script>
5、同心圆
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
// 同心圆,不同起点
ctx.moveTo(150, 100);
ctx.arc(100, 100, 50, 0, 2 * Math.PI, false);
ctx.moveTo(130, 100); // 起点设置为第二个圆的0开始的地方
ctx.arc(100, 100, 30, 0, 2 * Math.PI, false);
ctx.stroke();
</script>
6、环形
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "red";
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.beginPath();
ctx.arc(100, 100, 50, 2 * Math.PI / 2, 0, false);
ctx.stroke();
</script>
# 绘制文本
绘制文本使用fillText()
和strokeText()
两个方法,一般使用第一个,fillText第一个参数是文字,后面两个是位置
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "bold 20px Arial";
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.fillText("绘制文字", 10, 50)
ctx.strokeStyle = "red"; // 使用strokeText可以设置颜色
ctx.strokeText("绘制文字", 10, 150)
</script>
# 变换
变换和css的过渡一样,有旋转、缩放,变换原点等。
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(50, 50, 200, 50);
ctx.stroke();
// 变换原点
ctx.translate(100, 100)
// 旋转
ctx.rotate(1)
// 缩放
ctx.scale(2, 2)
</script>
# 渐变
渐变和css渐变差不多,分为线性渐变和径向渐变,渐变首先要先创建一个指定区域的渐变对象,然后再用这个对象设置渐变的颜色过渡。再然后把这个渐变赋值给要渐变的填充区域就行了。
- createLinearGradient(x1, y1, x2, y2) 线性渐变对象,设置渐变区域和方向。 从(x1,y1)到(x2,y2)方向渐变
- createRadialGradient(x1, y1, r1, x2, y2, r2) 径向渐变对象,沿着圆(x1,y1)的r1外边到圆(x2,y2)的r2内进行渐变,实际是从r1到r2一圈范围内渐变。改变圆心位置和半径r就会实现不规则渐变。
- addColorStop(ap, color) ap 颜色从0开始渐变到1结束
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 创建线性渐变对象
var gradient = ctx.createLinearGradient(50, 50, 150, 150);
// 设置渐变过渡颜色
gradient.addColorStop(0, "red");
gradient.addColorStop(0.5, "blue");
gradient.addColorStop(1, "green");
// 赋值给要渐变的区域
ctx.fillStyle = gradient;
ctx.fillRect(50, 50, 100, 100);
// 创建径向渐变对象
var gradient = ctx.createRadialGradient(50, 50, 10, 50, 50, 40); // 从10到40径向渐变
gradient.addColorStop(0, "red");
gradient.addColorStop(1, "green");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 100, 100);
</script>
# 透明度和重叠状态
透明度和css样式opacity
一样,使用globalAlpha
设置整个画布的透明度,值为0~1。
属性globalCompositeOperation
可以设置先后绘制两个图形相互重叠的状态。
- source-over 默认值,后绘制的在先绘制之上
- source-in 重叠部分可见,两者其他部分透明
- source-out 不重叠部分可见,先绘制的透明
- source-in 重叠部分可见,先绘制不受影响
等等其他状态。。。
# 裁剪
裁切路径,就是用 clip
绘制一个不可见的区域,让在画布上新绘制的所有内容都将局限在该区域内,区域以外进行绘制是没有任何效果的。已有的内容不受影响。要取消裁切路径的效果,可以绘制一个和画布等大的矩形裁切路径。
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 200, 200);
// 绘制一个圆形裁剪区域
ctx.beginPath();
ctx.arc(100, 100, 100, 0, Math.PI * 2, true);
ctx.clip();
// 蓝色矩形被裁剪成一个蓝色的圆
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 200, 200);
</script>
# 保存状态
如果想把设置好的状态保存,再次修改后想返回之前的状态,我们可以使用 save()
方法保存,它会把所有设置推进一个栈结构保存,然后对上下文进行其他修改,等需要回到之前状态时,可以使用restore()
方法,返回上一级栈中的状态。 这两个方法都可以连续调用,连续保存和连续返回。
# 模式
模式和css设置背景图一样,把获取到的图片元素给画布某个区域设置背景图片,也可以设置video元素。
- createPattern(dom, repeat) dom可以是图片或者视频,repeat和背景图片的repeat一样,是否重复。
<img src="./public/img/logo.png" alt="">
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 获取图片
var image = document.getElementsByTagName("img")[0];
// 创建模式
var pattern = ctx.createPattern(image, "no-repeat");
// 赋值给某个区域
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 100, 100);
</script>
# 绘制图片,操作图像
把图像绘制到画布上,可以使用drawImage()
方法。
<img src="./public/img/logo.png" alt="">
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 获取图片
var image = document.getElementsByTagName("img")[0];
// 把获取图片大小不动的绘制到 (10, 10) 的位置上
ctx.drawImage(image, 10, 10);
// 把图片绘制到画布位置(10, 10)大小为50x50的区域上
ctx.drawImage(image, 10, 10, 50, 50);
// 获取图片(0, 0)位置大小为50x50区域的地方绘制到画布大小为50x50位置为(10, 10)的位置上
ctx.drawImage(image, 0, 0, 50, 50, 10, 10, 50, 50);
</script>
操作图像,使用getImageData()
方法获取图像数据,改变后再通过putImageData()
方法把数据写入画布。
<img src="./public/img/logo.png" alt="">
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// 先绘制图片
var image = document.getElementsByTagName("img")[0];
ctx.drawImage(image, 0, 0);
// 获取图片像素数据
const imageData = ctx.getImageData(0, 0, 380, 380);
const data = imageData.data;
// 改变为黑白色
for (let i = 0; i < data.length; i += 4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
// 在把图像写入到画布中
ctx.putImageData(imageData, 0, 0);
</script>
# 绘制视频
# 把画布转成图片
绘制好画布后,我们可以使用toDataURL()
方法把画布转成图片导出来。
<img src="./public/img/logo.png" alt="">
<canvas id="canvas" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 200, 200);
// 把画布转成图片
var imgURL = canvas.toDataURL("image/png");
var image = document.createElement("img");
image.src = imgURL;
document.body.appendChild(image);
</script>
← Git开发规范 canvas绘制环形进度条 →