美文网首页
小程序Canvas分享(或者类似分享的海报)

小程序Canvas分享(或者类似分享的海报)

作者: 张成的开发笔记 | 来源:发表于2019-08-20 10:31 被阅读0次

微信小程序分享之canvas绘图

image

使用场景

我们在微信小程序中分享页面时使用了onShareAppMessage方法,该方法返回一个对象,包括:

  1. title 分享的卡片标题
  2. imageUrl 自定义图片路径(可以是本地文件路径、代码包文件路径或者网络图片路径。支持PNG及JPG。显示图片长宽比是 5:4。)
  3. path 转发路径(当前页面 path ,必须是以 / 开头的完整路径)
// 分享
onShareAppMessage() {
    return {
        title: this.cruiseLineInfo.title, // 分享的卡片标题
        imageUrl: this.shareImageUrl, // 分享的图片(如果不传默认本页面截图)
        path: `/pages/cruise/cruisedetail/main?lineId=...` // 分享给好友的路径
    };
}

如何自定义图片内容?

那么就要用到canvas了~

1. 拿到一些基本的数据

  1. img :背景图片(这里用的是邮轮船队的大图,用resizeImage将图片转换为5:4的比例)
  2. title 邮轮 | 222101
  3. price 价格
  4. isDiscount 是否是优惠线路
  5. info 其他信息:“8888人购买 98%满意度” 或 “新产品推荐”

2. 在页面中放入canvas

<canvas
    canvas-id="shareCanvas"
    style="width: 450px; height: 360px;"
    hidden="true"
></canvas>

值得注意的是 canvas本身并不是我们所需要的,我们需要的是绘制完的canvas转化后的临时路径,所以canvas需要隐藏。

但是canvas如果直接用 display:none 或者 wx:if 来隐藏,会导致canvs无法进行工作。

我们可以使用 hidden="true" 或者直接用 hidden 进行隐藏,但是这种方法在微信开发者工具上会导致无法绘制,但是真机上都可以。

也或者,可以使用一个view包裹住canvas,设置包裹view的样式为 position:fixed; top:-9999px;z-index:-1; 将它“移出”屏幕即可。

3. 网络图片记得转为本地图片

因为真机上网络图片无法用于绘制canvas,我们需要使用getImageInfo拿到网络图片的本地临时路径,用Promise来避免回调嵌套

// 处理网络图片变为本地图片
dealImg() {
  let that = this;
  Promise.all([
    // 背景图片
    new Promise(resolve => {
      wx.getImageInfo({
        src: that.data.img,
        success: (re) => {
          resolve(re.path);
        }
      });
    }),
    // 折扣图片
    new Promise(resolve => {
      wx.getImageInfo({
        src: "https://file.40017.cn/hubble/pic/discount.png",
        success: (re) => {
          resolve(re.path);
        }
      });
    })
  ]).then(result => {
    that.setData({
      img: result[0],
      discountImg: result[1]
    })
    that.drawCanvas();
  });
},

canvas上场

为什么要 ctx.save() ctx.restore()

  1. save表示保存save函数之前的状态,restore表示获取save保存的状态
  2. 每一次调用 save 方法,当前的状态就会被推入堆中保存起来, restore 的时候释放出来

图片

ctx.save();
ctx.drawImage(imgUrl, 0, 0, 450, 360);
ctx.restore();

写字

let ctx = wx.createCanvasContext('shareCanvas')
// ctx.translate(20, 20)
// ctx.setFontSize(20)
// ctx.setFillStyle('black')
// ctx.setTextAlign('left')
ctx.fillText("哈哈哈", 20, 20, 200)
ctx.draw()

线

const ctx = wx.createCanvasContext('shareCanvas')
ctx.moveTo(10, 10)
ctx.lineTo(100, 10)
ctx.lineTo(100, 100)
ctx.stroke()
ctx.draw()

实线矩形

