canvas入门详细教程(W3C)

10 篇文章 0 订阅
2 篇文章 0 订阅


详细介绍画布canvas的属性及方法,和矩形,路径,转化,文本,图像绘制等多个模块的使用。并附上代码示例+代码注解。
使用画布canvas之前,必做的三步:
①首先要有一用来画画的纸:

// 创建canvas标签:
<canvas id="canvas" height="400" width="400" style="box-shadow: 0 0 7px 0 #888888"></canvas>

②找到这张纸:

// 我们现在要使用JS获得这个canvas标签的DOM对象:
<script>
    const canvas = document.getElementById('canvas')
</script>

③决定是画二维还是三维的画:

// 通过getContext()方法来获得渲染上下文和它的绘画功能:
<script>
    const ctx = canvas.getContext('2d') // 这里我们先聚焦于2D图形
</script>

一、线形

1、画线形之前,最基本的方法需要知道:

moveTo(x,y):路径绘制命令的起点
lineTo(x,y):路径绘制转折点
stroke():绘制路径

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 第一条线性
ctx.moveTo(0,0); 	// 路径绘制命令的起点
ctx.lineTo(350,50); // 路径绘制转折点
ctx.stroke();  		// 绘制路径
// 第二条线形
ctx.moveTo(0,200);  
ctx.lineTo(50,200); 
ctx.lineTo(50,150);
ctx.lineTo(100,150);
ctx.lineTo(100,200);
ctx.lineTo(150,200);
ctx.lineTo(150,150);
ctx.lineTo(200,150);
ctx.stroke();

绘制结果如图:
canvas1

2、线形的样式设置:

strokeStyle = '颜色':设置线的颜色;
lineWidth = 数字:设置线的宽度;
lineCap = 'round/butt/square':设置线帽为圆型/默认/方形;
lineJoin = 'miter/round/bevel':设置线段连接处为默认/圆形/平直形式;
globalAlpha = 数字:设置图案的透明度
需要注意的是:这些样式设置,必须在ctx.stroke()之前给。因为ctx.stroke()是绘制图形轮廓,图形轮廓都已经画出来了,在它之后给是不生效的。

ctx.moveTo(0,200);  
ctx.lineTo(50,200); 
ctx.lineTo(50,150);
ctx.lineTo(100,150);
ctx.lineTo(100,200);
ctx.lineTo(150,200);
ctx.lineTo(150,150);
ctx.lineTo(200,150);
ctx.strokeStyle = 'red'; // 线形颜色
ctx.lineWidth = 6; // 线宽
ctx.globalAlpha = 0.5; // 透明度
ctx.lineCap = 'round'; // 线形末端样式圆型
ctx.lineJoin = 'round'; // 线形连接样式圆型
ctx.stroke();

线段样式效果如图:
canvas2

3、不同的线形路径给不同的样式设置-需要知道俩个方法:

beginPath():开启一条新路径,生成之后,图形绘制命令会被指向到新路径上;
closePath():关闭路径,生成闭合路径之后,图形绘制命令又重新指向到上下文中;

// 第一条
ctx.beginPath(); // 开启一条新路径
ctx.moveTo(0,0);
ctx.lineTo(350,50);
ctx.lineWidth = 1;
ctx.strokeStyle = 'blue';
ctx.lineCap = 'butt';
ctx.stroke();
ctx.closePath(); // 关闭路径
// 第二条
ctx.beginPath(); // 开启一条新路径
ctx.moveTo(0,200);
ctx.lineTo(50,200);
ctx.lineTo(50,150);
ctx.lineTo(100,150);
ctx.lineTo(100,200);
ctx.lineTo(150,200);
ctx.lineTo(150,150);
ctx.lineTo(200,150);
ctx.lineWidth = 5;
ctx.strokeStyle = 'red';
ctx.lineCap = 'round';
ctx.stroke();
ctx.closePath(); // 关闭路径

使用了beginPath、closePath 和 未使用的效果:
eg:在第二个效果图中,没有开辟新路径,导致第二条线形效果覆盖了第一条的样式效果。
canvas3

4、画线形三角

画线形三角也是用画线的思路,需要注意首尾点连接起来即可:

ctx.beginPath();
ctx.moveTo(60,60);
ctx.lineTo(150,60);
ctx.lineTo(150,150);
ctx.lineTo(60,60);
ctx.stroke();
ctx.closePath();

绘制效果如图:
canvas4
如果要添加样式也是一样的:

