小程序画布画海报

wxml文件

<view class='poste_box' id='canvas-container' bindlongpress="saveShareImg">
  <canvas canvas-id="myCanvas" style="width:calc(100% - 10px);height:920rpx; margin:0 auto"/>
</view>

wxss文件

page {
  background-color: #fff;
}

.poste_box {
  width: 82%;
  margin: auto;
  margin-top: 50rpx;
  background-color: #f8f8f8;
  /* border: 1rpx solid #ddd; */
  box-shadow:0px 0px  10px 5px #D8D7DD;
  border-radius: 30rpx;
  overflow: hidden;
  padding: 20rpx 0;
}

js文件

const app = getApp();
const util = require('../../../utils/util.js');//工具类
Page({

  /**
   * 页面的初始数据
   */
  data: {
    cardInfo: {
      avater: "", //主图
      qrCode: "", //二维码
      price: "", //价格
      Name: "", //商品名称
      userName: "", //用户名
      tips: "为你推荐", //提示语
    }
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    app.get_visitor()
    var data = app.globalData.poster_data//海报需要的资料
    const that = this
    var id = data.id
    var price_a = util.toPrice(data.now_price, true)
    var price_b = util.toPrice(data.now_price, false)
    console.log(app.globalData.userInfo)
    that.setData({
      'cardInfo.avater': data.avater,
      'cardInfo.Name': data.title,
      'cardInfo.price_a': price_a,
      'cardInfo.price_b': price_b,
      'cardInfo.orgin_price': data.orgin_price,//商品原价
      'cardInfo.userName': app.globalData.userInfo.nickName,//用户名称
      'cardInfo.txSrc': app.globalData.userInfo.avatarUrl,//头像
    })
      this.show_poster(id)
    }
  },
  /**
 * 先下载头像图片
 */
  getAvaterInfo: function () {
    wx.showLoading({
      title: '生成中...',
      mask: true,
    });
    var that = this;
    wx.downloadFile({
      url: that.data.cardInfo.avater, //头像图片路径
      success: function (res) {
        wx.hideLoading();
        if (res.statusCode === 200) {
          var avaterSrc = res.tempFilePath; //下载成功返回结果
          that.getQrCode(avaterSrc); //继续下载二维码图片
        } else {
          wx.showToast({
            title: '主图下载失败!',
            icon: 'none',
            duration: 2000,
            success: function () {
              var avaterSrc = "";
              that.getQrCode(avaterSrc);
            }
          })
        }
      }
    })
  },

  /**
   * 下载二维码图片
   */
  getQrCode: function (avaterSrc) {
    wx.showLoading({
      title: '生成中...',
      mask: true,
    });
    var that = this;
    if (!that.data.cardInfo.qrCode) {
      wx.showToast({
        title: '二维码加载失败!',
        icon: 'none',
        duration: 2000
      })
      return false
    }
    wx.downloadFile({
      url: that.data.cardInfo.qrCode, //二维码路径
      success: function (res) {
        wx.hideLoading();
        if (res.statusCode === 200) {
          var codeSrc = res.tempFilePath;
          that.getUserImg(avaterSrc, codeSrc);
        } else {
          wx.showToast({
            title: '二维码下载失败!',
            icon: 'none',
            duration: 2000,
            success: function () {
              var codeSrc = "";
              that.getUserImg(avaterSrc, codeSrc);
            }
          })
        }
      }
    })
  },
  /**
   * 下载头像
   */
  getUserImg: function (avaterSrc, codeSrc) {
    wx.showLoading({
      title: '生成中...',
      mask: true,
    });
    var that = this;
    wx.downloadFile({
      url: that.data.cardInfo.txSrc, //二维码路径
      success: function (res) {
        wx.hideLoading();
        if (res.statusCode === 200) {
          var txSrc = res.tempFilePath;
          that.sharePosteCanvas(avaterSrc, codeSrc, txSrc);
        } else {
          wx.showToast({
            title: '头像失败!',
            icon: 'none',
            duration: 2000,
            success: function () {
              var txSrc = "";
              that.sharePosteCanvas(avaterSrc, codeSrc, txSrc);
            }
          })
        }
      }
    })
  },

  /**
   * 开始用canvas绘制分享海报
    */
  sharePosteCanvas: function (avaterSrc, codeSrc, txSrc) {
    wx.showLoading({
      title: '生成中...',
      mask: true,
    })
    var that = this;
    var cardInfo = that.data.cardInfo; //需要绘制的数据集合
    const ctx = wx.createCanvasContext('myCanvas'); //创建画布
    var width = "";
    wx.createSelectorQuery().select('#canvas-container').boundingClientRect(function (rect) {
      var height = rect.height;
      var right = rect.right;
      width = (rect.width - 10) * 0.92;
      var left = width * 0.04;
      ctx.setFillStyle('#f8f8f8');
      ctx.fillRect(0, 0, rect.width, height);


      //名字
      var userNameWidth = 0
      if (cardInfo.userName) {
        ctx.setFontSize(13);
        ctx.setFillStyle('#333');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.userName, left + 31, 19);
        userNameWidth = ctx.measureText(cardInfo.userName).width
      }

      //提示语
      if (cardInfo.tips) {
        ctx.setFontSize(12);
        ctx.setFillStyle('#B8B8B8');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.tips, left + userNameWidth + 38, 18);
      }
      //  绘制头像
      if (txSrc) {
        ctx.save();
        ctx.beginPath();
        ctx.arc(left + 11, 16, 11, 0, 2 * Math.PI);//切圆角
        // 从画布上裁剪出这个圆形
        ctx.clip();
        ctx.drawImage(txSrc, left, 5, 22, 22)
        ctx.restore();
      }


      // 绘制矩形(背景色)
      ctx.save()
      that.roundRect(ctx, left, width + 28, width, 105, 8)
      ctx.clip()
      ctx.beginPath();//开始一个新的路径
      ctx.setFillStyle('#fff');//矩形颜色
      ctx.fillRect(left, width + 28, width, 105);//添加实心矩形
      ctx.stroke();//对当前路径进行描边
      ctx.closePath();//关闭当前路径
      ctx.restore()
      //商品主图为圆角
      if (avaterSrc) {
        ctx.save()
        that.roundRect(ctx, left, 40, width, width, 10)
        ctx.clip()
        ctx.drawImage(avaterSrc, left, 40, width, width);
        ctx.restore()
      }
      //价格
      // 绘制‘¥’
      var coinwidth = 0
      if (cardInfo.price_a) {
        ctx.setFontSize(14);
        ctx.setFillStyle('#F24F4C');
        ctx.setTextAlign('left');
        ctx.fillText(that.data.monetary_unit, left + 8, width + 85, width - 4);
        coinwidth = ctx.measureText(that.data.monetary_unit).width
      }
      //绘制价格第一个字符
      var pricewidth = 0
      if (cardInfo.price_a) {
        ctx.setFontSize(20);
        ctx.setFillStyle('#F24F4C');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.price_a, left + coinwidth + 8, width + 85, width - 4);
        pricewidth = ctx.measureText(cardInfo.price_a)
        console.log(pricewidth)
      }
      //绘制价格第二个字符
      if (cardInfo.price_b) {
        ctx.setFontSize(14);
        ctx.setFillStyle('#F24F4C');
        ctx.setTextAlign('left');
        ctx.fillText(cardInfo.price_b, left + coinwidth + pricewidth.width + 8, width + 85, width - 4);
      }
      // 绘制原价
      // if (cardInfo.orgin_price){
      //     ctx.setFontSize(14);
      //     ctx.setFillStyle('#999');
      //     ctx.setTextAlign('left'); 
      //     ctx.setStrokeStyle("#999")
      //     ctx.fillText(that.data.monetary_unit + cardInfo.orgin_price, left + coinwidth +44 + pricewidth.width, width + 36, width - 4);
      //     var linewidth = ctx.measureText(that.data.monetary_unit + cardInfo.orgin_price)
      //     ctx.moveTo(left + coinwidth + 44 + pricewidth.width, width + 30)
      //     ctx.lineTo(left + coinwidth + 44 + pricewidth.width + linewidth.width, width + 30)
      //     ctx.stroke()
      // }
      //标题
      if (cardInfo.Name) {
        ctx.setTextAlign('left');
        var text = cardInfo.Name
        var chr = text.split("");//这个方法是将一个字符串分割成字符串数组
        var temp = "";
        var row = [];
        ctx.setFontSize(14)
        ctx.setFillStyle("#333")
        for (var a = 0; a < chr.length; a++) {
          if (ctx.measureText(temp).width < 0.60 * width) {
            temp += chr[a];
          }
          else {
            a--; //这里添加了a-- 是为了防止字符丢失,效果图中有对比
            row.push(temp);
            temp = "";
          }
        }
        row.push(temp);

        //如果数组长度大于2 则截取前两个
        if (row.length > 2) {
          var rowCut = row.slice(0, 2);
          var rowPart = rowCut[1];
          var test = "";
          var empty = [];
          for (var a = 0; a < rowPart.length; a++) {
            if (ctx.measureText(test).width < 0.60 * width) {
              test += rowPart[a];
            }
            else {
              break;
            }
          }
          empty.push(test);
          var group = empty[0] + "..."//这里只显示两行,超出的用...表示
          rowCut.splice(1, 1, group);
          row = rowCut;
        }
        for (var b = 0; b < row.length; b++) {
          ctx.fillText(row[b], left + 8, width + 110 + b * 20, 300);
        }
      }

      //  绘制二维码
      if (codeSrc) {
        ctx.drawImage(codeSrc, width * 0.772, width + 55, width * 0.228, width * 0.228)
      }
      // 绘制长按识别二维码扫一扫购买
      ctx.setFontSize(12);
      ctx.setFillStyle('#B8B8B8');
      ctx.setTextAlign('left');
      ctx.fillText('长按识别二维码扫一扫购买', left + 66, width + 175);

      //虚线
      // ctx.setStrokeStyle("#e5e5e5")//设置线条的颜色
      // ctx.setLineWidth(1)//设置线条宽度
      // that.drawDashLine(ctx, left, width + 100, width+left+4, width + 100, 4)





    }).exec()

    setTimeout(function () {
      ctx.draw();
      wx.hideLoading();
    }, 1000)

  },

  // 切圆角,只兼容苹果
  roundRect(ctx, x, y, w, h, r) {
    // ctx要操作的画布,x:x轴距离,y:y轴距离,w:图片宽度,h:图片高度,r:圆角弧度
    var min_size = Math.min(w, h);
    if (r > min_size / 2) r = min_size / 2;
    // 开始绘制
    ctx.beginPath();//开始创建一个路径。需要调用 fill 或者 stroke 才会使用路径进行填充或描边
    ctx.moveTo(x + r, y);//把路径移动到画布中的指定点,不创建线条。用 stroke 方法来画线条x+r(目标位置的 x 坐标)y:(目标位置的 y 坐标)
    ctx.arcTo(x + w, y, x + w, y + h, r);//切圆角x+w(第一个控制点的 x 轴坐标),y(第一个控制点的 y 轴坐标),x+w(第二个控制点的 x 轴坐标)y+h(第二个控制点的 y 轴坐标),r(圆角弧度)
    ctx.arcTo(x + w, y + h, x, y + h, r);
    ctx.arcTo(x, y + h, x, y, r);
    ctx.arcTo(x, y, x + w, y, r);
    ctx.closePath();//关闭一个路径
    return ctx;
  },

  //点击长按保存到相册
  saveShareImg: function () {
    var that = this;
    wx.showLoading({
      title: '正在保存',
      mask: true,
    })
    setTimeout(function () {
      wx.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: function (res) {
          wx.hideLoading();
          var tempFilePath = res.tempFilePath;
          wx.saveImageToPhotosAlbum({
            filePath: tempFilePath,
            success(res) {

            },
            fail: function (res) {
              wx.showToast({
                title: res.errMsg,
                icon: 'none',
                duration: 2000
              })
            }
          })
        }
      });
    }, 1000);
  },
  //画虚线
  drawDashLine: function (ctx, x1, y1, x2, y2, dashLength) {  //传context对象,始点x和y坐标,终点x和y坐标,虚线长度
    var dashLen = dashLength === undefined ? 3 : dashLength,
      xpos = x2 - x1, //得到横向的宽度;
      ypos = y2 - y1, //得到纵向的高度;
      numDashes = Math.floor(Math.sqrt(xpos * xpos + ypos * ypos) / dashLen);
    //利用正切获取斜边的长度除以虚线长度,得到要分为多少段;
    for (var i = 0; i < numDashes; i++) {
      if (i % 2 === 0) {
        ctx.moveTo(x1 + (xpos / numDashes) * i, y1 + (ypos / numDashes) * i);
        //有了横向宽度和多少段,得出每一段是多长,起点 + 每段长度 * i = 要绘制的起点;
      } else {
        ctx.lineTo(x1 + (xpos / numDashes) * i, y1 + (ypos / numDashes) * i);
      }
    }
    ctx.stroke();
  },
  //获取二维码
  show_poster: function (id) {
    const _this = this;
    util.requestData({
      url: '后台接口',
      method: 'POST',
      data: {
        pro_id: id,
      },
      success: function (res) {
        console.log(res)
        var imgurl = res.data.img
        var txSrc = res.data.headimgurl
        var pro_img = res.data.pro_img
        _this.setData({
          'cardInfo.qrCode': imgurl ? imgurl : '',
          'cardInfo.txSrc': txSrc ? txSrc : '',
          'cardInfo.avater': pro_img || '',
        })
        _this.getAvaterInfo();
      }
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },


})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在微信小程序中,canvas 画布的尺寸不应该超过 2048*2048,因为这是微信小程序的限制。但是,如果你想要绘制更大尺寸的画布,可以使用分割绘制的方法,即将大的画布分成多个小的画布,分别绘制,最后将它们拼接起来。 具体实现步骤如下: 1. 将大画布分割成若干个小画布,每个小画布的尺寸都不超过 2048*2048。 2. 分别创建 canvas 组件,设置它们的宽度和高度,分别绘制小画布。 3. 将小画布拼接起来,可以使用 wx.canvasToTempFilePath() 方法,将 canvas 画布转换成图片,然后使用 wx.getImageInfo() 方法获取图片信息,最后使用 wx.createCanvasContext() 方法将图片绘制到一个新的 canvas 画布上。 下面是一个示例代码: ```html <!-- 在 wxml 文件中定义多个 canvas 组件 --> <canvas canvas-id="canvas1" style="width: 2048rpx; height: 2048rpx;"></canvas> <canvas canvas-id="canvas2" style="width: 2048rpx; height: 2048rpx;"></canvas> <canvas canvas-id="canvas3" style="width: 2048rpx; height: 2048rpx;"></canvas> <!-- ... --> // 在 js 文件中绘制小画布 const ctx1 = wx.createCanvasContext('canvas1') ctx1.fillRect(0, 0, 2048, 2048) // ... // 在 js 文件中拼接小画布 wx.canvasToTempFilePath({ canvasId: 'canvas1', success: function(res1) { wx.getImageInfo({ src: res1.tempFilePath, success: function(info1) { wx.canvasToTempFilePath({ canvasId: 'canvas2', success: function(res2) { wx.getImageInfo({ src: res2.tempFilePath, success: function(info2) { const canvas = wx.createCanvasContext('canvas') canvas.drawImage(info1.path, 0, 0, 2048, 2048) canvas.drawImage(info2.path, 2048, 0, 2048, 2048) canvas.draw() } }) } }) } }) } }) ``` 注意:分割绘制的方法可以绘制大尺寸的画布,但是实际效果可能会受到硬件性能的影响,如果画布过大,可能会导致绘制缓慢或者卡顿。因此,在实际开发中,需要根据具体情况来决定是否采用这种方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值