前言
-
canvas 是 HTML5 特性中最重要内容的之一,基础比较完善,应用广泛
-
canvas 指的是画布,类似于windows的画图工具;在HTML中,默认效果与div类似,背景色是默认色
-
配合js,动态效果非常帅
-
支持2D图像效果、3D图像效果
-
注意:IE8及之前版本不支持canvas 大哥,它可不是一块真布奥 😁
-
大家先来看一个小 demo ...好玩不?要想整出这玩意,首先还是得先从基础学起,所谓百炼成钢
基本使用
<canvas id="drawing" width="200" height="200">A drawing of something</canvas>
[A drawing of something是后备信息,如果浏览器不支持canvas,就会显示这些信息]
const cav = document.querySelector("#drawing");
if(cav.getContext){
const context = cav.getContext("2d");
// 使用 API 达到预期效果
}
- 注意:
- cav.getContext("2d"); 中的 d 只能小写,并且为字符串
- 使用canvas来绘制的图像,只能出现在canvas规定的范围内,如果超出则会被隐藏
绘图
绘制图形
-
canvas 只支持一种基本形状――矩形,所以其它形状都是有一个或多个路径组合而成
,还好,有一组路径绘制函数让我们可以绘制相当复杂的形状。 -
原点:canvas的左上角(0,0),
[x 和 y 指定矩形左上角(相对于原点)的位置]
-
fillRect(x,y,width,height) : 绘制一个实心矩形,默认背景颜色为黑色,没有边框
- 填充(实心)配合fillRect(),并在fillRect()之前使用
- fillStyle = "颜色值";
-
strokeRect(x,y,width,height) : 空心矩形,默认边框颜色为黑色,边框默认宽:1px
- 描边(空心)配合strokeRect(),并在strokeRect()之前使用
- strokeStyle = "颜色值";
-
clearRect(x,y,width,height) : 以矩形方式清除指定区域(类似橡皮擦) 放置在要清除的图形位置之后,即绘制一个,清除一下
-
全局设置透明度(0~1)在颜色后设置透明度
- globalAlpha = "透明值";
-
canvas是按顺序进行画图,后面的图形会将前面的覆盖,例如:
<canvas id="canvas" width="400" height="400" style="background: #eee;">浏览器不支持canvas</canvas>
function draw(id) {
const canvas = document.getElementById(id);
if (canvas.getContext) {
const ctx = canvas.getContext('2d');
ctx.fillRect(25, 25, 100, 100);
ctx.clearRect(45, 45, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
}
}
draw('canvas');
绘制渐变
将渐变基准线赋值给 fillStyle 或 strokeStyle
线性渐变
- createLinearGradient(x1,y1,x2,y2);
- 两点一线(渐变的基准线)
const canv = document.getElementById('canvas');
if (canv.getContext) {
const context = canv.getContext('2d');
// 创建渐变的基准线(水平)
// const grad = context.createLinearGradient(0, 0, canv.width, 0);
// 垂直
// const grad = context.createLinearGradient(0, 0, 0, canv.height);
// 斜着来
const grad = context.createLinearGradient(0, 0, canv.width, canv.height);
// 添加颜色
grad.addColorStop(0, 'yellow');
grad.addColorStop(0.5, 'red');
grad.addColorStop(1, 'blue');
// 画矩形
context.fillStyle = grad; //将渐变加入到矩形中
context.fillRect(0, 0, canv.width, canv.height);
}
圆形渐变
- createRadialGradient(x1,y1,r1,x2,y2,r2);
- x1,y1:表示第一个圆的圆心位置,r1:表示第一个圆的半径,圆柱体或圆锥体基准线
...beautiful 不?
const canv = document.querySelector('#drawing');
if (canv.getContext) {
const context = canv.getContext('2d');
const g = context.createRadialGradient(50, 100, 0, 100, 100, 100);
g.addColorStop(0.0, '#fff');
g.addColorStop(1.0, '#000');
context.translate(20, 20);
context.scale(2, 2);
context.fillStyle = g;
context.arc(100, 100, 100, 0, 2 * Math.PI);
context.fill();
}
绘制路径
-
用 beginPath() 创建一个路径。在内存里,路径是以一组子路径(直线,弧线等)的形式储存的,它们共同构成一个图形。每次调用 beginPath,子路径组都会被重置,然后可以绘制新的图形。
-
调用 closePath 方法,它会尝试用直线连接当前端点与起始端点来关闭路径,但如果图形已经关闭或者只有一个点,它会什么都不做。这一步不是必须的
-
只有在调用 stroke 或 fill 方法时,图形才会真实的绘制到 canvas 上
- stroke()绘制路径的轮廓
- fill()绘制路径的填充
- clip()在上下文中设置裁剪区域(注意:再绘制图像,只能在该区域中)
- 注意:当调用 fill 时,开放的路径会自动闭合,而无需再调用 closePath
图形渐远
function draw(id) {
var canvas = document.getElementById(id);
if (canvas) {
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#eeeeef';
ctx.fillRect(0, 0, 600, 700);
for (var i = 0; i <= 10; i++) {
ctx.beginPath();
ctx.arc(i * 25, i * 25, i * 10, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = 'rgba(255,0,0,0.25)';
ctx.fill();
}
}
}
创建形状
矩形
rect(x, y, width, height)
圆形
arc(x, y, radius, startAngle, endAngle, [direction])
- 以(x,y)为圆心绘制一条弧线,弧线半径为radius,起始角度和结束角度(用弧度表示 [角度 * Math.PI/2])
- direction: startAngle和endAngle是否按逆时针方向计算(false表示顺时针) 默认是顺时针
var canv = document.querySelector('#drawing');
if (canv.getContext) {
var context = canv.getContext('2d');
context.strokeStyle = 'red';
context.fillStyle = 'green';
/*矩形*/
context.beginPath();
context.rect(10, 10, 100, 100);
context.stroke();
context.beginPath();
context.rect(120, 10, 100, 100);
context.fill();
context.beginPath();
context.rect(230, 10, 100, 100);
context.stroke();
context.fill();
/*圆形*/
context.beginPath();
context.arc(55, 170, 50, 0, (Math.PI * 3) / 2);
context.stroke();
context.beginPath();
context.arc(165, 170, 50, 0, (Math.PI * 3) / 2);
context.fill();
context.beginPath();
context.arc(275, 170, 50, 0, (Math.PI * 3) / 2);
context.fill();
context.stroke();
/*使用closePath*/
context.beginPath();
context.arc(55, 280, 50, 0, (Math.PI * 3) / 2);
context.closePath();
context.stroke();
context.beginPath();
context.arc(165, 280, 50, 0, (Math.PI * 3) / 2);
context.closePath();
context.fill(); //没有区别
context.beginPath();
context.arc(275, 280, 50, 0, (Math.PI * 3) / 2);
context.fill();
context.closePath();
context.stroke();
}
五角星
/**
* 绘制五角星
* @param {[type]} ctx
* @param {[type]} x 小圆圆心位置
* @param {[type]} y 小圆圆心位置
* @param {[type]} r 小圆半径
* @param {[type]} R 大圆半径
* @param {[type]} rotate 旋转角度
* @param {[type]} lineJoinStyle 设置两条线连接点的形状
* @param {[type]} borderWidth [description]
*/
function drawStar(ctx, x, y, r, R, rotate, borderWidth, borderColor, fillColor, lineJoinStyle) {
ctx.beginPath();
for (var i = 0; i < 5; i++) {
ctx.lineTo(
Math.cos(((18 + i * 72 - rotate) / 180) * Math.PI) * R + x,
Math.sin(((18 + i * 72 - rotate) / 180) * Math.PI) * R + y
);
ctx.lineTo(
Math.cos(((54 + i * 72 - rotate) / 180) * Math.PI) * r + x,
Math.sin(((54 + i * 72 - rotate) / 180) * Math.PI) * r + y
);
}
ctx.closePath();
if (fillColor) {
ctx.fillStyle = fillColor;
}
if (borderColor) {
ctx.strokeStyle = borderColor;
}
ctx.lineWidth = borderWidth;
ctx.lineJoin = lineJoinStyle;
fillColor && ctx.fill();
ctx.stroke();
}
绘制三角形
var drawing = document.querySelector('#drawing');
if (drawing.getContext) {
var context = drawing.getContext('2d');
context.beginPath();
context.moveTo(10, 10);
context.lineTo(100, 10);
context.lineTo(55, 100);
context.fill();
// ------------------
context.beginPath();
context.moveTo(55, 100);
context.lineTo(10, 200);
context.lineTo(100, 200);
context.closePath();
// context.stroke();
}
设置路径
- moveTo(x,y): 将当前坐标移动到指定坐标(就是起点)
- lineTo(x,y): 将当前坐标到指定坐标绘制一条新线(就是终点)
var canvas = document.getElementById('canvas');
if (canvas.getContext('2d')) {
var ctx = canvas.getContext('2d');
//canvas是基于状态变化来进行绘图的
//1.画直线
ctx.moveTo(100, 100); //状态,设置笔尖设置位置
ctx.lineTo(400, 400); //状态,要从笔尖位置连接到当前位置
ctx.lineTo(200, 400); //状态
ctx.lineTo(100, 100); //状态,与笔尖开始的坐标首尾相接,就形成了一个多边形
ctx.lineWidth = 5; //状态,设置线的宽度
ctx.strokeStyle = '#e8393c'; //状态,设置绘制的颜色
ctx.stroke(); //这才是真正的绘制
ctx.fillStyle = 'rgba(0,0,0,.6)';
ctx.fill();
// 因为是基于状态的绘制,所以想另画东西,需要使用路径
ctx.beginPath();
ctx.moveTo(500, 100);
ctx.lineTo(600, 200);
ctx.stroke();
}
设置线形
-
lineWidth: 设置线的宽度,默认为 1
-
lineCap: 设置线端点的形状
- butt:默认: 与边平行
- round:圆
- square:正方形,与butt效果一致
-
lineJoin: 设置两条线连接点的形状
- round:圆角
- bevel:斜角
- miter:默认,尖角
-
miterLimit: 设置线条交接点的延伸范围(0~5:5最大,尖角;0平角)
- 与lineJoin配合使用,仅当lineJoin="miter"时有效
var canv = document.querySelector('#drawing');
if (canv.getContext) {
var context = canv.getContext('2d');
context.beginPath();
context.lineWidth = '20';
context.lineCap = 'round';
// context.lineJoin = "bevel";
context.lineJoin = "round";
context.miterLimit = '3';
context.moveTo(110, 10);
context.lineTo(110, 110);
context.lineTo(200, 40);
context.stroke();
}
图形组合
- ctx 属性 globalCompositeOperation = type 属性,如下
- source-atop : 绘制原有图层被新图层覆盖的部分和新图层其它部分
- source-in : 只绘制新图形与原图形重合的部分,其他部分透明
- source-out: 只绘制新图形与与原图不重合的部分,重合部分透明
- source-over: 新图形在原有图形上面,覆盖(默认)
- destination-atop:
- destination-in:
- destination-out:
- destination-over:
- ighter:重叠部分颜色加深
- copy:
- xor:只绘制重叠部分
function draw(id) {
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
var oprtns = new Array(
'source-atop',
'source-in',
'source-out',
'source-over',
'destination-atop',
'destination-in',
'destination-out',
'destination-over',
'lighter',
'copy',
'xor'
);
const i = 8;
ctx.fillStyle = 'blue';
ctx.fillRect(10, 10, 60, 60);
ctx.globalCompositeOperation = oprtns[i];
ctx.beginPath();
ctx.fillStyle = 'red';
ctx.arc(60, 60, 30, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
绘制文字
- font: 与css使用相同
- textAlign: 设置水平位置 - left、right、center
- start: 效果与left相同
- end: 效果与right相同
- textBaseline: 设置垂直位置 - top、bottom、middle
- hanging: 悬挂基线
- alphabetic: 字母基线
- strokeText(text,x,y); 绘制指定文字的轮廓
- fillText(text,x,y); 绘制指定文字的填充
艺术字
var canv = document.querySelector('#drawing');
if (canv.getContext) {
var context = canv.getContext('2d');
context.font = 'bold 40px Arial';
var g = context.createLinearGradient(200, 0, 400, 0);
g.addColorStop(0.0, 'red');
g.addColorStop(1.0, 'green');
context.fillStyle = g;
context.fillText('We are family', 200, 200);
context.strokeStyle = 'blue';
context.strokeText('We are family', 200, 400);
}
文字度量
- context.measureText(str).width - str 文字字符串
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.font = "italic bold 24px Arial";
var s = '文艺青年';
context.fillText(s, 50, 200);
console.log(context.measureText(s).width); // 96
文字对齐
var canvas = document.getElementById('canvas'); // 800 x 500
var context = canvas.getContext('2d');
context.font = 'italic bold 24px Arial';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText('canvas', 400, 250);
context.moveTo(0, 250);
context.lineTo(800, 250);
context.stroke();
context.moveTo(400, 0);
context.lineTo(400, 500);
context.stroke();
绘制阴影
- shadowColor: 设置阴影颜色,默认为黑色
- shadowOffsetX: 表示当前阴影为水平效果,值为数字( +阴影在右,-阴影在左边)
- shadowOffsetY: 表示当前阴影为垂直效果,值为数字( +阴影在下,-阴影在上边)
- shadowBlur: 设置当前阴影效果,值为数字(值越大,越模糊 ,最小值为0)
var canv = document.querySelector('#drawing');
if (canv.getContext) {
var context = canv.getContext('2d');
context.fillStyle = 'green';
context.shadowColor = 'gray';
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
// 图二
// context.shadowOffsetX = 100;
// context.shadowOffsetY = 100;
context.shadowBlur = 50;
context.fillRect(0, 0, 100, 100);
// 图三
// context.shadowOffsetX = -10;
// context.shadowOffsetY = -10;
// context.shadowBlur = 100;
// context.fillRect(40, 40, 100, 100);
}