文章目录
详细介绍画布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();
绘制结果如图:
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();
线段样式效果如图:
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:在第二个效果图中,没有开辟新路径,导致第二条线形效果覆盖了第一条的样式效果。
4、画线形三角
画线形三角也是用画线的思路,需要注意首尾点连接起来即可:
ctx.beginPath();
ctx.moveTo(60,60);
ctx.lineTo(150,60);
ctx.lineTo(150,150);
ctx.lineTo(60,60);
ctx.stroke();
ctx.closePath();
绘制效果如图:
如果要添加样式也是一样的:
// 画三角 // 闭合处显示的更衔接一点
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();
绘制效果:
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();
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();
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();
二、画矩形
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()方法才会绘制出来
三种方式绘制效果如图:
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()方法都是用来绘制出来形状,只不过前者是填充绘制,后者是用线轮廓。
两种方式绘制效果如图:
三、画圆弧⌒⚪
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();
注意事项:
- arcTo()方法是用“开始点”、“控制点”和“结束点”三点所形成夹角,绘制与夹角的两边相切且半径为radius的圆弧。控制点:夹角俩边相交点。
- 弧线的起点是“开始点所在边与圆的切点”,而弧线的终点是“结束点所在边与圆的切点”。
- arcTo()方法绘制的弧线是两个切点之间长度最短的那个圆弧。
- 如果开始点不是弧线起点,arcTo()方法还将添加一条当前端点到弧线起点的直线线段。也就是说,开始点坐标不一定是弧线起点坐标。通俗点讲就是:开始点到弧线起点会有一段直线线段。
两种方式绘制结果:
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()
四、绘制文本
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();
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居中对齐则是以中心点为参考水平对齐。
.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();
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
填充。
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
填充。
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)
效果:
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);
};
填充结果:
六、绘制图片
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)处绘制原图
};
注意:先是裁切参数后绘制参数
效果:
绘制图片除了通过new Image对象来绘制,还可以通过DOM来绘制图片,效果是一样的:
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()
更多详细内容:
https://blog.csdn.net/nvgis/article/details/127316552