一、概述
Canvas API 提供了一个通过JavaScript 和 HTML的 canvas 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。
Canvas 最有意思的一项特性是针对图像的操作能力,可以动态的合成图像、制作图形的背景,支持浏览器的各种图片格式,甚至可以使用同一页面中其他canvas元素生成的图片作为图片源。
【引入图像到canvas】:
- 获得一个指向HTMLImageElement的对象或者另一个canvas元素的引用作为源,也可以通过URL的方式来使用图片
- 使用drawImage()函数将图片绘制到画布上
【canvas API图片源的来源】:
1、HTMLImageElement:Image()函数构造出来的,或者任何的img元素
2、HTMLVideoElement:video元素,从视频中抓取当前帧作为一个图像
3、HTMLCanvasElement:canvas元素
4、ImageBitmap:位图,可以通过上述源生成
二、绘制图片
在获取到源图像对象后,就可以使用drawImage方法将源图像渲染到canvas里。
/**
image: img 或者 canvas对象
x:在canvas中起始的横坐标
y:在canvas中起始的纵坐标
*/
drawImage(image, x, y)
// 例子
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
ctx.beginPath();
ctx.moveTo(30, 96);
...
}
img.src="http://xxx.png"
}
三、缩放Scaling
drawImage 方法的又一变种是增加了两个用于控制图像在 canvas 中缩放的参数。
/**
image: img 或者 canvas 对象
x,y: 坐标的起始位置
width,height: 向canvas画入时应该缩放的大小
**/
drawImage(image, x, y, width, height)
四、切片Slicing
drawImage 方法的第三个方式是有8个新参数,用于控制做切片显示的
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
第一个参数和其它的是相同的,都是一个图像或者另一个 canvas 的引用。其他8个中前4个是定义图像源的切片位置和大小,后4个则是定义切片的目标显示位置和大小。
/**
相框的例子
**/
<html>
<body onload="draw();">
<canvas id="canvas" width="150" height="150"></canvas>
<div style="display:none;">
<img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227">
<img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150">
</div>
</body>
</html>
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
// Draw slice
ctx.drawImage(document.getElementById('source'),33,71,104,124,21,20,87,104);
// Draw frame
ctx.drawImage(document.getElementById('frame'),0,0);
}
五、通过canvas实现图片上传裁剪
在项目中会遇见头像更新等功能,根据上传的图片实现固定的尺寸裁剪之后上传至服务端;具体的流程为:
1、获取图片:本地图片上传 new FileReader对象 或者 图片链接 new Image对象
2、canvas绘制图片
3、canvas裁剪图片
4、输出裁剪图片toBlob
5、上传至服务端
// 1.上传图片;通过监听input的onChage事件来回去file对象
<input type="file" accept="image/*" onChange={this.handleChange} />
const handleChange = (e) => {
const file = Array.from(e.target.value);
// 可以检验图片的大小和格式操作
// 在每次上传之后,记得将input的value置空,防止再次上传相同图片无法触发onchange事件
}
// 2.canvas绘制图片
// 首先先解析图片,使用FileReader
const fileInfo = (file) => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e) {
let img = new Image();
img.onload = function() {
...// 处理图片的高宽等信息
}
img.src = e.target.result
}
}
//预览图片
使用drawImage 绘制图片到canvas上
// 3、裁剪操作
初始化配置:
const initConfig = () => {
this.ctx = document.getElementById("canvas").getContext("2d");
this.draging = false;
this.startX = null;
this.startY = null;
}
// 鼠标点击事件
const mouseDown = (e) =>
this.draging = true;
this.startX = e.nativeEvent.offsetX;
this.startY = e.nativeEvent.offsetY;
}
// 移动鼠标,绘制裁剪框
const mouseMove = (e) => {
if (!this.draging) return;
let tmpWid = e.nativeEvent.offsetX-startX,
tmpHig = e.nativeEvent.offsetY-startY;
// 开始绘制裁剪框
drawTrim(startX, startY, tmpWid, tmpHig)
}
//松开鼠标
const mouseOut = (e) => {
if (this.draging) {}
this.draging = false;
}
裁剪框的绘制主要分为:1、绘制蒙层阴影;2、裁剪框部分镂空;3、将图片绘制在蒙层下方
const drawTrim= (startX, startY, width, height) => {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// 消除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 蒙层
ctx.save();
ctx.fillStyle='rgba(0,0,0,0.5)';
ctx.fillRect(0, 0, canvas.width, canvas.height)
// 将蒙层凿开,变成透明
ctx.globalCompositeOperation = 'source-atop';
ctx.clearRect(startX, startY, width, height); // 裁剪框
ctx.restore();
//将图片绘制在蒙层下面
ctx.save();
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(this.image, 0, 0, canvas.width, canvas.height);
ctx.restore();
}
最后将裁剪框内的图像输出图片,有两种方式:
- canvas.toDataURL()
- canvas.toBlob()
再此之前需要将裁剪的部分绘制到新的canvas画布上;
const uploadImg = (type) => {
this.canvas.toBlob((blog) => {
blob.lastModifiedDate = new Date();
let fd = new FormData();
fb.append('image', blob);
})
}