canvas
1.简介
canvas(画布)是HTML5标准引入的一个新标签,该标签结合js可以实现各种图形的绘制,这给web带来了无限可能。
1.1 效果展示
炫酷的特效 - 大家学完canvas之后,再加上自己的一点点思考,就可以完成这些特效。当然,实际的工作中并不需要这样炫酷的特效,所以大家可以作为兴趣了解学习。
图表 - canvas并非只能做炫酷的效果,基于canvas/svg有一些很实用的图表插件,比如echarts,highcharts。
结合WebGL - 在浏览器端开启硬件加速,实现3D场景的绘制。利用webGL技术可以在浏览器端做出非常棒的3D效果和游戏。并且随着5G时代的到来,移动端网页游戏发展前端可观。这是一门单独且很硬核的学习方向,感兴趣或者想从事web游戏开发的同学可以报名我们后期逐步推出的webGL课程。
2.绘制准备
2.1 绘制上下文的获取
<canvas></canvas>
<script>
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
</script>
首先需要通过canvas节点的getContext方法获取ctx对象,所有的绘制都是在ctx对象上进行操作的。getContext方法的参数为 "2d"
,当然参数还有"webgl"
与"webgl2"
,可以结合webGL来绘制图形。
2.2 canvas画布大小设置
canvas标签的默认大小为300*150。
增大canvas绘图区域不能在css样式里面设置,因为那样只会缩放canvas绘制的图像,并不会使绘制的实际区域增大。我们需要在canvas标签中设置width="500" height="500"
这样的标签属性,才能真正的改变绘图区域的大小。
如果你想让你的canvas和显示区一样大的话,可以使用js来操作:
//将canvas画布大小调整到与显示区大小一致
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
3.绘制基础图形
3.1 绘制线段
//规定线段的各个起止点
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(100,70);
//画线绘制
ctx.stroke();
线段的绘制,需要使用moveTo方法规定线段的起点,lineTo方法规定线段的各个中间点,这些点的坐标都是相对于canvas标签的左上角(0,0)的。最后使用stroke方法绘制出线段。
绘制方法有两种,一种为stroke(绘制线段)还可以使用 fill 方法将线段围成的区域绘制出来:
//规定线段的各个起止点
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(100,70);
//填充绘制
ctx.fill();
3.2 设置绘制颜色
默认的线段或者填充是黑色的,我们可以在绘制之前设置颜色:
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(100,70);
//设置填充颜色。
ctx.fillStyle = "rgba(255,0,0,.9)";
ctx.fill();
/*
//设置线段颜色
ctx.strokeStyle = "red";
ctx.stroke();
*/
颜色值支持 单词、#、rgb、rgba,还支持渐变色,我们在后面介绍。
3.3 beginPath与closePath
//1
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(100,70);
ctx.strokeStyle = "red";
ctx.stroke();
//2
ctx.moveTo(400,20);
ctx.lineTo(300,200);
ctx.lineTo(300,250);
ctx.fillStyle = "green";
ctx.fill();
上述代码并不能实现一段线段和一块填充,而是1部分有线段和填充,2部分有填充。也就是说2部分的填充对1部分也会生效。如果我们想要让两块内容不相互影响的话,需要使用 beginPath 方法,规定每个部分的绘画起始:
//1
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(100,70);
ctx.strokeStyle = "red";
ctx.stroke();
//2
ctx.beginPath();
ctx.moveTo(400,20);
ctx.lineTo(300,200);
ctx.lineTo(300,250);
ctx.fillStyle = "green";
ctx.fill();
对应的还有 closePath 方法,这个方法会使线段产生回环:
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(100,50);
ctx.lineTo(100,70);
ctx.closePath();
ctx.strokeStyle = "red";
ctx.stroke();
所以,closePath并不是必须的,根据需求决定是否添加。
3.4 绘制矩形
边框矩形 - 绘制一个只有边框的矩形:
ctx.beginPath();
ctx.strokeStyle = "red";
//四个参数, x:起点x坐标,y:起点y坐标,w:矩形宽,h:矩形高
//比如:绘制一个起点在(10,10),且宽度是200,高度为100的矩形
ctx.rect(10,10,200,100);
ctx.stroke();
//上两行代码等价于:
//ctx.strokeRect(10,10,200,100);
填充矩形 - 绘制一个拥有填充色的矩形:
ctx.beginPath();
ctx.fillStyle = "red";
//参数与上述相同
ctx.rect(10,10,200,100);
ctx.fill();
//上两行代码等价于:
//ctx.fillRect(10,10,200,100);
3.5 擦除区域
将指定的矩形区域所绘制的内容擦除:
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.stroke();
//擦除该矩形范围里面的绘图内容,参数与上述相同
ctx.clearRect(0,0,50,30);
3.6 绘制圆形(或圆的一部分)
ctx.beginPath();
ctx.arc(200,200,100,0*Math.PI,1.5*Math.PI,false);
ctx.stroke();
/*
arc参数
x :圆心 x 坐标
y :圆心 y 坐标
r :半径
sAngle : 起始弧度
eAngle : 结束弧度
counterclockwise :可选,布尔值,默认false。true代表逆时针画,false代表顺时针画
*/
3.8 绘制弧线
与绘制圆不同的是,绘制弧是通过指定点的切线绘制的:
ctx.beginPath();
ctx.moveTo(100,20); //弧起点
ctx.arcTo(150,20,150,70,50); //弧线
ctx.stroke();
/*
arcTo参数
x1 : 两条切线交点x坐标
y1 : 两条切线交点y坐标
x2 : 第二条切线上一点的x坐标
y2 : 第二条切线上一点的y坐标
r : 弧半径
也就是说,弧线是与两条相交线段都相切的。
第一条线段是 起点---(x1,y1)
第二条线段是 (x1,y1)---(x2,y2)
*/
4.各种样式
4.1 线条样式
-
lineWidth
设置线段的宽度:
ctx.lineWidth = 10; //10px的线段宽度
-
lineCap
设置线段两端的线帽:
ctx.lineCap = "round"; //线段两端添加圆形线帽 /* butt 默认值,平直的边缘 round 圆形线帽(线段会略微变长) square 正方形线帽(线段会略微变长) */
-
lineJoin
设置线段相交时夹角的样式:
ctx.lineJoin = "round"; //圆形夹角 /* bevel 斜角 round 圆角 miter 默认,尖角 */
4.2 阴影样式
与css设置阴影类似,只不过canvas里面分为4个属性来设置:
ctx.shadowOffsetX
设置水平偏移;
ctx.shadowOffsetY
设置垂直偏移;
ctx.shadowBlur
设置模糊程度;
ctx.shadowColor
设置阴影颜色。
4.3 渐变色
当设置绘制颜色时,除了直接写固定的颜色之外,还可以使用渐变色。
-
createLinearGradient
// 设置线性渐变的 起点坐标 终点坐标 let x = ctx.createLinearGradient(0,0,200,0); //设置各个色阶(可以结合css来理解) x.addColorStop(0,"#000"); x.addColorStop(.5,"#f00"); x.addColorStop(1,"#fff"); //应用样式 ctx.fillStyle = x; ctx.fillRect(0,0,300,300);
-
createRadialGradient
//渐变开始圆的坐标与半径 结束圆的坐标与半径 let x = ctx.createRadialGradient(200,200,0,200,200,200); //设置各个色阶(可以结合css来理解) x.addColorStop(0,"#fff"); x.addColorStop(0.5,"yellow"); x.addColorStop(1,"red"); //应用样式 ctx.fillStyle = x; ctx.fillRect(0,0,400,400);
4.4 转换
-
scale()
ctx.scale(1.5,2); //水平缩放1.5倍,垂直缩放2倍
-
rotate()
ctx.rotate(30/180*Math.PI); //旋转30deg,(注意要转换成弧度)
-
translate()
ctx.translate(100,100); //规定(100,100)位置 为canvas的(0,0)点
ctx.save()
保存当前环境的状态
ctx.restore()
返回之前保存的环境状态
5.绘制文字
5.1 绘制方式
-
fillText
实心文字
ctx.fillText("ABC",100,100);
文字内容,x坐标,y坐标。
-
strokeText
空心文字,参数与上述相同。
5.2 文字样式
-
font
ctx.font = "bold 18px '微软雅黑'"; //值与css类似
-
textAlign
ctx.textAlign = "right";//对齐方式 start默认 end left right center
-
textBaseline
ctx.textBaseline = "Middle";//文字基线 alphabetic top hanging middle ideographic bottom
6.绘制图片
let img = new Image();
img.src = "./1.png";
//需要先加载图片然后绘制
img.onload = function(){
ctx.drawImage(img,100,100);
};`
7.像素操作
7.1 获取区域像素数据
let imageData = ctx.getImageData(0,0,200,200);
/*
imageData.data中存储着每个像素点的颜色数据,每四位对应一个点的信息 r g b a
imageData.width返回对象的宽度
imageData.height返回对象的高度
*/
7.2 创建空白的imageData对象
let imgData = ctx.createImageData(100,100);
//创建一个空白的 100*100 对象,可以后续设置各个色点数据
7.3 将图像数据绘制到画布
ctx.putImageData(imgData,100,100);
8.合成
8.1 透明度
ctx.globalAlpha=0.2; //设置透明度为0.2
8.2 绘制内容重叠时合成方式
ctx.globalCompositeOperation
9.补充
9.1 clip
ctx.rect(50,20,200,120);
ctx.clip();
//clip之后,后续所有的绘画的内容只有(50,20,200,120)之间的才会显示
//如果不想clip影响后续所有,可以使用save方法保存状态,在需要不需要剪裁之后,使用restore
9.2 贝塞尔曲线
ctx.beginPath();
ctx.moveTo(20,20); //起点
ctx.quadraticCurveTo(20,100,200,20); //切线交点坐标,终点坐标
ctx.stroke();
//ctx.bezierCurveTo 三次贝赛尔曲线