// 画三角                           // 闭合处显示的更衔接一点
ctx.beginPath();                    ctx.beginPath();
ctx.moveTo(60,60);                  ctx.moveTo(60,60);
ctx.lineTo(150,60);                 ctx.lineTo(150,60);    
ctx.lineTo(150,150);                ctx.lineTo(150,150);    
ctx.lineTo(60,60);                  ctx.lineTo(60,60);
ctx.lineWidth = 5;                  ctx.closePath();
ctx.strokeStyle = 'red'             ctx.lineWidth = 5;
ctx.stroke();                       ctx.strokeStyle = 'red';        
ctx.closePath();                    ctx.stroke(); 

绘制效果:
canvas5

5、画贝塞尔曲线

推荐一个在线调试二次贝塞尔曲线的小工具:在线调试工具
1、quadraticCurveTo(cpx,cpy,x,y)方法来绘制二次贝塞尔曲线:
cpx,cpy:控制点坐标
x,y:结束点坐标
在它之前有一个开始点坐标,一般由moveTo()或lineTo()方法提供。

ctx.beginPath();
ctx.moveTo(100,150);
ctx.quadraticCurveTo(250, 10, 300, 100); // 控制点(250,10)结束点(300, 100)
ctx.stroke();
ctx.closePath();

canvas10
2、bezierCurveTo(cpx1,cpy1,cpx2,cpy2,x,y)来绘制三次贝塞尔曲线:
cpx1,cpy1:第一个控制点坐标
cpx2,cpy2:第二个控制点坐标
x,y:结束点坐标

// 三次贝塞尔曲线
ctx.beginPath();
ctx.moveTo(100,150);
ctx.bezierCurveTo(200,10, 275,250, 380,150); //控制点1(200,10)控制点2(275,250)结束点(300,100)
ctx.stroke();
ctx.closePath();
// 辅助线
ctx.beginPath();
ctx.moveTo(100, 150);
ctx.lineTo(200, 10);
ctx.lineTo(275, 250);
ctx.lineTo(380, 150);
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();

canvas11

6、画虚线

setLineDash([])方法来绘制虚线,可以接收若干个参数。
数组参数会“铺开”,下标为偶数的项为实线,为奇数项为透明线段,数字的大小代表着线段的长度。
getLineDash()方法可以获得当前虚线设置的样式。如下面虚线样式,得到的结果是[10,5]

ctx.beginPath();
ctx.moveTo(100, 150);
ctx.lineTo(200, 10);
ctx.lineTo(275, 250);
ctx.lineTo(380, 150);
ctx.strokeStyle = 'red';
ctx.setLineDash([10, 5])
ctx.stroke();
ctx.closePath();

canvas12

二、画矩形

1、绘制空心矩形有三种方法

第一种跟绘制三角形思路是一样的;第二种是strokeRect方法绘制;第三种是stroke()和rect()方法。
下面看一下三种方式绘制的空心矩形:

// 绘制三角思路绘制矩形        // strokeRect(x,y,width,height)     // stroke()和rect()     
ctx.beginPath();             ctx1.beginPath();                   ctx2.beginPath();        
ctx.moveTo(50,50);           ctx1.strokeRect(50,50,100,100)      ctx2.rect(50,50,100,100);     
ctx.lineTo(150,50);          ctx1.closePath();                   setTimeout(() => {        
ctx.lineTo(150,150);                                                ctx2.stroke();        
ctx.lineTo(150,150);                                             }, 2000);           
ctx.lineTo(50,150);                                              ctx2.closePath();          
ctx.lineTo(50,50);            									
ctx.stroke();           
ctx.stroke();          
ctx.closePath();    

rect()暂时生成了矩形,但必须调用stroke()方法才会绘制出来
三种方式绘制效果如图:
canvas6

2、绘制填充矩形有俩种方法:

第一种是fillRect()和fillStyle()方法;第二种是rect()和fill()方法。
下面看一下两种方式绘制的空心矩形:

// fillRect()和fillStyle()填充矩形   // rect()和fill()填充矩形
ctx.beginPath();                    ctx1.beginPath();
ctx.fillStyle = 'skyblue';          ctx1.rect(50, 50, 100, 100);
ctx.fillRect(50, 50, 100, 100);     setTimeout(() => {
ctx.closePath();                        ctx1.fill();
                                    }, 2000);                              
                                    ctx1.closePath();

fillStyle()填充颜色一定要写在生成矩形fillRect()之前,否则颜色不生效
fill()方法和stroke()方法都是用来绘制出来形状,只不过前者是填充绘制,后者是用线轮廓。
两种方式绘制效果如图:
canvas7

