canvas的一些简单实用方法汇总

351 阅读3分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

0.为什么要写这篇

原因有两个:

  1. 目前已经存在很多canvas入门,技巧等文章。在开发过程中,我们需要一些能直接使用的canvas方法。把它们进行组合,去实现各种功能。下面是方法汇总,持续补充中,同时也是为了自己记录。
  • 最好拿来就能直接使用。
  • 最好有一个方法列表,方便查询
  1. 本文开头第一句

首先,最基础的创建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));
  • 继续补充中....