自己动手封装canvas公用函数

1,426 阅读2分钟

canvas公用函数封装

前言

在传播和分享中很多时候会用到canvas生成图片进行分享的操作,场景不一需求也不一致,但是有些方法是比较公用,适当的做一些抽离,下边就是我列的几个比较常用的方法。

把长段文字进行多行拆分

// 把需要绘制的文字根据参数改成多行,然后逐行绘制
export const getCanvasMultiLineText = (
  ctx: WechatMiniprogram.CanvasContext,
  options: {
    text: string,
    width: number,
    fontSize: number
  }
) => {
  const {
    text,
    width,
    fontSize
  } = options;
  // 这要单独提一下如果不设置 font-family的话,在小程序端会有展示异常问题
  ctx.font = `${fontSize}px sans-serif`
  ctx.setFontSize(fontSize);

  let textArr: any = text.split(''),
    lineArr: string[] = [],
    line = '';
  textArr.forEach((word: string, index: number) => {
    if (index > 0 && ctx.measureText(`${line}${word}`).width > width) {
      lineArr.push(line);
      line = word;
    } else {
      line = `${line}${word}`;
      if (index === textArr.length - 1) {
        lineArr.push(line)
      }
    }
  });
  return lineArr
}

逐行绘制文本


// 逐行绘制文本
export const drawMultiLineTextOnCanvas = (
  ctx: WechatMiniprogram.CanvasContext,
  options: {
    text: string,
    width: number,
    fontSize: number,
    line?: number,
    color: string,
    align?: "left" | "center" | "right",
    baseline?: "top" | "bottom" | "middle" | "normal",
    x: number,
    y: number,
    lineHeight?: number
  }
) => {
  const {
    text,
    width,
    fontSize,
    line = 1,
    color,
    align = 'left',
    baseline = 'top',
    x,
    y,
    lineHeight = fontSize * 1.5
  } = options;
  let textLineArr: any = getCanvasMultiLineText(ctx, { text, width, fontSize })
  textLineArr.slice(0, line).forEach((str: string, index: number) => {
    let textTemp = textLineArr.length > line && index === line - 1
      ? `${str.substring(0, str.length - 2)}...`
      : str;
    ctx.save();
    ctx.setFillStyle(color);
    ctx.setFontSize(fontSize);
    ctx.setTextAlign(align);
    ctx.setTextBaseline(baseline);
    ctx.fillText(textTemp, x, y + index * lineHeight);
    ctx.restore();
  });
}

小程序网络图片转本地图片

// 小程序网络图片转本地图片
export const getLocalePathFromNetImgUrl = (images: string[]) => {
  const promises: any = [];
  images.forEach((image: any, index: number) => {
    const promise = new Promise((resolve, reject) => {
      wx.getImageInfo({
        src: image,
        success: res => {
          resolve(extend(true, {
            index
          }, res))
        },
        fail: reject
      })
    })
    promises.push(promise);
  })
  return Promise.all(promises)
}

canvas圆角方法

roundRect(ctx: any, x: number, y: number, w: number, h: number, r: number, c: string) {
  if (w < 2 * r) {
    let r = w / 2;
  }
  if (h < 2 * r) {
    let r = h / 2;
  }

  ctx.beginPath();
  ctx.fillStyle = c;

  ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.lineTo(x + w, y + r);

  ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
  ctx.lineTo(x + w, y + h - r);
  ctx.lineTo(x + w - r, y + h);

  ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);
  ctx.lineTo(x + r, y + h);
  ctx.lineTo(x, y + h - r);

  ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);
  ctx.lineTo(x, y + r);
  ctx.lineTo(x + r, y);

  ctx.fill();
  ctx.closePath();
},

canvas 圆形方法

// canvas 圆形方法
getCirclePic(ctx: any, x: number, y: number, r: number, pic: string, dx: number, dy: number, dWidth: number, dHeight: number) {
  //  x:圆心x轴位置 
  //  y:圆心y轴位置 
  //  r:圆半径
  //  pic:图片 
  //  dx:图片左上角x轴位置
  //  dy:图片左上角y轴位置 
  //  dWidth:图片的宽 
  //  dHeight:图片的高
  ctx.save();
  ctx.beginPath();
  ctx.arc(x, y, r, 0, 2 * Math.PI, false);
  ctx.fill();
  ctx.clip();
  ctx.drawImage(pic, dx, dy, dWidth, dHeight);
  ctx.restore();
},

总结

公用的方法目前封装了这几个,如果以后还有其他的需求,在进行填充,生命不息,代码重构不止~

如果小伙伴们觉得有用的话欢迎点赞分享~

如果有其他好的方法也可以评论区留言,大家一同进步~