canvas学习
canvas....学前端的看到这个标签就会有一种高大上的感觉,因为这个标签出来的时候,项目大部分时候用于复杂交互,游戏等比较深入的领域,不学好canvas,都不好自称自己是合格的前端工程师....
一些注意点:
- Canvas是基于状态的绘制
- 设置
canvas
的大小只有2种方法,直接在标签中设置和通过js设置,其余都是无效的 - 每次变换要保存状态,变换结束读取状态
基础
// 获取绘制画布
let canvas = document.getElementById('canvas')
let context = canvas.getContext('2d') //获取画笔
//设置绘制图形
context.beginPath(); // Canvas是基于状态的绘制,所以每次绘制应该重设状态
context.moveTo(100, 100) //把笔尖放到100px 100px
context.lineTo(600, 600) // 从100,100移动到600,600
context.closePath() //绘制结束调用,自动闭合图形
// 设置绘制样式
context.lineWidth = 5 // 设置线宽5px
context.strokeStyle = '#AA394C' //设置颜色
context.fillStyle = "black"; //设置背景填充颜色是黑色
// 绘制
context.fill(); //填充
context.stroke() //画线
// 保存调用状态
context.save();
context.restore();
//一些js封装好的绘制函数
context.rect(x,y,width,height); //绘制矩形
context.fillRect(x,y,width,height)//直接填充出来一个矩形
context.strokeRect(x,y,width,height) //直接画一个矩形
线条
lineCap 定义上下文中线的两端端点,可以有以下 3 个值:
- butt:默认值,端点是垂直于线段边缘的平直边缘。
- round:端点是在线段边缘处以线宽为直径的半圆。
- square:端点是在线段边缘处以线宽为长、以一半线宽为宽的矩形。
lineJoin 定义两条线相交产生的拐角,可将其称为连接。在连接处创建一个填充三角形,可以使用 lineJoin 设置它的基本属性:
- miter:默认值,在连接处边缘延长相接。miterLimit 是角长和线宽所允许的最大比例(默认是 10)。
- bevel:连接处是一个对角线斜角。
- round:连接处是一个圆。
颜色
除了直接设置颜色,还有渐变色的设置
渐变色的设置分2种:
- 线性渐变,基于2个端点之间渐变
- 径向渐变,基于2个同心圆之间的渐变
填充的时候也可以填充纹理或者说就是设置图片背景
下面介绍api
//添加线性渐变渐变线
var grd = context.createLinearGradient(xstart,ystart,xend,yend);
// 为渐变线添加关键色(类似于颜色断点)
grd.addColorStop(stop,color); //stop传递0~1浮点数
// 应用渐变
context.fillStyle = grd;
context.strokeStyle = grd;
//例子:
var grd = context.createLinearGradient(200,300,600,300);
grd.addColorStop(0,"black");
grd.addColorStop(0.5,"white");
grd.addColorStop(1,"black");
context.fillStyle = grd;
context.fill();
//添加径向渐变渐变圆
var grd = context.createRadialGradient(x0,y0,r0,x1,y1,r1);
//为渐变线添加关键色(类似于颜色断点)
grd.addColorStop(stop,color)
context.fillStyle = grd;
context.strokeStyle = grd;
//例子:
var grd = context.createRadialGradient(400,300,100,400,300,200);
//添加颜色断点
grd.addColorStop(0,"olive");
grd.addColorStop(0.25,"maroon");
grd.addColorStop(0.5,"aqua");
grd.addColorStop(0.75,"fuchsia");
grd.addColorStop(0.25,"teal");
//应用渐变
context.fillStyle = grd;
context.fillRect(100,100,600,400);
// 填充纹理(背景图片)
context .createPattern(img,repeat-style) // 第一个参数是new Image(),或者canvas和video对象实例,第二个参数是重复方式
//例子
var pattern = context.createPattern(img, "repeat");
context.fillStyle = pattern;
context.fillRect(0,0,800,600);
弧度
- 标准圆弧 arc()
context.arc(x,y,radius,startAngle,endAngle,anticlockwise)
前面三个参数,分别是圆心坐标与圆半径。startAngle、endAngle使用的是弧度值(Math.PI) (上1.5* Math.PI,右0* Math.PI,下0.5Math.PI,左1Math.PI)
anticlockwise 代表顺时针还是逆时针绘制,true逆时针,false顺时针,缺省值为false
// 例子,一个有弧度的矩形封装函数
function drawRoundRect(cxt, x, y, width, height, radius){
cxt.beginPath();
cxt.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
cxt.lineTo(width - radius + x, y);
cxt.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
cxt.lineTo(width + x, height + y - radius);
cxt.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2);
cxt.lineTo(radius + x, height +y);
cxt.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI);
cxt.closePath();
}
- 切线画弧 arcTo()
arcTo(x1,y1,x2,y2,radius)
这个函数以给定的半径绘制一条弧线,圆弧的起点与当前路径的位置到(x1, y1)点的直线相切,圆弧的终点与(x1, y1)点到(x2, y2)的直线相切
-
二次贝塞尔曲线
quadraticCurveTo(cpx,cpy,x,y)
(cpx, cpy)是控制点,(x, y)是终止点,一般搭配moveTo设置一个初始点使用 -
三次贝塞尔曲线
context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
常用来绘制波浪效果
变换
平移变换、旋转变换、缩放变换都属于坐标变换,或者说是画布变换
。因此,缩放并非缩放的是图像,而是整个坐标系
、整个画布!就像是对坐标系的单位距离缩放了一样,所以坐标和线条都会进行缩放
平移变换 translate()
// 直接上例子
context.translate(100,100); // 平移变换100,100
context.fillRect(100,100,200,100); //现在这个矩形在200,200的位置
// 有一个注意点: 如果平移后继续平移
context.translate(100,100);
context.fillRect(100,100,200,100); //这时候是300,300,因为基于状态绘制的
//所以需要状态保存读取
context.save();
context.translate(200,200);
context.fillRect(100,100,200,100);
context.restore();
旋转变换 rotate()
rotate(deg)
传入的是弧度Math.PI
,已坐标系原点为圆心的顺时针旋转,所以使用rotate()前通常使用translates()
平移坐标系确认圆心
缩放变换 scale()
scale(sx,sy)
传入两个参数,分别是水平方向和垂直方向上对象的缩放倍数
需要注意的是:
- 缩放时,图像左上角坐标的位置也会对应缩放。
- 缩放时,图像线条的粗细也会对应缩放。
文本
// font参数值 所有都有默认值,具体设置查询相应文档
context.font =
"[font-style] [font-variant] [font-weight]
[font-size/line-height] [font-family]"
//1. 使用`font`设置字体。
context.font = "50px serif";
//2. 使用`fillStyle`设置字体颜色。
context.fillStyle = "#00AAAA";
//3. 使用`fillText()`方法显示填充字体。
context.fillText("《CANVAS--Draw on the Web》",50,300);
// 4. 使用`strokeText`方法显示文本字体
context.strokeText(String,x,y,[maxlen])
文本对齐
水平对齐与起始点的关系
context.textAlign="center|end|left|right|start";
垂直对齐与 基准线的关系
context.textBaseline="alphabetic|top|hanging|middle|ideographic|bottom";
文本度量
context.measureText(txt).width
度量文本长度,可以用来实现换行
阴影效果
创建阴影效果需要操作以下4个属性:
- context.shadowColor:阴影颜色string。
- context.shadowOffsetX:阴影x轴位移。正值向右,负值向左number。
- context.shadowOffsetY:阴影y轴位移。正值向下,负值向上number。
- context.shadowBlur:阴影模糊滤镜。数据越大,扩散程度越大number。
context.globalAlpha = 0.5
设置全局透明度0-1之间,如果不想针对全局设置不透明度,就得在下次绘制前重置globalAlpha
裁剪
裁剪是对画布进行的,裁切后的画布不能恢复到原来的大小,所以记得save
和restore
状态
// 来个例子
//裁剪画布从(0,0)点至(50,50)的正方形
context.rect(0,0,50,50);
context.clip();
//红色圆
context.beginPath();
context.strokeStyle = "red";
context.lineWidth = 5;
context.arc(100,100,100,0,Math.PI * 2,false);
//整圆
context.stroke();
context.closePath();
//只能显示(50,50)矩形里面的红色圆弧
绘制图像
这是一个非常重要的api,可以引入图像、画布、视频,并对其进行缩放或裁剪
一共有三种表现形式:
- 三参数:context.drawImage(img,x,y)
- 五参数:context.drawImage(img,x,y,width,height)
- 九参数:context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
参数 | 描述 |
---|---|
img | 规定要使用的图像、画布或视频。 |
sx | 可选。开始剪切的 x 坐标位置。 |
sy | 可选。开始剪切的 y 坐标位置。 |
swidth | 可选。被剪切图像的宽度。 |
sheight | 可选。被剪切图像的高度。 |
x | 在画布上放置图像的 x 坐标位置。 |
y | 在画布上放置图像的 y 坐标位置。 |
width | 可选。要使用的图像的宽度。(伸展或缩小图像) |
height | 可选。要使用的图像的高度。(伸展或缩小图像) |
橡皮擦
context.clearRect(x,y,w,h)
清除指定矩形上的画布上的像素,xy为起始点,wh宽高
isPointInPath (x,y)
接收两个参数,就是一个点的坐标值,用来判断指定的点是否在当前路径中。若是,则返回true。