创建canvas画布
css:
canvas{
border:3px solid blue;
}
html:
<canvas width="700" height="700" id="myCanvas">
您的浏览器不支持canvas,请更换浏览器访问!
</canvas>
Javascript:
<script>
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
</script>
Point:
-
canvas标签是一个双标签,其内部写的是当浏览器不支持canvas时显示的内容,可以插入其他元素,比如文字,图片等。
-
canvas画布的宽高应该在其标签内定义,不能在其CSS内定义,否则其绘制的图像会按照300*150发生缩放。
-
所有绘图行为都在script标签中进行。
let ctx = canvas.getContext("2d");
所有canvas的API都是定义在该对象上的,其中参数可以是2D,或者3D.
Canvas绘制图像
canvas的绘制图形有两种方式:
- context.fill()
fill()指的是填充,其默认颜色是黑色,可以在使用fill()之前使用fillStyle()方法改变填充颜色,如果是闭合图像,那么就直接填充。如果是非闭合的路径,则fill()先帮其闭合,然后填充。
ctx.fillStyle = "red";//设置填充色
ctx.fillRect(10,10,100,100);//绘制一个填充矩形
- context.stroke()
stroke()方法会实际的绘制出moveTo()和lineTo()方法的路径。默认颜色是黑色,在绘制之前,可以使用strokeStyle()进行设置。
ctx.strokeStyle = "red";//设置边框填充色
ctx.strokeRect(10,10,100,100);//绘制空心矩形
绘制矩形
绘制基本矩形
ctx.fillRect(x,y,height,width)//实心矩形
ctx.strokeRect(x,y,height,width)//空心边框
- x:起点的x坐标(即左上角的x坐标)
- y:起点的y坐标(即左上角的y坐标)
- height:矩形的高
- width:矩形的宽
改变颜色
ctx.fillStyle = "red";//设置填充颜色
ctx.fillRect(10,10,100,100);
ctx.strokeStyle = "red";//设置边框颜色
ctx.strokeRect(200,200,100,100);
Point:
- ctx.fillStyle = "red"用来设置填充颜色
- ctx.strokeStyle = "red"用来设置边框颜色
- 这些描述都要放在绘制图形之前声明
擦除矩形区域
-
ctx.clearRect(x,y,height,width)
ctx.clearRect(50,50,200,200)//绘制一个矩形区域并擦除该区域之前的内容
绘制圆形
绘制基本圆
实心圆
-
ctx.arc(x,y,radius,starAngle,endAngle,anticlockwise)
- x:圆心的x坐标
- y:圆心的y坐标
- radius:半径
- startAngle:开始角度
- endAngle:结束角度
- anticlockwise:旋转方向,
- true:逆时针(可选参数,默认为false)
- false:顺时针
ctx.fillStyle = "red"; //设置填充色 ctx.arc(200,200,50,0,Math.PI*2,true);//绘制圆形 ctx.fill();//填充
空心圆
ctx.beginPath()
ctx.arc(200,200,50,0,Math.PI*2,true);
ctx.strokeStyle = "red";
ctx.closePath();
ctx.stroke();
Point
上面用到了路径,实际ctx.arc()相当于是一个lineTo()的一个集合。利用其绘制出一个圆形,最后要关闭(ctx.cloePath()),以及要(stroke())才能完全绘制出该图形。
非完整圆
如果要绘制一个非完整的圆,比如一个实心半圆,该如何绘制呢?
答案是使用arc方法中的startAngle和endAngle来改变。
ctx.fillStyle = "red";
ctx.arc(200,200,50,0,Math.PI,true);
空心圆形
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.arc(400,400,100,0,Math.PI);
ctx.closePath();
ctx.stroke();
绘制线段
-
moveTo(x,y):把画笔移动至画布的制定位置,不创建线条
-
lineTo(x,y):添加一个点(x,y)
-
stroke():按照之前添加的点绘制路径
ctx.strokeStyle = "red";//设置填充色 ctx.moveTo(0,0);//将画笔移动至(0,0) ctx.lineTo(100,100);//添加一个点(100,100) ctx.stroke();//按点绘制路径
Point
-
如果没有在第一次指定moveTo(x,y),则第一个lineTo(x,y) == moveTo(x,y)
-
如果在lineTo()后没有使用moveTo()方法,则依次连接,eg:
ctx.moveTo(0,0); ctx.lineTo(10,10); ctx.lineTo(20,20); ctx.lineTo(30,30); ctx.stroke();
则画出后是一段从点(0,0)=>(10,10)=>(20,20)=>(30,30)的一段折线。
- ctx.beginPath():开始一段路径
- ctx.closePath():闭合路径,即canvas会自动将未闭合的线段的首尾连接起来。
eg(一个三角形):
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(10,10);
ctx.lineTo(20,20);
ctx.closePath();
ctx.stroke();
案例(六边形):
var n = 0;
var dx = 150;//路径开始x坐标
var dy = 150;//路径开始y坐标
var s = 100;//边长
ctx.beginPath();//路径开始
ctx.fillStyle = 'pink';//设置填充色
ctx.strokeStyle = 'rgb(0,0,100)';//设置边框颜色
var dig = Math.PI / 3;//计算偏移角度
for (var i = 0; i < 6; i++) {
var x = Math.sin(i * dig);//计算以下个点的x坐标的增量
var y = Math.cos(i * dig);//计算下一个点的y坐标的增量
ctx.lineTo(dx + x * s, dy + y * s);//绘制下一个点
//console.log( x ,y )
}
ctx.closePath();//闭合整个路径
ctx.fill();//设置填充
ctx.stroke();//绘制路径
Point
这个例子用了一点数学知识,主要是:
for (var i = 0; i < 6; i++) {
var x = Math.sin(i * dig);//计算以下个点的x坐标的增量
var y = Math.cos(i * dig);//计算下一个点的y坐标的增量
ctx.lineTo(dx + x * s, dy + y * s);//绘制下一个点
//console.log( x ,y )
}
其原理是利用了简单的沟股定理,计算下一个点的坐标
线性渐变
- let lg = ctx.createLinearGradient(xStart,yStart,xEnd,yEnd)
- lg.addColorStop(offset,color)
- xSart:渐变开始点的x坐标
- yStart:渐变开始点的y坐标
- xEnd:渐变结束点的x坐标
- yEnd:渐变结束点的y坐标
- offset:设定的颜色离渐变结束点的偏移量
- color:绘制的颜色
eg: let lg = ctx.createLinearGradient(0,0,100,200); lg.addColorStop(0,"#E55D87"); lg.addColorStop(1,"#5FC3E4"); ctx.fillStyle = lg; ctx.fillRect(0,0,200,200);
Point
- 线性渐变仅仅是相当于设置填充色,在定义完填充色之后,我们还需要将填充设置为该线性渐变
(ctx.fillStyle = gl) - 由于线性渐变仅仅是设置填充色,所以具体的背景容器还需要我们自己设置,比如设置一个矩形作为容器
ctx.fillRect(0,0,200,200) - 由于渐变背景的坐标是相对于画布,而图形的坐标也是相对于画布,所以在定义背景时,需要注意与图形的坐标搭配以达到需要的效果
径向渐变
let rg = ctx.createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd)
rg.addCOlorStop(offset,color);
-
xSart:发散开始的圆心x坐标
-
yStart:发散开始的圆心y坐标
-
radiusStart:发散开始圆的半径
-
xEnd:发散结束圆心的x坐标
-
yEnd:发散结束圆心的y坐标
-
radiusEnd:发散结束圆的半径
-
offset:设定的颜色结束点的偏移量(0-1)
-
color:绘制颜色
var g1 = ctx.createRadialGradient(200, 150, 0, 200, 150, 200); g1.addColorStop(0.1, '#F09819'); g1.addColorStop(1, '#EDDE5D'); ctx.fillStyle = g1; ctx.beginPath(); ctx.arc(200, 150, 100, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill();
图形变形
缩放
-
scale(x,y)
-
x:x坐标轴按x比例缩放
-
y:y坐标轴按y比例缩放
-
前面参数的是按倍数来衡量的(0.5=>50%,1=>100%,2=>200%)
eg:
ctx.strokeStyle = "red";
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);
Point
- 缩放一个图形,先使用
ctx.scale(x,y)对画布进行缩放处理,后面再创建要缩放的工具ctx.strokeRect(5,5,25,15);。 - 缩放的原点都是在(0,0)位置。
旋转
-
ratate(angle)
-
angle:旋转的角度,以弧度计。
eg:
ctx.strokeStyle = "red";
// ctx.strokeRect(5,5,200,200);
ctx.rotate(20*Math.PI/180);//旋转5°
ctx.strokeRect(5,5,200,300);
Point:
默认的旋转中心是在(0,0)位置。下面介绍如何改变旋转中心。
平移
-
translate(x,y)
-
x:坐标原点向x轴平移x
-
y:坐标原点想y轴平移y
eg1(以矩形中心为原点旋转):
ctx.strokeStyle = "red";
//以(0,0)为原点绘制一个起点为(200,200),边长为200的正方形
ctx.strokeRect(200,200,200,200);
//移动原点至(300,300),即上面矩形的中心位置
ctx.translate(300,300);
//将画布进行一个45°的旋转,得到一个旋转后的图形
ctx.rotate(45*Math.PI/180);
//将原点坐标改为(0,0)
ctx.translate(-300,-300);
//绘制出旋转后的矩形
ctx.strokeRect(200,200,200,200);
eg2(以矩形中心为原点缩放图形):
ctx.strokeStyle = "red";
ctx.strokeRect(200,200,100,100);
ctx.translate(250,250);
ctx.scale(2,2);
ctx.translate(-250,-250);
ctx.strokeRect(200,200,100,100);
Point
上面提到的,scale,rotate方法的操作都是对画布而言的,貌似整的canvas的思维都是这样,需要我们有反向思考的能力。
组合图形
globalCompositeOperation = type
后绘制的图形如何与之前的图像叠加渲染,取决于type。下面是type的种类:
- source-over(默认):在原图形之上绘制(覆盖)。
- destination-over:在原图形之下绘制。
- source-in:显示原有图形和新图形的交集,新图形在上,所以颜色为新图形颜色
- destination-in:显示原图形和新图形的交集,原图形在上,所以颜色为原图形的颜色
- source-out:只显示新图形的非交集部分
- destination-out:只显示旧图形的非交集部分
- source-atop:显示原图形和交集部分,新图形在上,所以交集部分为新图形颜色
- destination-atop:显示新图形和交集部分,新图形在上,所以交集部分为新图形颜色
- lighter:显示原有图形和新图形,交集部分做颜色叠加
- copy:只显示新图形
eg:
ctx.globalCompositeOperation = "lighter";
ctx.fillStyle = "red";
ctx.fillRect(50,50,200,200);
ctx.fillStyle = "blue";
ctx.fillRect(100,100,200,200);
Point
该属性与上面的ctx.translate(x,y)一样,一旦作用,就对下面的元素都起作用,如果要还原,请在此使用该属性还原。
阴影
- shadowOffsetX:设置或返回阴影距形状的水平距离(默认值为0) -shadowOffsetY:设置或返回阴影形状的垂直距离(默认值为0)
- shadowColor:设置或返回阴影的颜色
- shadowBlur:设置或返回阴影的模糊级别(值越大越模糊)
eg: ctx.shadowOffsetX=20; ctx.shadowColor="blue"; ctx.shadowBlur = 50; ctx.fillStyle = "red"; ctx.fillRect(100,100,200,200);
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.fillStyle = "yellow";
ctx.fillRect(400,400,100,100);
Point
相同的是,阴影属性也是对一下的所有图形都生效。要取消阴影效果,必须重置:
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
图像操作
- drawImage(img,x,y):在画布上定位图像
- drawImage(img,x,y,width,height):在画布上定位图像,并规定图像的宽度和高度
- drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
- img:规定要使用的图像,画布或视频
- sx(可选):开始剪切的x坐标位置
- sy(可选):开始剪切的y坐标位置
- swidth(可选):被剪切的图像的宽度
- sheight(可选):被剪切的图像的高度
- x:在画布上放置img的x坐标位置
- y:在画布上放置img的y坐标位置
- width(可选):要使用的图像的宽度。(拉伸或压缩)
- height(可选):要使用的图像的高度。(拉伸或压缩)
eg:
let img = new Image();
img.src = "expi.jpg";
img.onload = function(){
ctx.drawImage(img,100,100,200,200,200,200,200,200);
}
Point
-
img应该是一个img对象,
img = new Image()或者是一个Image的DOM标签document.getElementById("img")(实际也是一个Image对象,因为在HTML中,每创建一个img标签,就会自动创建一个Image对象。) -
在使用该标签时,应当使用,Image对象的回调函数onload,否则不能渲染成功,其原因是:
let img = new Image(); img.src = "expi.jpg";这个过程中,对img.src赋值的时候,可能还没有赋值完成,就进行了
ctx.drawImage语句,由于还没赋值完成,此使img.src还是空,所以无法渲染出来。
图像平铺
- createPattern(image,type)
type:
- no-repeat:不平铺
- repeawt-x:按x轴方向平铺
- repeat-y:按y轴方向平铺
- repeat:全方向平铺
eg: let img = new Image; img.src = "beauty.png"; img.onload = function(){ let pattern = ctx.createPattern(img,"repeat-x"); ctx.fillStyle = pattern; ctx.fillRect(10,10,500,500); }
Point
- 相同的是,必须要配合Image的oload回调函数来使用,道理同上。
图像剪切
- clip()
该函数的使用方法:
- 创建剪切区域:ctx.rect(x,y,width,heigth)
- 设置剪切部分的填充色:ctx.fillStyle = "pink"
- 进行填充:ctx.fill();
- 进行剪切:ctx.clip();
eg:
ctx.fillStyle = "yellow";
ctx.fillRect(0,0,300,300);
ctx.rect(100,100,500,500);
ctx.fillStyle = "pink";
ctx.fill();
ctx.clip();
ctx.fillStyle = "blue";
ctx.fillRect(0,0,200,200);
Point
-一旦剪切了某个区域,则之后的所有绘图都会被限制在被剪切区域内进行(不能访问画布上的其他区域)。我们也可以在使用clip()方法之前通过使用save()方法将之前的画布保存下来,并在任意时间使用restored()方法。
绘制文字
- fillText(text,x,y):绘制实心文字
- x:文字的中心点x坐标
- y:文字的中心点y坐标
- strokeText():绘制文字描边(空心文字)
- textAlign:设置或返回文字内容的当前对齐方式(注意:其都是相对于该文字对象的中心),其值有:
- start:默认。文本在指定的位置开始。
- end:文本在指定的位置结束。
- left:文本左对齐。
- center:文本的中心被放置在指定的位置。
- right:文本右对齐。
- textBaseline:设置会返回在绘制文本时使用的当前文字基线,其值有:
- Bottom:文本基线是 em 方框的底端。
- Top:文本基线是 em 方框的顶端。
- Middle:文本基线是 em 方框的正中。
- Alphabetic:默认。文本基线是普通的字母基线。
- hanging:文本基线是悬挂基线。
- font:设置或返回文本内容的当前文字属性
eg:
ctx.font = "40px Arial";
ctx.textAlign = "center";
ctx.fillText("Hello World",200,200);
ctx.strokeText("Hello World",200,300);
console.log(ctx.textBaseline);
看看这
更多有趣文章都在公众号-《全站学习小师兄》