这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
0.为什么要写这篇
原因有两个:
- 目前已经存在很多canvas入门,技巧等文章。在开发过程中,我们需要一些能直接使用的canvas方法。把它们进行组合,去实现各种功能。下面是方法汇总,持续补充中,同时也是为了自己记录。
- 最好拿来就能直接使用。
- 最好有一个方法列表,方便查询
- 本文开头第一句
首先,最基础的创建canvas
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
1.写文字
- 查看 API 可得:
通过 font 属性设置字体,参数和css font设置的DOM string一样
- 必填参数:
- font-size
- font-family
- 可选参数
- font-style
- font-varient
- font-weight
- font-height
context.font = '16px serif';
context.fillStyle = '#fff';
context.fillText('text', x, y);
2.加载图片
const image = new Image();
// 处理图片跨域问题
image.setAttribute("crossOrigin", "anonymous");
image.src = imageData;
image.onload = () => {
// 等图片加载完后的操作
};
3.绘制二维码
import QRCode from "qrcode";
// 返回的是一个Promise,需要在then或catch后进行操作
QRCode.toDataURL(url, { margin })
4.加载自定义字体
const fontface = new FontFace(fontName, fontUrl);
document.fonts.add(fontface);
fontface.load();
fontface.loaded.then(() => {
// 加载完之后进行操作
});
5.给canvas设置图片背景
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image,x ,y ,w ,h);
6.导出图片,生成url
const url = canvas.toDataURL("image/png");
总结:
- 可以发现,上述方法中,加载字体,加载图片,绘制二维码,都需要等待完成才能操作,可以使用promise进行优化,解决回调过多的问题
- 创建canvas的过程可以写在类中,方便调用,避免全局声明canvas进行使用
- constructor可以传入width,设置canvas的大小。设置base,如果设置的width的导入的背景图片宽度不一致,自动计算比例,进行放大或者缩小。默认为1.
- 参数尽可能的进行抽离,方便自定义,同时设置参数的默认值,方便使用。
import QRCode from "qrcode";
class canvasToImage {
constructor(width) {
this.width = width;
this.base = 1;
this.canvas = document.createElement("canvas");
this.context = this.canvas.getContext("2d");
}
/**
* @description: 写文字
*/
writeText = (option) => {
const {
fontWeight,
fontSize,
textColor,
text,
x,
y,
fontFamily = "AlibabaPuHuiTiH",
} = option;
return new Promise((reslove) => {
this.context.font = `${fontWeight} ${
fontSize * this.base
}px ${fontFamily}`;
this.context.fillStyle = textColor;
this.context.fillText(text, x * this.base, y * this.base);
reslove();
});
};
/**
* @description: canvas导入图片
*/
loadingImage = (imageData) =>
new Promise((resolve) => {
const image = new Image();
image.setAttribute("crossOrigin", "anonymous");
image.src = imageData;
image.onload = () => {
resolve(image);
};
});
/**
* @description: canvas绘制二维码并设置大小和位置
*/
drawQrcode = (option) => {
const { url, margin = 1.5 } = option;
return QRCode.toDataURL(url, { margin });
};
/**
* @description: 图片加载到canvas中,并设置位置和大小
*/
drawImageToCancas = (option) => {
const { image, x, y, w, h } = option;
return new Promise((reslove) => {
this.context.drawImage(
image,
x * this.base,
y * this.base,
w * this.base,
h * this.base
);
reslove();
});
};
/**
* @description: 初始化canvas背景
*/
initImageBackground = ({ image }) => {
this.canvas.width = image.width;
this.canvas.height = image.height;
if (this.width) {
this.base = image.width / this.width;
}
return this.drawImageToCancas({
image,
x: 0,
y: 0,
w: image.width / this.base,
h: image.height / this.base,
});
};
/**
* @description: canavs转图片,导出最后的url
*/
outputImage = () =>
new Promise((resolve) => {
const url = this.canvas.toDataURL("image/png");
resolve(url);
});
/**
* @description: 加载自定义字体
*/
importFont = (fontName, fontUrl) =>
new Promise((resolve) => {
const fontface = new FontFace(fontName, fontUrl);
document.fonts.add(fontface);
fontface.load();
fontface.loaded.then(() => resolve());
});
}
链式使用
// 按需引入方法
const { loadingImage, initImageBackground, writeText, drawQrcode, drawImageToCancas, outputImage } = new canvasToImage(1500);
// 设置字体的参数
const textOption = {
fontWeight: 800,
fontSize: 72,
textColor: '#000000',
text: 'text',
x: 400,
y: 2140,
};
// 加载图片
loadingImage(image)
// 加载图片完成后,设置canvas背景图片
.then((image) => initImageBackground({ image }))
// 书写文字,同时设置文字位置,字体,颜色,大小
.then(() => writeText({ ...textOption }))
// 绘制二维码
.then(() => drawQrcode(qrcodeOption))
// 绘制成功后加载图片
.then((qrCodeSrc) => loadingImage(qrCodeSrc))
// 加载图片完成后,绘制进canvas
.then((image) => drawImageToCancas({ image, x: 1028, y: 2145, w: 410, h: 410 }))
// 加载其他图片
.then(() => loadingImage(this.avatar))
// 继续放在canvas中
.then((image) => drawImageToCancas({ image, x: 120, y: 1990, w: 230, h: 230 }))
// 将canvas转化成url
.then(() => outputImage())
// 输出url,进行保存,其他地方使用
.then((res) => {
this.shareImgUrl = res;
})
.catch((error) => console.log('绘制失败', error.message));
- 继续补充中....