三、画圆弧⌒⚪

1、画圆弧一般有两种方式

第一种:
arc(x, y, radius, startAngle, endAngle, anticlockwise)方法生成⚪⌒,然后stroke()方法绘制。
x,y:圆形坐标
radius:半径
startAngle:初始角度
endAngle:结束角度
anticlockwise:false顺时针或true逆时针(默认为false)
第二种:
先是一般由moveTo()或lineTo()方法提供起始点,然后arcTo(x1,y1,x2,y2,radius)方法来绘制圆弧。
x1,y1:两切线交点坐标
x2,y2:结束点坐标
radius:半径

// 1、arc()绘制圆
ctx.beginPath();
ctx.arc(100, 100, 50, 0, [(Math.PI) / 180] * 360); // (Math.PI) / 180 = 1°
ctx.stroke(); // 如果此处改为使用fill()方法,那么将会绘制出填充的圆
ctx.closePath();
// 2、arc()绘制圆弧
ctx1.beginPath();
ctx1.arc(100, 100, 50, 0, [(Math.PI) / 180] * 90); // (Math.PI) / 180 = 1°
ctx1.stroke();
ctx1.closePath();
// 3、arcTo()绘制圆弧
ctx2.beginPath();
ctx2.moveTo(100, 100); // 定义线段的起点
ctx2.arcTo(150, 50, 200, 200, 45); // 切线交点坐标为(150,50),结束点为(200,200)
ctx2.lineWidth = 1;
ctx2.stroke();
ctx2.closePath();
// 辅助线
ctx2.beginPath();
ctx2.moveTo(100, 100);
ctx2.lineTo(150, 50);
ctx2.lineTo(200, 200);
ctx2.strokeStyle = 'red';
ctx2.stroke();
ctx2.closePath();

注意事项:

  1. arcTo()方法是用“开始点”、“控制点”和“结束点”三点所形成夹角,绘制与夹角的两边相切且半径为radius的圆弧。控制点:夹角俩边相交点。
  2. 弧线的起点是“开始点所在边与圆的切点”,而弧线的终点是“结束点所在边与圆的切点”。
  3. arcTo()方法绘制的弧线是两个切点之间长度最短的那个圆弧。
  4. 如果开始点不是弧线起点,arcTo()方法还将添加一条当前端点到弧线起点的直线线段。也就是说,开始点坐标不一定是弧线起点坐标。通俗点讲就是:开始点到弧线起点会有一段直线线段。

两种方式绘制结果:
canvas8

2、画椭圆

用ellipse(x,y,radiusX,radiusY,rotation,startAngle,endAngle,anticlockwise)方法来绘制椭圆。
x,y:圆心坐标
radiusX:x轴半径
radiusY:y轴半径
rotation:椭圆旋转角度
startAngle:开始绘制点
endAngle:结束绘制点
anticlockwise:false顺时针或true逆时针(默认false)

// 椭圆
ctx.beginPath();
// 旋转角度[(Math.PI)/180]*60	起点[(Math.PI)/180]*0   终点[(Math.PI)/180]*360
ctx.ellipse(100,100,50,100, [(Math.PI)/180]*60, [(Math.PI)/180]*0, [(Math.PI)/180]*360);
ctx.stroke();
ctx.closePath();

// 给椭圆填充色stroke()换成fill()
// ctx.fillStyle = 'skyblue'
// ctx.fill()

canvas9

四、绘制文本

1、strokeText(), fillStroke()绘制文本

使用strokeText(text,x,y,maxWidth)方法绘制描边文本。
使用fillStroke(text,x,y,maxWidth)方法绘制填充文本。
text:需要绘制的文本
x,y:文本左下角起始坐标
maxWidth:文本最大宽度

// 绘制描边文本									// 绘制填充文本
ctx.beginPath();								ctx1.beginPath();
ctx.font = '50px Verdana';						ctx1.font = '50px Verdana';
ctx.strokeText('Hello Canvas!', 30, 180, 400);	ctx1.fillText('Hello Canvas!', 30, 180, 400);
ctx.closePath();								ctx1.closePath();
ctx.beginPath();
ctx.font = '20px Verdana';
ctx.strokeText('Helvas!', 30, 280, 400);
ctx.closePath();

canvas13

2、文本样式

.font设置文本大小和字体。
.textAlign设置水平对齐方式,值可选left/right/center/start/end。对齐方式以strokeText()方法中坐标参数为参考。

