1.canvas基础用法
1.1 canvas概念
canvas标签相当于一个"画板",它常用于图片绘制、动画、数据可视化等。
1.2 canvas坐标系
1.3 小例子
<canvas id=“canvas” width=“400” height="400"></canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = "green";
ctx.fillRect (10, 10, 55, 50);
结果如下
注:
1).canvas标签需写全,不能简写为单标签。
2).canvas标签只有两个属性 width 和 height(当然 id、class等标签通用属性也有),canvas的大小只受width、height属性影响,css样式不起作用,如果不设置则默认为150*300。
3).canvas.getContex获取渲染上下文对象,该对象可以理解为该 “画板” 的 “绘画工具”。
2.使用 canvas 绘制图形
2.1 路径
路径指的是在 “画板“ 上产生的画痕,从开始 “下笔” 到结束,单一次在 “画板” 产生的画痕,算一个路径。
beginPath()
新建一条路径,生成之后,“绘画工具”指向新建的路径。
moveTo(x,y)
在画板坐标系上移动下笔的焦点
lineTo(x,y)
从焦点处画线到指定坐标处
stroke()
使刚刚画的路径现形
fill()
填充刚刚画的路径闭合区域
closePath()
关闭路径,"绘画工具会重新指向上下文"
例子如下
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 200;
canvas.height = 200;
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(40, 10);
ctx.lineTo(40, 40);
ctx.fill();
ctx.closePath();
document.body.appendChild(canvas);
结果
2.2 矩形
canvas提供了api绘制矩形
fillRect(x, y, width, height)
绘制一个填充的矩形
strokeRect(x, y, width, height)
绘制一个矩形的边框
rect(x, y, width, hright)
将一个矩形加入当前路径,需使用stroke等使它现形
clearReact(x, y, width, height)
清除指定矩形区域,让清除部分完全透明
例子如下
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
ctx.fillRect(10, 10, 100, 100);
ctx.clearRect(30, 30, 60, 60);
ctx.strokeRect(35, 35, 50, 50);
document.body.appendChild(canvas);
结果如下:(自行脑补坐标系)
2.3 圆弧
arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
其中,startAngle和endAngle的单位是弧度(1圈为2π=360度,1弧度为π/180),anticlockwise为布尔值(true逆时针,false顺时针),圆弧的0弧度在正右方。
小例子:
let canvas = document.createElement("canvas");
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext("2d");
ctx.arc(20, 20, 20, 0, Math.PI / 3, false);
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
2.4 贝塞尔曲线
顾名思义,就是专门提供来画曲线的api
2.4.1 二次贝塞尔曲线
quadraticCurveTo(cp1x, cp1y, x, y)
两个蓝点,一个为起始点(当前焦点),一个为结束点(参数x,y)。
红点为控制点(参数cp1x,cp1y),用来 "拉扯" 出曲线的。
小例子:
let canvas = document.createElement("canvas");
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext("2d");
ctx.moveTo(20, 20);
ctx.quadraticCurveTo(40, 20, 40, 40);
ctx.quadraticCurveTo(40, 60, 60, 60);
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
2.4.2 三次贝塞尔曲线
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
同样两个蓝点,起始点(当前焦点),结束点(参数x,y)
两个控制点,坐标分别为(cp1x, cp1y),(cp2x, cp2y)
小例子:
let canvas = document.createElement("canvas");
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext("2d");
ctx.moveTo(20, 20);
ctx.bezierCurveTo(40, 20, 40, 60, 60, 60);
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
同样,焦点总会重新定到上一次曲线的结束点。
2.5 文本
2.5.1 canvas 提供了两种方法来渲染文本
fillText(text, x, y, maxWidth)
绘制实体文本,text为文本内容,x,y为文本开始坐标,maxWidth为最大宽度
strokeText(text, x, y, maxWidth)
绘制描边文本,参数含义与上相同
2.5.2 提供了四个属性设置文本样式
font
设置字号与字体,语法规则与css font一样,如"10px sans-serif"
textAlign
设置文本对齐,可选值有top、end、left、right、center,默认值start
textBaseline
设置基线对齐,可选值有top、hanging、middle、alphabetic、ideographic、bottom,默认alphabetic
direction
文本方向,可选值有ltr、rtl、inherit,默认inherit
小例子
let canvas = document.createElement('canvas');
canvas.width = 400;
canvas.height = 400;
let ctx = canvas.getContext('2d');
ctx.font = "36px serif";
ctx.strokeText('this is a world!', 20, 30);
ctx.textAlign = 'right';
ctx.fillText('this is a world!', 160, 60, 140);
document.body.appendChild(canvas);
结果如下
3.应用颜色和样式
3.1 颜色
实际上在绘制图形时,我们可以切换当前所使用的的颜色,从而画出彩色的图案。canvas通过fillStyle(设置图形的填充颜色)和strokeStyle(设置图形轮廓的颜色)这两个属性来实现这一点。它以路径为单位,每个路径都只能使用一种填充颜色和一种轮廓颜色。其中颜色的值可以为英文、16进制值、rgb、rgba。
小例子:
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
//画橙色的扇形
ctx.fillStyle = 'orange';
ctx.strokeStyle = "orange";
ctx.moveTo(40, 40);
ctx.lineTo(70, 40);
ctx.arc(40, 40, 30, 0, Math.PI / 3, false);
ctx.fill();
ctx.moveTo(74, 40);
ctx.arc(40, 40, 34, 0, Math.PI / 3, false);
ctx.stroke();
ctx.closePath();
// 画蓝色的扇形
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.fillStyle = "blue"
ctx.arc(40, 40, 30, Math.PI / 3, 0, false);
ctx.lineTo(40, 40);
ctx.fill();
ctx.moveTo(40, 74);
ctx.arc(40, 40, 34, Math.PI / 3, 0, false);
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
3.2 透明度
我们除了通过设置绘制颜色的rgba来间接控制图案的透明度外,还可以使用属性globalAlpha来直接控制。同样的,也是以路径为单位,每个路径只有一个透明度。
小例子:
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
for (let i = 1; i <= 10; i++) {
ctx.beginPath();
ctx.globalAlpha = 1 - i / 10;
ctx.arc(30, 30, 3 * i, 0, 2 * Math.PI, true);
ctx.fill();
}
document.body.appendChild(canvas);
结果如下:
3.3 线条样式
canvas提供了很多属性来控制线条的样式
3.3.1 lineWidth
设置线条宽度
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
ctx.strokeStyle = 'orange'
for (let i = 0; i < 10; i++) {
ctx.beginPath()
ctx.moveTo(i * 20 + i, 20);
ctx.lineWidth = i;
ctx.lineTo(i * 20 + i, 60);
ctx.stroke();
}
document.body.appendChild(canvas);
结果如下:
3.3.2 lineCap
设置线条末端样式,可取值有"butt"(线段末端以方形结束),"round"(线段末端以圆形结束),"square"(线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域)
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
let caps = ['butt', 'round', 'square'];
ctx.lineWidth = 8;
caps.forEach((item, index) => {
ctx.beginPath();
ctx.moveTo(20, 20 * index + 20);
ctx.lineCap = item;
ctx.lineTo(80, 20 * index + 20);
ctx.stroke();
})
document.body.appendChild(canvas);
结果如下:
3.3.3 lineJoin
设置线条与线条间接合处的样式,可取值有"round","bevel","miter"
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
let lineJoin = ['round', 'bevel', 'miter'];
ctx.lineWidth = 10;
for (var i = 0; i < lineJoin.length; i++) {
ctx.lineJoin = lineJoin[i];
ctx.beginPath();
ctx.moveTo(-5, 5 + i * 40);
ctx.lineTo(35, 45 + i * 40);
ctx.lineTo(75, 5 + i * 40);
ctx.lineTo(115, 45 + i * 40);
ctx.lineTo(155, 5 + i * 40);
ctx.stroke();
}
document.body.appendChild(canvas);
结果如下:
3.3.4 miterLimit
限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
ctx.lineWidth = 10;
ctx.moveTo(20, 20);
ctx.lineTo(40, 100);
ctx.lineTo(80, 20);
ctx.stroke();
//加上limit限制后
ctx.beginPath();
ctx.miterLimit = 2;
ctx.moveTo(90, 20);
ctx.lineTo(110, 100);
ctx.lineTo(150, 20);
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
3.3.5 setLineDash(array)
设置线条为虚线,传入一个数字数组([长度,间距,长度,间距,......]),该数组被当做重复的最小虚线单元,如果数组长度为奇数则会被重复一遍([5,6,7]=>[5,6,7,5,6,7])
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
ctx.lineWidth = 2;
ctx.setLineDash([10, 2])
ctx.moveTo(20, 20);
ctx.lineTo(160, 20);
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
3.3.6 getLineDash()
获取当前路径的虚线数组
3.3.7 lineDashOffset
设置虚线的起始偏移量,正数向左偏移,负数向右偏移
3.4 渐变
canvas的渐变方式
1).创建一个渐变对象
2).设置渐变对象的渐变规则
通过addColorStop(position,color)方法实现,整个渐变趋势进度为0~1,而position和color表示在某个进度位置的渐变颜色,可设置多个进度颜色。
3).将渐变对象赋给fillStyle或strokeStyle属性
4).当前路径的所有绘制都具有相应的渐变效果
canvas提供了两种渐变对象,linearGradient和radialGradient
3.4.1 linearGradient
该对象通过设置两个坐标点,来表示整个路径绘制的颜色渐变趋势,常用于整体颜色渐变。
小例子:
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
let lg = ctx.createLinearGradient(0, 0, 150, 150);
lg.addColorStop(0, 'red');
lg.addColorStop(0.25, 'purple');
lg.addColorStop(0.5, 'blue')
lg.addColorStop(0.75,'orange');
lg.addColorStop(1, 'green');
ctx.fillStyle = lg;
ctx.fillRect(0, 0, 170, 170);
document.body.appendChild(canvas);
结果如下:
3.4.2 radialGradient
该对象用来实现圆心向外扩散的渐变效果,对象接收两个圆(内圆与外圆),外圆包裹着内圆,两圆之间的间距部分就是用来呈现最终的渐变效果的。
小例子:
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
let lg = ctx.createRadialGradient(40, 40, 20, 46, 46, 80);
lg.addColorStop(0, 'white');
lg.addColorStop(1, 'black');
ctx.fillStyle = lg;
ctx.fillRect(0, 0, 150, 150);
document.body.appendChild(canvas);
结果如下:
3.5 图案样式
可以使用指定的图案来绘制canvas
1).创建图案对象(img对象或canvas对象)
2).基于图案对象创建样式对象
3).将样式对象赋给strokeStyle或fillStyle
小例子:
let canvasImg = document.createElement('canvas');
canvasImg.width = 40;
canvasImg.height = 40;
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
//创建图案
let ctxImg = canvasImg.getContext('2d');
ctxImg.fillStyle = "orange";
ctxImg.strokeStyle = "orange";
ctxImg.moveTo(0, 0);
ctxImg.lineTo(40, 0);
ctxImg.arc(0, 0, 40, 0, Math.PI / 2, false);
ctxImg.fill();
// 创建样式对象
let ctx = canvas.getContext('2d');
let ptrn = ctx.createPattern(canvasImg, 'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 200, 200);
document.body.appendChild(canvas);
结果如下:
3.6 阴影
canvas提供了四个属性来设置阴影样式
shadowOffsetX
表示阴影在x轴的延伸距离,正值向右延伸,负值向左延伸,默认为0
shadowOffsetY
表示阴影在y轴的延伸距离,正值向下延伸,负值向上延伸,默认为0
shadowBlur
表示阴影的模糊程度,数值越大越模糊,负值无效,默认值为0
shadowColor
表示阴影的颜色,值可取英文、rgba、十六进制值
小例子:
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
ctx.arc(40, 40, 30, 0, 2 * Math.PI, false);
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.shadowBlur = 2;
ctx.shadowColor = "orange";
ctx.stroke();
document.body.appendChild(canvas);
结果如下:
3.7 填充规则
canvas有两种填充规则
"nonzero"
表示全填充,只要是闭合图形都进行填充(默认)
"evenodd"
只填充图形不相交的部分
小例子:
let canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;
let ctx = canvas.getContext('2d');
ctx.arc(40, 40, 30, 0, 2 * Math.PI, false);
ctx.arc(50, 40, 30, 0, 2 * Math.PI, false);
ctx.fill('evenodd');
document.body.appendChild(canvas);
结果如下: