canvas详解

canvas

1.简介

canvas(画布)是HTML5标准引入的一个新标签,该标签结合js可以实现各种图形的绘制,这给web带来了无限可能。

1.1 效果展示

炫酷的特效 - 大家学完canvas之后,再加上自己的一点点思考,就可以完成这些特效。当然,实际的工作中并不需要这样炫酷的特效,所以大家可以作为兴趣了解学习。

图表 - canvas并非只能做炫酷的效果,基于canvas/svg有一些很实用的图表插件,比如echartshighcharts

结合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();
*/

颜色值支持 单词#rgbrgba,还支持渐变色,我们在后面介绍。

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 三次贝赛尔曲线
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬日柠檬茶.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值