1 介绍
canvas是HTML5新增的标签,用于提供画布
它的标准属性有width和height,例如(class, id这些都属于标准属性)
width:表示canvas的宽
height:表示canvas的高
在javascript中,可以通过canvas.getContext(‘2d’)方法获取画布上下文
画布上下文为我们提供了大量的绘图方法
canvas是用于显示图形的,自带了一个坐标系,默认与元素的定位坐标是一致的位于左上角,是一个倒置的数学坐标系(与浏览器一样)
2 canvas API
在canvas中大部分都是在操作路径,所以在操作之前要开启路径
beginPath():用于开启路径
closePath():用于闭合路径,在闭合时候的点和最开始时候的点之间会形成一条线段
fillRect(x, y, w, h):填充矩形
x:当前坐标系的x点 y:当前坐标系的y点
w:矩形的宽 h:矩形的高
strokeRect(x, y, w, h):描边矩形
x:当前坐标系的x点 y:当前坐标系的y点
w:矩形的宽 h:矩形的高
clearRect(x, y, w, h):清除canvas上的一块区域
x:当前坐标系的x点 y:当前坐标系的y点
w:要清除的区域的宽 h:要清除的区域的高
arc(x, y, r, star, end, bool):绘制弧
x:圆心所在的圆弧的x点 y:圆心所在的圆弧的y点 r:表示圆弧的半径
star:起始位置 end:终点位置
bool:是一个布尔值,默认是false表示顺时针绘制,反之逆时针绘制
fill: 用于填充
stroke: 用于描边
fillStyle: 用于改变填充色
strokeStyle:用于改变描边色
fillText: 用于绘制文字
font: 用于改变文字样式
lineWidth: 用于改变线宽
lineTo: 绘制线
moveTo: 移动绘制的起点
- 绘制线示例
<canvas id="app" class="demo" width="600" height="400"></canvas>
<script>
// 获取元素
var canvas = document.getElementById('app');
// 获取画布
var ctx = canvas.getContext('2d');
// 启动绘制
ctx.beginPath();
// 移动绘制起点
ctx.moveTo(100, 100);
// 绘制线
ctx.lineTo(200, 200);
// 结束绘制
ctx.closePath();
// 描边
ctx.stroke();
</script>
效果:
- 绘制圆
// // 更改描边颜色
ctx.strokeStyle = 'red';
// 更改填充颜色
ctx.fillStyle = 'green';
// 绘制圆
ctx.beginPath();
// // 顺时针
// ctx.arc(200, 200, 100, 0, Math.PI);
// 逆时针
ctx.arc(200, 200, 100, 0, Math.PI / 2, true); // 传入true逆时针
效果
第一张为顺时针,第二张为逆时针
- 绘制矩形
// // 更改描边颜色
ctx.strokeStyle = 'red';
// 更改填充颜色
ctx.fillStyle = 'green';
ctx.beginPath();
// 绘制矩形
// ctx.strokeRect(100, 100, 200, 200);
// 填充矩形
ctx.fillRect(100, 100, 200, 200);
ctx.closePath();
ctx.stroke();
效果:
第一张为绘制矩形,第二张为填充矩形
清除矩形
// // 更改描边颜色
ctx.strokeStyle = 'red';
// 更改填充颜色
ctx.fillStyle = 'green';
ctx.beginPath();
// 填充矩形
ctx.fillRect(100, 100, 200, 200);
ctx.closePath();
ctx.stroke();
// // 清除矩形
ctx.clearRect(200, 200, 100, 100);
效果
- 绘制哑铃
<canvas id="app" class="demo" width="600" height="400"></canvas>
<script>
// 获取元素
var canvas = document.getElementById('app');
// 获取画布
var ctx = canvas.getContext('2d');
// 更改填充颜色
ctx.fillStyle = 'green';
ctx.arc(300, 200, 50, 0, 2 * Math.PI);
ctx.arc(500, 200, 50, 0, 2 * Math.PI);
ctx.fill();
ctx.strokeStyle = 'green';
ctx.lineWidth = 10;
// 绘制线
line(350, 200, 450, 200);
// 封装方法
function line(x, y, endX, endY) {
ctx.beginPath();
// 移动绘制起点
ctx.moveTo(x, y);
// 绘制线
ctx.lineTo(endX, endY);
// 结束绘制
ctx.closePath();
// 描边
ctx.stroke();
}
</script>
效果
3 绘制图片
在canvas中绘制图片有三种方式:1 设置背景图片 2插入图片 3drawImage方法绘制
drawImage 该方法用于绘制图片,使用方式有三种:
第一种:可以以原尺寸来绘制图片 ctx.drawImage(img, x, y)
img:要绘制的图片
x:以原尺寸将图片放在canvas中的x点 y:以原尺寸将图片放在canvas中的y点
第二种:可以缩放图片 ctx.drawImage(img, x, y, w, h)
img:要绘制的图片
x:将缩放的图片放在canvas中的x点 y:将缩放的图片放在canvas中的y点
w:缩放后的图片的宽 h:缩放后的图片的高
第三种:截取图片中的某一部分
ctx.drawImage(img, img_x, img_y, img_w, img_h, canvas_x, canvas_y, canvas_w, canvas_h)
img:要绘制的图片
img_x:要截取的图片的x点 img_y:要截取的图片的y点
img_w:要截取图片的宽 img_h:要截取的图片的高
canvas_x:将截取后的图片放在canvas中的x点
canvas_y:将截取后的图片放在canvas中的y点
canvas_w:将截取后的图片放在canvas中的宽
canvas_h:将截取后的图片放在canvas中的高
<canvas id="app" class="demo" width="600" height="400"></canvas>
<script>
// 获取元素
var canvas = document.getElementById('app');
// 获取画布
var ctx = canvas.getContext('2d');
// 通过js方式加载图片
var img = new Image();
// 监听图片加载完成
img.onload = function() {
// 可以通过this和img获取图片,this指向img,就是img
// console.log(this, img, img.width, img.height);
// 绘制图片
ctx.drawImage(img, 100, 100);
// 缩小图片
// ctx.drawImage(img, 100, 100, 400, 250);
// 截取图片
// ctx.drawImage(img, 800, 0, 600, 400, 0, 0, 600, 400);
// 截取之后也可以缩放
// ctx.drawImage(img, 800, 0, 600, 400, 0, 0, 300, 200);
}
// 加载图片
img.src = './image/2.PNG';
</script>
效果:
- 绘制图片
- 缩小图片
- 截取图片
- 截取之后也可以缩放
4 坐标系
canvas中允许我们对坐标系做变换,类似css中transform
translate(x, y) 移动坐标系
x:表示水平移动 y:表示垂直移动
rotate(deg) 旋转坐标系
deg:表示旋转角度 单位是弧度(pi)
scale(x, y) 缩放坐标系
x:水平方向缩放 y:垂直方向缩放
大于1表示放大,小于1表示缩小
<canvas id="app" class="demo" width="800" height="400"></canvas>
<script>
// 获取元素
var canvas = document.getElementById('app');
// 获取画布
var ctx = canvas.getContext('2d');
// 封装方法
function line(x, y, endX, endY) {
ctx.beginPath();
// 移动绘制起点
ctx.moveTo(x, y);
// 绘制线
ctx.lineTo(endX, endY);
// 结束绘制
ctx.closePath();
// 描边
ctx.stroke();
}
// 绘制坐标系方法
function drawXY() {
// 水平方向
line(0, 10, 780, 10);
line(760, 0, 780, 10);
line(760, 20, 780, 10);
// 垂直方向
line(10, 0, 10, 380);
line(0, 360, 10, 380);
line(20, 360, 10, 380);
}
drawXY();
// 平移坐标系
// 平移之前的绘制不受影响,平移之后的绘制受到影响
ctx.translate(canvas.width / 2, canvas.height / 2);
// 旋转
// ctx.rotate(Math.PI / 4);
// 放缩
// ctx.scale(0.5, 0.5);
drawXY();
</script>
效果:
平移
旋转
放缩
平移放缩
- 小案例:旋转坐标系
<canvas id="app" class="demo" width="800" height="400"></canvas>
<script>
// 获取元素
var canvas = document.getElementById('app');
// 获取画布
var ctx = canvas.getContext('2d');
// 封装方法
function line(x, y, endX, endY) {
ctx.beginPath();
// 移动绘制起点
ctx.moveTo(x, y);
// 绘制线
ctx.lineTo(endX, endY);
// 结束绘制
ctx.closePath();
// 描边
ctx.stroke();
}
// 绘制坐标系方法
function drawXY() {
// 水平方向
line(0, 10, 780, 10);
line(760, 0, 780, 10);
line(760, 20, 780, 10);
// 垂直方向
line(10, 0, 10, 380);
line(0, 360, 10, 380);
line(20, 360, 10, 380);
}
// 在中间旋转
ctx.translate(canvas.width / 2, canvas.height / 2);
// 旋转的速度
var speed = Math.PI / 180;
// 起始度数
var deg = 0;
// 每隔1s绘制一次
setInterval(function() {
// 在下一次的绘制的时候清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
deg += speed;
ctx.rotate(deg);
drawXY();
}, 100);
</script>
效果:坐标系会一直旋转,速度不断加快
5 状态的保存与恢复
在canvas中很多时候要用到之前的状态,所以提供了相应的API用于保存canvas上的状态
save 存储状态
restore 恢复状态
save方法可以使用多次,每save一次就好比装了一颗子弹
每restore一次,就好比扣了一次扳机
<canvas id="app" class="demo" width="800" height="600"></canvas>
<script>
// 获取元素
var canvas = document.getElementById('app');
// 获取画布
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
// 绘制矩形
ctx.fillRect(100, 100, 50, 50);
// 存储状态
ctx.save();
// 绘制红色盒子
ctx.fillStyle = 'red';
ctx.fillRect(200, 200, 50, 50);
ctx.save();
// 恢复状态,此时恢复上一次保存的红色盒子
ctx.restore();
ctx.fillRect(300, 300, 50, 50);
ctx.restore(); // 此时恢复上上一次保存的绿色盒子
ctx.fillRect(400, 400, 50, 50);
</script>
效果
6 融合
融合,是在canvas中新图形和原有图形之间的覆盖方式
默认情况下,新图形覆盖原有图片
通过ctx.globalCompositeOperation属性设置
source-over 默认,在目标图像上显示源图像
source-atop 在目标图像顶部显示源图像,源图像位于目标图像之外的部分是不可见的
source-in 在目标图像中显示源图像,只有目标图像内的源图像部分会显示,目标图像是透明的
source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的
destination-over在源图像上方显示目标图像
destination-atop在源图像顶部显示目标图像,源图像之外的目标图像部分不会被显示
destination-in 在源图像中显示目标图像,只有源图像内的目标图像部分会被显示,源图像是透明的
destination-out 在源图像外显示目标图像,只有源图像外的目标图像部分会被显示,源图像是透明的
lighter 显示源图像+目标图像
copy 显示源图像,忽略目标图像
xor 使用异或操作对源图像与目标图像进行组合
<canvas width="600" height="600" style="margin: 10px auto; display: block; border: 1px solid pink;"></canvas>
<script>
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
fillArc(200, 200, 100);
// 修改覆盖关系
// 重叠的绿色显示
// ctx.globalCompositeOperation = 'source-atop';
// 两个圆重叠的部分显示
// ctx.globalCompositeOperation = 'source-in';
// 显示绿色没有重叠的部分
// ctx.globalCompositeOperation = 'source-out';
// 优先显示底部红色部分
// ctx.globalCompositeOperation = 'destination-over';
// 显示红色与绿色重叠部分
// ctx.globalCompositeOperation = 'destination-atop';
// 重叠部分显示,显示红色
// ctx.globalCompositeOperation = 'destination-in';
// 显示红色未重叠部分
// ctx.globalCompositeOperation = 'destination-out';
// 显示源图像+目标图像
// ctx.globalCompositeOperation = 'lighter';
// 显示源图像,忽略目标图像
// ctx.globalCompositeOperation = 'cpoy';
// 使用异或操作对源图像与目标图像进行组合
ctx.globalCompositeOperation = 'xor';
ctx.fillStyle = 'green';
fillArc(300, 200, 100);
// 绘制两个圆
function fillArc(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
</script>
7 像素信息
getImageData 该方法用于获取canvas上的像素信息
返回的是一个像素信息对象,该对象中有三个属性
第一个是一个data是一个数组、
第二个是height表示获取图像的高度
第三个是width表示获取图像的宽度
putImageData 该方法用于将修正之后的像素信息对象重新放回canvas,三个参数分别是:
第一个参数:像素数据
第二个参数:绘制横坐标
第三个参数:绘制纵坐标
<canvas id="app"></canvas>
<script>
var img = new Image();
var canvas = document.getElementById('app');
var ctx = canvas.getContext('2d');
img.onload = function() {
// 修改画布大小
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width / 2, img.height / 2);
// 获取像素数据
var result = ctx.getImageData(100, 100, 400, 400);
// console.log(result);
// 将获取到的像素信息绘制到右边
ctx.putImageData(result, img.width / 2, 0);
}
img.src = './image/2.PNG';
</script>
效果
- 实现图片特效
<body>
<button id="red">去除红色</button>
<button id="green">去除绿色</button>
<button id="blue">去除蓝色</button>
<button id="gray">灰色</button>
<canvas id="app" style="border: 2px solid green;"></canvas>
<script>
var img = new Image();
var canvas = document.getElementById('app');
var ctx = canvas.getContext('2d');
var width, height;
img.onload = function() {
// 修改画布大小
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width / 2, img.height / 2);
width = img.width / 2;
height = img.height / 2;
// 获取像素数据
// var result = ctx.getImageData(100, 100, 400, 400);
// // console.log(result);
// // 将获取到的像素信息绘制到右边
// ctx.putImageData(result, img.width / 2, 0);
}
img.src = './image/2.PNG';
// 绑定事件
// 去除红色
red.onclick = function() {
var result = ctx.getImageData(0, 0, width, height);
for (var i = 0, len = result.data.length; i < len; i +=4) {
// 每个像素点包括四个信息,红,绿,蓝,透明度
// 删除红色通道
result.data[i] = 0;
}
ctx.putImageData(result, width , 0);
}
// 去除绿色
green.onclick = function() {
var result = ctx.getImageData(0, 0, width, height);
for (var i = 0, len = result.data.length; i < len; i +=4) {
// 每个像素点包括四个信息,红,绿,蓝,透明度
// 删除绿色通道
result.data[i + 1] = 0;
}
ctx.putImageData(result, width , 0);
}
// 去除蓝色
blue.onclick = function() {
var result = ctx.getImageData(0, 0, width, height);
for (var i = 0, len = result.data.length; i < len; i +=4) {
// 每个像素点包括四个信息,红,绿,蓝,透明度
// 删除蓝色通道
result.data[i + 2] = 0;
}
ctx.putImageData(result, width , 0);
}
// 灰色
gray.onclick = function() {
var result = ctx.getImageData(0, 0, width, height);
var arr = result.data;
for (var i = 0, len = arr.length; i < len; i +=4) {
// 每个像素点包括四个信息,红,绿,蓝,透明度
// // 让三个通道取红色值
// arr[i + 1] = arr[i];
// arr[i + 2] = arr[i];
// 取三个通道的平均值
var arg = (arr[i] + arr[i + 1] + arr[i + 2]) / 3;
arr[i] = arg;
arr[i + 1] = arg;
arr[i + 2] = arg;
}
ctx.putImageData(result, width , 0);
}
</script>