小程序canvas常见画图(圆形图片,导出图片,多行文本...)

118 阅读2分钟

文中所有参数为canvas的定义

const query = wx.createSelectorQuery()
query.select('#poster').fields({ node: true, size: true }).exec(async (res) => {
    const canvas = res[0].node
    //此处的canvas即下列封装方法参数cavans
})

1:矩形

// 绘制矩形
export const drawRect = (ctx: CanvasRenderingContext2D, width: number, height: number, backgroundColor = '#fff', x = 0, y = 0): Promise<boolean> => {
  return new Promise(resolve => {
    ctx.save()
    ctx.rect(x, y, width, height)
    ctx.fillStyle = backgroundColor
    ctx.fill()
    ctx.restore()
    resolve(true)
  })
}

2:绘制文字

export const drawText = (ctx: CanvasRenderingContext2D, content: string, color = '#fff', size = 14, fontWeight = 400, fontFamily = 'Alibaba-PuHuiTi-R, Alibaba-PuHuiTi', x = 0, y = 0): Promise<boolean> => {
  return new Promise(resolve => {
    ctx.save()
    ctx.textBaseline = 'top'
    ctx.textAlign = 'left'
    ctx.font = `normal ${fontWeight} ${size}px ${fontFamily}`
    ctx.fillStyle = color
    ctx.fillText(content, x, y)
    ctx.restore()
    resolve(true)
  })
}

3:绘制多行文本

// width指文本宽度多少时换行
export const drawMultiLineText = (ctx: CanvasRenderingContext2D, width: number, lineHeight: number, content: string, x = 0, y = 0, color = '#fff', size = 14, fontWeight = 400, fontFamily = 'Alibaba-PuHuiTi-R, Alibaba-PuHuiTi',): Promise<boolean> => {
  return new Promise(resolve => {
    ctx.save();
    let arrText = content.split("");
    let line = "";
    ctx.font = `normal ${fontWeight} ${size}px ${fontFamily}`
    ctx.fillStyle = color
    ctx.textBaseline = "top";
    ctx.textAlign = 'left'
    for (let n = 0; n < arrText.length; n++) {
      let testLine = line + arrText[n];
      let metrics = ctx.measureText(testLine);
      let testWidth = metrics.width;
      if (testWidth > width && n > 0) {
        ctx.fillText(line, x, y);
        line = arrText[n];
        y += lineHeight;
      } else {
        line = testLine;
      }
    }
    ctx.fillText(line, x, y);
    ctx.restore();
    resolve(true);
  });
}

4:绘制图片

//此处canvas参数请查看文章开头注释
export const drawImage = (canvas: any, ctx: CanvasRenderingContext2D, src: string, width: number, height: number, x = 0, y = 0): Promise<boolean> => {
  return new Promise(resolve => {
    const nowTime = new Date().getTime()
    ctx.save()
    let pic = canvas.createImage();
    pic.src = `${src}?${nowTime}`//nowTime防止图片缓存
    pic.onload = () => {
      ctx.drawImage(pic, x, y, width, height);
      ctx.restore()
      resolve(true)
    }
  })
}

5:绘制圆形图片

//此处canvas参数请查看文章开头注释
//此处的x与y记住需要加上原型图片的半径;原理自己思考;
export const drawCircleImage = (canvas: any, ctx: CanvasRenderingContext2D, src: string, r: number, x = 0, y = 0,): Promise<boolean> => {
    return new Promise(async resolve => {
        ctx.save()
        ctx.beginPath();
        ctx.arc(x, y, r, 0, Math.PI * 2, false);
        ctx.clip();
        //此处的drawImage即 4:绘制图片方法
        await drawImage(canvas, ctx, src, r * 2, r * 2, x - r, y - r)
        ctx.restore()
        resolve(true)
    })
}

6:绘制圆形图片&&带边框

//此处canvas参数请查看文章开头注释
//此处的x与y记住需要加上原型图片的半径以及border宽度;原理自己思考;
export const drawCircleImageWithBorder = (canvas: any, ctx: CanvasRenderingContext2D, src: string, x = 0, y = 0, r = 0, borderWidth = 1, backgroundColor = "#fff", borderColor = '#fff'): Promise<boolean> => {
  return new Promise(resolve => {
    ctx.save()
    ctx.beginPath()
    ctx.arc(x, y, r + borderWidth, 0, Math.PI * 2, false)
    ctx.fillStyle = borderColor
    ctx.fill()
    ctx.save()
    ctx.beginPath()
    ctx.arc(x, y, r + borderWidth, 0, Math.PI * 2, false)
    ctx.fillStyle = backgroundColor
    ctx.fill()
    ctx.clip()
    wx.downloadFile({
      url: src,
      success: async (res) => {
        if (res.statusCode === 200) {
            //此处的drawImage即 4:绘制图片方法
          await drawImage(canvas, ctx, res.tempFilePath, r * 2, r * 2, x - r, y - r,)
          ctx.restore()
          resolve(true)
        }
      }
    })
  })
}

7:测量文本宽度

export const measureTextWidth = (ctx: CanvasRenderingContext2D, content: string, fontWeight = 400, size = 14, fontFamily = 'Alibaba-PuHuiTi-R, Alibaba-PuHuiTi'): number => {
  ctx.font = `normal ${fontWeight} ${size}px ${fontFamily}`
  const width = ctx.measureText(content).width
  return width
}

8:cavans导出图片

// 画布导出=>图片
//此处canvas参数请查看文章开头注释
export const canvasToImage = (canvas: any, width: number, height: number, x = 0, y = 0): Promise<boolean> => {
  return new Promise(resolve => {
    wx.canvasToTempFilePath({
      canvas,
      x,
      y,
      width, //自己定义canvas的宽度
      height, //自己定义canvas的高度
      success: function (res) {
        let tempFilePath = res.tempFilePath
        wx.saveImageToPhotosAlbum({
          filePath: tempFilePath,
          success: function () {
            resolve(true)
          },
          fail: (err) => {
            wx.hideLoading()
            if (err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" || err.errMsg === "saveImageToPhotosAlbum:fail auth deny" || err.errMsg === "saveImageToPhotosAlbum:fail authorize no response") {
              wx.showModal({
                title: '提示',
                content: '请授权保存到相册',
                showCancel: false,
                success() {
                  wx.openSetting({
                    success(openres) {
                      if (openres.authSetting['scope.writePhotosAlbum']) {
                        console.log('获取权限成功')
                      } else {
                        console.log('获取权限失败')
                      }
                    },
                    fail(failerr) {
                      console.log("failerr", failerr)
                    }
                  })
                }
              })
            }
          }
        })
      },
      fail: function (res) {
        console.log(res)
        wx.hideLoading()
      }
    })
  })
}