编辑代码

/**
 * 生成canvas海报
 */
export default class GenerateCanvas {
  // canvas 的宽/高
  canvasWidth = 314
  canvasHeight = 376

  // canvas的节点本身
  canvas = null
  // canvas的上下文
  context = null

  constructor(node) {
    this.canvas = node
    this.context = this.canvas.getContext('2d')
    this.resizeCanvas()
  }

  /**
   * 调整canvas
   */
  resizeCanvas() {
    const dpr = uni.getSystemInfoSync().pixelRatio
    this.canvas.width = this.canvasWidth * dpr
    this.canvas.height = this.canvasHeight * dpr
    this.context.scale(dpr, dpr)
  }

  /**
   * 绘制文本
   * @param {string} text 文本
   * @param {number} x
   * @param {number} y
   * @param {object} options 文字的css属性
   */
  drawText(text, x, y, options = {}) {
    this.context.font = `${options.fontWeight || ''} ${options.fontSize}px cursive`
    this.context.fillStyle = options.color || '#2A2A2A'
    this.context.textAlign = options.textAlign || 'start'
    this.context.textBaseline = options.textBaseline || 'hanging'
    this.context.fillText(text, x, y)
  }

  /**
   * 绘制旋转文字
   * @param {*} text
   * @param {*} x
   * @param {*} y
   * @param {*} options
   */
  drawRotateText(text, x, y, options = {}) {
    this.context.save()
    const width = this.context.measureText(text).width
    // 移动画布
    this.context.translate(x + options.fontSize / 2, y)
    this.context.rotate((90 * Math.PI) / 180)
    this.drawText(text, 0, 0, options)
    this.context.restore()
  }

  /**
   * 绘制换行文字
   * @param {string} text 文本
   * @param {number} chunkSize 切割的大小
   * @param {number} x x 坐标
   * @param {number} y y 坐标
   * @param {number} gap 间距
   * @param {object} options 文本属性
   */
  drawLineFeedText(text, chunkSize, x, y, gap, options = {}) {
    const splitText = this.splitString(text, chunkSize)
    splitText.forEach((text) => {
      this.drawText(text, x, (y += gap), options)
    })
  }

  splitString(str, size) {
    const chunks = []
    for (let i = 0; i < str.length; i += size) {
      const chunk = str.substring(i, i + size)
      chunks.push(chunk)
    }
    return chunks
  }

  /**
   * 绘制线条
   * @param {Array<number>} startPoint 开始端点 [x,y]
   * @param {Array<number>} endPoint 结束端点 [x,y]
   */
  drawLine(startPoint, endPoint) {
    const [sx, sy] = startPoint
    const [ex, ey] = endPoint
    this.context.beginPath()
    this.context.strokeStyle = '#A79F88'
    this.context.lineWidth = 0.5
    this.context.moveTo(sx, sy)
    this.context.lineTo(ex, ey)
    this.context.stroke()
    this.context.closePath()
  }

  /**
   * 绘制图像,并可选地进行圆形裁剪
   *
   * @param {Image} image - 要绘制的图像对象
   * @param {number} x - 绘制起始点的 x 坐标
   * @param {number} y - 绘制起始点的 y 坐标
   * @param {number} width - 图像的宽度
   * @param {number} height - 图像的高度
   * @param {number} radius - 圆形裁剪的半径
   */
  drawImage(imagePath, x, y, width, height, radius = 0) {
    this.createImage(imagePath).then((image) => {
      this.drawWithOptionalClip(image, x, y, width, height, radius)
    })
  }

  drawPattern(imagePath) {
    this.createImage(imagePath).then((image) => {
      const pattern = this.context.createPattern(image, 'no-repeat')
      this.drawRect(0, 0, this.canvasWidth, this.canvasHeight, pattern)
    })
  }

  createImage(path) {
    return new Promise((resolve, reject) => {
      const image = this.canvas.createImage()
      image.src = path
      image.onload = () => {
        resolve(image)
      }
    })
  }

  /**
   * 辅助函数:绘制图像,并可选地进行圆形裁剪
   *
   * @param {Image} image - 要绘制的图像对象
   * @param {number} x - 绘制起始点的 x 坐标
   * @param {number} y - 绘制起始点的 y 坐标
   * @param {number} width - 图像的宽度
   * @param {number} height - 图像的高度
   * @param {number} radius - 圆形裁剪的半径
   */
  drawWithOptionalClip(imagePath, x, y, width, height, radius = 0) {
    if (radius > 0) {
      this.context.save()
      this.context.beginPath()
      this.context.arc(x + width / 2, y + height / 2, radius, 0, 2 * Math.PI)
      this.context.clip()
    }
    this.context.drawImage(imagePath, x, y, width, height)

    if (radius > 0) {
      this.context.restore()
    }
  }

  /**
   * 绘制矩形
   * @param {number} x x 坐标
   * @param {number} y y 坐标
   * @param {number} width 宽度
   * @param {number} height 高度
   * @param {string} color 颜色
   */
  drawRect(x, y, width, height, color = '#A79F88') {
    this.context.fillStyle = color
    this.context.fillRect(x, y, width, height)
  }
}