// 绘制水平居中描边文本
ctx.beginPath();
ctx.font = '50px Verdana';
ctx.textAlign = 'center';
ctx.strokeText('Hello Canvas!', 200, 200, 400);
ctx.closePath();
// 辅助线
ctx.beginPath();
ctx.moveTo(200,0);
ctx.lineTo(200, 400);
ctx.setLineDash([10, 5])
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(0,200);
ctx.lineTo(400, 200);
ctx.setLineDash([10, 5])
ctx.stroke();
ctx.closePath();

strokeText()绘制文本的坐标在画布的中心点(200,200),textAlign = center居中对齐则是以中心点为参考水平对齐。
canvas14
.textBaseline设置垂直对齐方式,值可选alphabetic/top/hanging/middle/ideographic/bottom
.direction:设置文本绘制方向,值可选ltr(left to right)和rtl(right to left)。

// 水平左对齐,垂直上对齐
ctx.beginPath();
ctx.font = '20px Verdana';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.strokeText('Hello!', 0, 200, 400);
ctx.closePath();
// 水平居中,垂直居中
ctx.beginPath();
ctx.font = '20px Verdana';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.strokeText('Hello Canvas!', 200, 200, 400);
ctx.closePath();
// 水平右对齐,垂直下对齐 + 文本绘制方向rtl`(right to left)
ctx.beginPath();
ctx.font = '20px Verdana';
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.direction = 'rtl';
ctx.strokeText('Canvas!', 400, 200, 400);
ctx.closePath();

canvas16
measureText(text)方法测量文本的宽度。
text:测量的文本
注意:不是必须显示出文本来才能计算文本的长度,测量结果也不受文本的最大宽度等外界因素的影响,文本长度的测量结果只和文本的font参数相关。

五、样式补充

1、线性渐变色

使用createLinearGradient(x1,y1,x2,y2)来创建线性渐变色。
x1,y1:渐变色起点坐标
x2,y2:终点坐标
使用addColorStop(offset,color)添加渐变色。
offset:偏移值
color:渐变色

// 横向线性渐变色
ctx.beginPath();
const gradient = ctx.createLinearGradient(0,0,400,0);
gradient.addColorStop(0, 'skyblue');
gradient.addColorStop(1, '#fffc96');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 400, 400)
ctx.closePath();

线形渐变步骤就是:先是使用createLinearGradient创建一个线性渐变对象;然后使用addColorStop添加颜色;然后使用fillStyle设置填充颜色(就是线形渐变对象);最后使用fillRect填充。
canvas7

2、径向渐变

使用createRadialGradient(x1,y1,r1,x2,y2,r2)方法来创建渐径向渐变色。
x1,y1:开始圆的圆心坐标
r1:开始圆的半径
x2,y2:结束圆的圆心坐标
r2:结束圆的半径

// 径向渐变
ctx.beginPath();
const gradient = ctx.createRadialGradient(200,200, 100, 200, 200, 200);
gradient.addColorStop(0, 'skyblue');
gradient.addColorStop(1, '#fffc96');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 400, 400);
ctx.closePath();

径向渐变步骤就是:同线形渐变是一样的。先是使用createRadialGradient创建一个径向渐变对象;然后使用addColorStop添加颜色;然后使用fillStyle设置填充颜色(就是径向渐变对象);最后使用fillRect填充。
canvas18

3、阴影样式

shadowOffsetX = 数字:设置阴影在X轴上的延申距离,正值表示阴影向x轴正方向延申,负值表示阴影向x轴负方向延申。
shadowOffsetY = 数字:设置阴影在Y轴上的延申距离,正值表示阴影向y轴正方向延申,负值表示阴影向y轴负方向延申。
shadowBlur = 数字:设定阴影的模糊度,默认为0。
shadowColor = '颜色':设置阴影的颜色,默认是全透明色。

// 绘制带阴影的线段:
ctx.moveTo(50, 50)
ctx.lineTo(100, 50)
ctx.shadowOffsetX = 10 // 向x轴正方向平移10像素
ctx.shadowOffsetY = 10 // 向y轴正方向平移10像素
ctx.shadowColor = '#ccc' // 设置阴影颜色
ctx.shadowBlur = 3 // 设置阴影模糊度
ctx.lineWidth = 6
ctx.stroke()
// 绘制带阴影的文本:
ctx.lineWidth = 1
ctx.font = '30px Verdana'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.strokeText('Hello Canvas!', 200, 200, 400)

效果:
canvas20

4、添加指定元素