const ctx = wx.createCanvasContext('shareCanvas')
ctx.setStrokeStyle('red')
ctx.strokeRect(10, 10, 150, 75)
ctx.draw()

填充矩形

const ctx = wx.createCanvasContext('shareCanvas')
ctx.setFillStyle('red')
ctx.fillRect(10, 10, 150, 75)
ctx.draw()

const ctx = wx.createCanvasContext('shareCanvas')
// Draw arc
ctx.beginPath()
ctx.arc(100, 75, 50, 0, 2 * Math.PI)
ctx.setStrokeStyle('#333333')
ctx.stroke()
ctx.draw()

实线圆角矩形

填充圆角矩形

渐变色

const ctx = wx.createCanvasContext('shareCanvas')
let grd = ctx.createLinearGradient(0, 0, 0, 360);
grd.addColorStop(0, 'rgba(0,0,0,0)');
grd.addColorStop(0.5, 'rgba(0,0,0,0.05)');
grd.addColorStop(0.7, 'rgba(0,0,0,0.5)');
grd.addColorStop(1, 'rgba(0,0,0,0.9)');
ctx.setFillStyle(grd);
ctx.fillRect(0, 0, 450, 360);
ctx.draw()

全部代码

<canvas
    canvas-id="shareCanvas"
    style="width: 450px; height: 360px;"
    hidden="true"
