小程序 | canvas篇

场景:画布在小程序的分享海报中是很常见的功能,如果遇到内容过多的时候可以使用第三方插件如html2canvas。本文记录下原生计算的方式:

1.wxml:

<view class='canvas-container' id='canvas-container'>
  <canvas canvas-id="myCanvas"/>
</view>

2.wxss:

.canvas-container {
  position: fixed;left: 0 ;right: 0;z-index: -99999999;
  width: 171px;height: 305px; 
  margin: 0 auto;
}
.canvas-container canvas {width:100%;height:100%;}

3.js:

①关于响应式问题:定义一个响应比例,后期通过设计稿量出来的尺寸要进行比例相乘达到适配不同尺寸手机效果。

wx.createSelectorQuery().select('#canvas-container').boundingClientRect(function (rect) {
    let rpx = 1; 
    wx.getSystemInfo({
       success(res) {
          rpx = res.windowWidth / 375;
       },
    })
}).exec()

②关于文字居中问题:使用API获取文字宽度来获取文字显示在x轴的距离

 let str = '我是一串文字';
 ctx.fillText(str, ((171 - ctx.measureText(str).width) / 2)*rpx, 20*rpx);

③关于头像裁剪成圆形问题:

ctx.arc(圆心的 x 坐标,圆心的 y坐标,圆的半径,起始弧度,终止弧度,弧度的方向是否是逆时针)

ctx.arc( ((171 - ctx.measureText(str).width) / 2 ) * rpx, 14 * rpx, 6 * rpx, 0, Math.PI * 2, false);
ctx.clip();
ctx.drawImage(headImg, ((171 - ctx.measureText(str).width) / 2 - 6)*rpx, 8*rpx, 12*rpx, 12*rpx)

④关于绘制网络图片问题:

资源为网络图片的话需要通过 downloadFile 先下载。

绘制图像到画布有三个版本的写法(具体详见文档):

CanvasContext.drawImage(string imageResource, number sx, number sy, number sWidth, number sHeight, number dx, number dy, number dWidth, number dHeight) | 微信开放文档

  • drawImage(imageResource, dx, dy)
  • drawImage(imageResource, dx, dy, dWidth, dHeight)
  • drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) 从 1.9.0 起支持

当有一张背景图需要绘制在画布的正中间时,可能遇到图片需要缩放问题:

思路:1.获取图片得宽高 2.获取画布的宽高 3.计算图片的缩放比例以及位置

wx.getImageInfo({
  src: cardbg,
  success (res) {
    let imgW = res.width;  //获取到图片宽度
    let imgH = res.height; //获取到图片高度
    let canvasWidth = rect.width; //画布宽(通过createSelectorQuery中获取到)
    let canvasHeight = rect.height; //画布高
    let x=0;
    let y=0;
    if(canvasWidth/imgW>canvasHeight/imgH){
      imgScale = canvasWidth/imgW
      y= -(imgScale*imgH-canvasHeight)/2
    }else{
      imgScale =canvasHeight/imgH
      x= -(imgScale*imgW-canvasWidth)/2
    }
    ctx.drawImage(cardbg,0,0, imgW,imgH,x, y,imgScale*imgW, imgScale*imgH); 
})

⑤多张网络图片下载处理方式:Promise.all([url1,url2,..]) 返回的结果与数组中的序列号是对应的,以此类推使用

Promise.all([
   that.downloadImage(url1),  //调用方法获取到返回路径
   that.downloadImage(url2),
]).then((result)=>{
   that.getCanvas(result[0], result[1])
})

downloadImage(url){ //下载网络图片方法
  return new Promise(function(resolve){
    wx.downloadFile({
      url,success:function(res){
      if (res.statusCode === 200) { resolve(res.tempFilePath) }
      },
    })
  })
},

展示效果图:

 

实现代码:

 onLoad() {
    let that = this;
    let { headImg, codeImg } = that.data;
    Promise.all([
      that.downloadImage(headImg),
      that.downloadImage(codeImg),
    ]).then((result) => {
      that.getCanvas(result[0], result[1])
    }).catch((err) => {
      console.log(err)
    })
  },

  downloadImage(url) {
    return new Promise(function (resolve) {
      wx.downloadFile({
        url,
        success: function (res) {
          if (res.statusCode === 200) {
            resolve(res.tempFilePath)
          }
        },
      })
    })
  },

  getCanvas(headImg, codeImg ) { //绘制画布
    let that = this;
    let { cardbg } = that.data;
    const ctx = wx.createCanvasContext('myCanvas'); //创建画布
    wx.createSelectorQuery().select('#canvas-container').boundingClientRect(function (rect) {
      let rpx = 1;
      wx.getSystemInfo({
        success(res) {
          rpx = res.windowWidth / 375;
          wx.getImageInfo({
            src: cardbg,
            success(res) {
              let imgScale = 1;
              let imgW = res.width; //图片宽度
              let imgH = res.height; //图片高度
              let canvasWidth = rect.width; //画布宽度
              let canvasHeight = rect.height * .777; //画布高度(是否有比例按照实际需求来)
              let x = 0;
              let y = 0;
              let imgScalew = canvasWidth / imgW;
              let imgScaleh = canvasHeight / imgH;
              if (imgScalew > imgScaleh) {
                imgScale = imgScalew
                y = -(imgScale * imgH - canvasHeight) / 2
              } else {
                imgScale = imgScaleh
                x = -(imgScale * imgW - canvasWidth) / 2
              }

      //背景图
      ctx.drawImage(cardbg, 0, 0, imgW, imgH, x, y, imgScale * imgW, imgScale * imgH);
      ctx.setFontSize(14 * rpx);
      ctx.setFillStyle('#3D3D3D');
      ctx.fillText("我是昵称", 50 * rpx, (474 / 2 + 34) * rpx);
      // 绘制头像
       ctx.save();
       ctx.beginPath();
       ctx.arc(24 * rpx, 271 * rpx, 24 * rpx, 0, Math.PI * 2, false);
       ctx.clip();
       ctx.drawImage(codeImg, 0, 247 * rpx, 48 * rpx, 48 * rpx)


            }
          })
        },
      })

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

  saveShareImg: function () {
     wx.showLoading({
       title: '海报生成中...',
       mask: true,
     })
    setTimeout(function () {
      wx.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: function (res) {
          wx.hideLoading();
          wx.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success(res) {
              wx.showModal({
                content: '图片保存到相册',
                showCancel: false,
                confirmText: '我知道了',
                success: function (res) {
                  if (res.confirm) {}
                },
                fail: function (res) {}
              })
            },
            fail: function (res) {
              console.log(res)
              if (res.errMsg === "saveImageToPhotosAlbum:fail:auth denied") {
                console.log("打开设置窗口");
                wx.openSetting({
                  success(settingdata) {
                    if (settingdata.authSetting["scope.writePhotosAlbum"]) {
                      console.log("获取权限成功,再次点击图片保存到相册")
                    } else {
                      console.log("获取权限失败")
                    }
                  }
                })
              }
            }
          })
        },
        fail: function (err) {
          console.log(err)
        }
      });
    }, 1000);
  },

常规画布需求实现完毕,后期有额外的需求再补充实现。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值