使用createPattern(pattern,type)方法添加指定元素。
pattern:要添加的元素,可以是图片,视频,canvas对象
type:绘制类型,可选repeat/no-repeat/repeat-x(沿x轴平铺)/repeat-y(沿y轴平铺)

// 添加图片
const img = new Image();
img.src = "https://phper-1234567890.cos.ap-guangzhou.myqcloud.com/logoCopy.png";
img.onload = function () {
   const ptrn = ctx.createPattern(img, 'repeat');
   ctx.fillStyle = ptrn;
   ctx.fillRect(0, 0, 400, 400);
};

填充结果:
canvas9

六、绘制图片

1、使用drawImage()方法绘制图片

drawImage(img,x,y,width,height,sx,sy,swidth,sheight)可以接收3-9个参数进行拉伸、裁剪等。
img:需要绘制的图片(必填参数)
x,y:绘制的坐标(必填参数)
width,height:图片拉伸宽度、高度
sx,sy:开始裁切的位置
swidth,sheight:要裁切图像的宽高

// 1、绘制基础图片
var img = new Image();
img.src = 'https://phperzlz-1234567890.cos.ap-guangzhou.myqcloud.com/apply/logo2.png';
img.onload = function () {
    ctx.drawImage(img, 0, 0); // 在(0,0)处绘制原图
};
// 2、绘制拉伸图片
var img = new Image();
img.src = 'https://phperzlz-1234567890.cos.ap-guangzhou.myqcloud.com/apply/logo2.png';
img.onload = function () {
    ctx.drawImage(img, 0, 0, 400, 400); // 在(0,0)处绘制原图,拉伸至(400, 400)的图片
};
///3、绘制裁切拉伸图片
var img = new Image();
img.src = 'https://phperzlz-1234567890.cos.ap-guangzhou.myqcloud.com/apply/logo2.png';
img.onload = function () {
	// 在(50,50)处裁切,裁切成(100,100)的图片;在(0,0)处绘制原图,拉伸至(400, 400)的图片
    ctx.drawImage(img, 50, 50, 200, 200,0, 0, 400, 400); 
};
// 4、通过拿到image的DOM元素,来绘制图片
const img = document.getElementById('img');
img.onload = function () {
    ctx.drawImage(img,0, 0); // 在(0,0)处绘制原图
};

注意:先是裁切参数后绘制参数
效果:
canvas21
绘制图片除了通过new Image对象来绘制,还可以通过DOM来绘制图片,效果是一样的:
canvas22

2、绘制图片的合成、保存和还原绘画状态、变形、裁剪

合成:在绘制多个图案的时候,就需要考虑先后显示问题。通过globalCompositeOperation来控制谁覆盖谁,值可选:
source-over:在已有图像之上绘制新图像(默认值)
source-in:只会展示新图像与已有图像重叠的部分
source-out:在已有图像之外显示新图像,只有已有图像之外的新图像部分显示,已有图像是透明的
source-atop:在已有图像顶部显示新绘制的图像。已有图像位于新绘制图像之外的部分是不可见的
destination-over:与source-over相反,在已有图像之后绘制新图像
destination-in:与source-in相反,显示的是最开始的已有图像
destination-out:在新绘制图像之外显示已有图像。只有新图像之外的已有图像部分显示,新绘制图像是透明的
destination-atop:在新绘制图像顶部显示已有图像。已有图像位于新绘制图像之外的部分是不可见的
lighter:折叠图像的颜色是有颜色值相加得来的
xor:两个图像重叠部分变为透明的

// 1、source-over
ctx.arc(350, 200, 200, 0, [(Math.PI) / 180] * 360)
ctx.fillStyle = 'skyblue'
ctx.globalCompositeOperation = 'source-over'
ctx.fill()
ctx.beginPath()
ctx.arc(200, 400, 200, 0, [(Math.PI) / 180] * 360)
ctx.fillStyle = '#fffc96'
ctx.globalCompositeOperation = 'source-over'
ctx.fill()
ctx.closePath();
// 2、xor
ctx.arc(350, 200, 200, 0, [(Math.PI) / 180] * 360)
ctx.fillStyle = 'skyblue'
ctx.globalCompositeOperation = 'source-over'
ctx.fill()
ctx.beginPath()
ctx.arc(200, 400, 200, 0, [(Math.PI) / 180] * 360)
ctx.fillStyle = '#fffc96'
ctx.globalCompositeOperation = 'xor'
ctx.fill()

canvas23


更多详细内容:
https://blog.csdn.net/nvgis/article/details/127316552

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

F2E_zeke

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

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

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

打赏作者

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

抵扣说明:

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

余额充值