></canvas>
Page({

  /**
   * 页面的初始数据
   */
  data: {
    img: "https://pic5.40017.cn/02/000/6f/69/rBANDFk5ELWAAtBcAAgAAHoheBo892_450x360_00.png",
    title: "邮轮  |  222101",
    titleL: 0,
    price: 4699,
    priceL: 0,
    isDiscount: true,
    info: "8888人购买   98%满意度",
    shareImageUrl: "",
    discountImg: ""
  },

  onLoad: function (options) {
    this.setData({
      titleL: this.data.title.length * 15,
      priceL: (this.data.price + '').length
    });
    this.dealImg();
  },

  // 处理网络图片变为本地图片
  dealImg() {
    let that = this;
    Promise.all([
      // 背景图片
      new Promise(resolve => {
        wx.getImageInfo({
          src: that.data.img,
          success: (re) => {
            resolve(re.path);
          }
        });
      }),
      // 折扣图片
      new Promise(resolve => {
        wx.getImageInfo({
          src: "https://file.40017.cn/hubble/pic/discount.png",
          success: (re) => {
            resolve(re.path);
          }
        });
      })
    ]).then(result => {
      that.setData({
        img: result[0],
        discountImg: result[1]
      })
      that.drawCanvas();
    });
  },

  // 绘制canvas
  drawCanvas() {
    let that = this;
    // 创建 canvas 的绘图上下文 CanvasContext 对象
    let ctx = wx.createCanvasContext('shareCanvas');
    
    ctx.save();// 保存绘图上下文

    // 绘制背景图片
    ctx.drawImage(that.data.img, 0, 0, 450, 360);
    
    ctx.restore();// 恢复之前保存的绘图上下文

    //圆角填充矩形 起始坐标20,20 宽高titleL*36  圆角半径4
    that.fillRoundRect(ctx, 20, 20, that.data.titleL, 36, 4, 'rgba(0,0,0,0.6)');

    //写字(邮轮 | 222101) 起始坐标 titleL / 2, 26 最大长度titleL
    ctx.save();
    ctx.translate(20, 20);
    ctx.setFontSize(22);
    ctx.setFillStyle('white');
    ctx.setTextAlign('center');
    ctx.fillText(that.data.title, that.data.titleL / 2, 26, that.data.titleL);
    ctx.restore();

    //底部渐变蒙层
    ctx.save();
    let grd = ctx.createLinearGradient(0, 0, 0, 360);
    grd.addColorStop(0, 'rgba(0,0,0,0)');
    grd.addColorStop(0.5, 'rgba(0,0,0,0.05)');
    grd.addColorStop(0.7, 'rgba(0,0,0,0.5)');
    grd.addColorStop(1, 'rgba(0,0,0,0.9)');
    ctx.setFillStyle(grd);
    ctx.fillRect(0, 0, 450, 360);
    ctx.restore();

    //价格
    that.setPrice(ctx, that.data.price, that.data.priceL);

    //优惠立减
    if (that.data.isDiscount) {
      ctx.save();
      ctx.drawImage(that.data.discountImg, that.data.priceL * 25 + 50, 226, 108, 32);
      ctx.restore();
    }
    //产品描述(满意度、销量、新品推荐等)
    ctx.save();
    ctx.setFontSize(20);
    ctx.setFillStyle('rgba(255,255,255,0.7)');
    ctx.fillText(that.data.info, 20, 335);
    ctx.restore();
    
    // 结束绘制
    ctx.draw(true, function () {
      wx.canvasToTempFilePath({
        x: 0,
        y: 0,
        width: 450,
        height: 360,
        destWidth: 500,
        destHeight: 400,
        canvasId: "shareCanvas",
        success: function (res) {
          that.setData({
            shareImageUrl: res.tempFilePath
          });
        }
      });
    });
  },

  onShareAppMessage() {
    let that = this;
    return {
      title: "【盛世公主号】上海-福冈(日本)-上海 4晚5日游", // 分享的卡片标题
      imageUrl: that.data.shareImageUrl, // 分享的图片(如果不传默认本页面截图)
      path: `/pages/canvas/canvas/main` // 分享给好友的路径
    };
  },

  //绘制价格
  setPrice(ctx, price, priceL) {
    ctx.save();
    ctx.setFontSize(24);
    ctx.setFillStyle('#FFCD17');
    if (price) {
      ctx.fillText("¥", 20, 295);
      ctx.setFontSize(46);
      ctx.fillText(price, 36, 295);
      ctx.setFontSize(20);
      ctx.fillText("/人起", priceL * 25 + 50, 293);
    } else {
      ctx.fillText("实时计价", 20, 295);
    }
    ctx.restore();
  },

  /**该方法用来绘制一个有填充色的圆角矩形 yes
    *@param ctx canvas的上下文环境
    *@param x 左上角x轴坐标
    *@param y 左上角y轴坐标
    *@param width 矩形的宽度
    *@param height 矩形的高度
    *@param radius 圆的半径
    *@param fillColor 填充颜色
  **/
  fillRoundRect(ctx, x, y, width, height, radius, fillColor) {
    //圆的直径必然要小于矩形的宽高
    if (2 * radius > width || 2 * radius > height) { return false; }

    ctx.save();

    // 对当前坐标系的原点 (0, 0) 进行平移
    ctx.translate(x, y);

    // 开始创建一个路径 需要调用 fill(填充) 或者 stroke(画框) 才会使用路径进行填充或描边
    ctx.beginPath();

    //从右下角顺时针绘制,弧度从0到1/2PI(圆的周长是2*PI*R,1/4圆就是PI/2)
    ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2, false);

    //矩形下边线
    ctx.lineTo(radius, height);

    //左下角圆弧,弧度从1/2PI到PI
    ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI, false);

    //矩形左边线
    ctx.lineTo(0, radius);

    //左上角圆弧,弧度从PI到3/2PI
    ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2, false);

    //上边线
    ctx.lineTo(width - radius, 0);

    //右上角圆弧
    ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2, false);

    //右边线
    ctx.lineTo(width, height - radius);

    // 关闭一个路径。会连接起点和终点。如果关闭路径后没有调用 fill 或者 stroke 并开启了新的路径,那之前的路径将不会被渲染。
    ctx.closePath();

    // 填充颜色
    // ctx.stroke()
    ctx.setFillStyle(fillColor || "#000");
    ctx.fill();
    ctx.restore();
  }

})

相关文章

网友评论

      本文标题:小程序Canvas分享(或者类似分享的海报)

      本文链接:https://www.haomeiwen.com/subject/hgrskctx.html