[开发]小程序 canvas简单教程

根据开发过程中遇到的一些问题,整理总结出来的小程序的canvas的相关使用
适合新手,配合小程序开发文档食用更佳~

首先我们来看一下设计图(图比较大)
在这里插入图片描述
技术点:(我个人遇到的)
1、小程序相册授权功能(拒绝后重新调起授权)
2、绘制网络图片
3、文字换行(单行超出省略号)
4、canvas生成图片
5、canvas的大小随着手机屏幕自适应

下面我们开始小程序 canvas的使用教程(完全新手那种教程,我用的是低版本的canvas)
先看一下微信小程序的开发文档
https://developers.weixin.qq.com/miniprogram/dev/component/canvas.html

https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.createOffscreenCanvas.html

然后直接上代码!!!

wxml
tip:小程序请求授权时,如果点击拒绝,短时间内不能够再调起,找了很久,最后还是只能替换一下按钮,通过 button 里的openSetting 可以打开小程序的相册权限设置

文档里面原话是:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。

<view class='box'>
    <canvas canvas-id="myCanvas" style='position:relative;width: {{canvasWidth}}px;height:{{canvasHigth}}px;left:{{canvasLeft}}px;top:{{canvasTop}}px'></canvas>
  </view>

<view class='bottom'>
    <view class='btn_qrcode' wx:if='{{saveImgRight}}' bindtap="saveQrcode">仅保存二维码</view>
    <!-- 未授权 -->
    <button class='btn_qrcode' wx:if='{{!saveImgRight}}' open-type="openSetting">仅保存二维码</button>

    <view class='btn_card' wx:if='{{saveImgRight}}' bindtap="saveImg">保存名片到相册</view>
    <!-- 未授权 -->
    <button class='btn_card' wx:if='{{!saveImgRight}}' open-type="openSetting">保存名片到相册</button>

  </view>

定义一个canvas,取好id名(canvas-id:canvas 组件的唯一标识符),定义宽高(后期处理为自适应,注意这里使用的单位是 px)

js的展示部分 按照我的代码顺序介绍

data: {
    logo: 'https://xxxxxxxxx/logo_c.png',//logo的网络地址
    qcode: '',//二维码信息
    doctor: {},//医生信息
    shareImg: '',//名片图片路径
    shareQrcode: '',//二维码图片路径
    canvasWidth: '',//名片canvas宽度
    canvasHigth: '',
    canvasLeft: '',//名片canvas位置
    canvasTop:'',
    saveImgRight:true,//图片保存授权
  },

在onload的时候,处理好canvas画布的宽高
因为在绘制内容时所应用的单位是 px,但是小程序canvas的API并没有像其他的一样支持小程序独有的 rpx 自适应尺寸单位,而设计稿的尺寸目测常规的都是按照 iPhone6 屏幕尺寸(375*667)来制作的。
如果想要适应其他尺寸的屏幕时其实需按照iPhone6的绘制大小按比例进行换算即可:

onLoad: function (options) {
    let that = this;
    let rpx = 1;
    wx.getSystemInfo({
      success(res) {
        rpx = res.windowWidth / 375;
      },
    })
    that.setData({
      canvasWidth: 305 * rpx,
      canvasHigth: 500 * rpx,
      canvasLeft: 35 * rpx,
      canvasTop: 20 * rpx,
    })
    that.downLoadImg();
    that.getBasicInfo();
  },

在onshow的时候 我调用了 getAuthor() 这个方法,主要用于判断用户授权

onShow: function () {
    const that = this;
    that.getAuthor();
  },

获取相册授权

//获取相册授权
  getAuthor() {
    let that = this;
    wx.getSetting({
      success(res) {
        if (res.authSetting['scope.writePhotosAlbum'] == true) { 
          console.log("用户已授权")
          that.setData({
            saveImgRight: true
          })
        } else if (res.authSetting['scope.writePhotosAlbum'] == false) {
          console.log("用户点击拒绝授权")
          that.setData({
            saveImgRight: false
          })
        } else {
          console.log("用户未授权--没有点击同意,也没点击拒绝")
          that.setData({
            saveImgRight: true,
          })
        }
      }
    })
  },

下载网络图片

小程序 canvas 在绘制网络图片时,需要先下载到本地,再用本地生成的路径进行绘制
一定要在小程序中配置好网络图片的路径

// 下载logo图片
  downLoadImg: function () {
    let that = this;
    wx.getImageInfo({
      src: that.data.logo,//网络图片地址
      success: function (res) {
        wx.setStorageSync('logo_canvas', res.path);
      }
    });
  },

绘制圆角矩形

我遇到的第一个问题是:绘制带圆角的矩形,然后我找到了写的最简洁的一个方法(因为搜索时候 打开的页面太多了 已经忘记了原作者是谁。。 再找到会补充链接过来)

// 蓝色圆角矩形
  roundRectPath: function (rect, x, y, w, h, r) {
   //rect 是接下来绘图时传入的canvas id,  x,y:距离左上角的距离 
   //w,h:绘制图形的宽高, r: 圆角的半径
    rect.beginPath();
    rect.moveTo(x + r, y);
    rect.arcTo(x + w, y, x + w, y + h, r); // 右上
    rect.arcTo(x + w, y + h, x, y + h, r);
    rect.arcTo(x, y + h, x, y, r);
    rect.arcTo(x, y, x + w, y, r);// 左上
    rect.closePath();
    rect.fillStyle = "#4892FF"; //填充一个矩形
    rect.fill();
  },

然后白色的部分,我还是用的这个方法,绘制的下半部分有圆角,上半部分没有
调整一下 右上和左上部分,删除 r 即可

文字换行加省略号

文字换行,同样是抄的别的小朋友的方法(开发中日常感谢大家的无私奉献,找到链接再来贴)

// 文字换行
  dealWords: function (options) {
    options.ctx.setFontSize(options.fontSize);//设置字体大小
    var allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth);//实际总共能分多少行
    var count = allRow >= options.maxLine ? options.maxLine : allRow;//实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数

    var endPos = 0;//当前字符串的截断点
    for (var j = 0; j < count; j++) {
      var nowStr = options.word.slice(endPos);//当前剩余的字符串
      var rowWid = 0;//每一行当前宽度    
      if (options.ctx.measureText(nowStr).width > options.maxWidth) {//如果当前的字符串宽度大于最大宽度,然后开始截取
        for (var m = 0; m < nowStr.length; m++) {
          rowWid += options.ctx.measureText(nowStr[m]).width;//当前字符串总宽度
          if (rowWid > options.maxWidth) {
            if (j === options.maxLine - 1) { //如果是最后一行
              options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 18);    //(j+1)*18这是每一行的高度        
            } else {
              options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 18);
            }
            endPos += m;//下次截断点
            break;
          }
        }
      } else {//如果当前的字符串宽度小于最大宽度就直接输出
        options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 18);
      }
    }
  },

开始绘图

// canvas 画图--名片
  drawImg() {
    let that = this;
    wx.showLoading({
      title: '名片生成中',
    })
    let rpx = 1;
    wx.getSystemInfo({
      success(res) {
        rpx = res.windowWidth / 375;
      },
    })
    const ctx = wx.createCanvasContext('myCanvas');
    
    //此处我先填充了一个背景色为#f4f4f4的矩形,作为生成图片保存时候的背景色
    //不然白色的圆角看不出来,默认canvas的背景就是白色的
    
    ctx.fillStyle = '#f4f4f4';
    ctx.fillRect(0, 0, 305 * rpx, 500 * rpx);

    this.roundRectPath(ctx, 0, 0, 305 * rpx, 500 * rpx, 10 * rpx);
    this.whiteRect(ctx, 0, 195 * rpx, 305 * rpx, 305 * rpx, 10 * rpx);
    // 文字部分
    ctx.font = "normal 14px PingFangSC-Regular"	//设置字体
    ctx.fillStyle = '#BCD7FF';					//设置字体颜色
    ctx.fillText('xxxxxxxxxxx', 16 * rpx, 32 * rpx); 	//设置文字
    //  logo图片
    let headUrl = wx.getStorageSync('logo_canvas');
    if (headUrl){
      ctx.drawImage(headUrl, 252 * rpx, 18 * rpx, 35 * rpx, 35 * rpx)  //绘制网图
    }
    
    //  医生姓名 —— 这里有加省略号 下面有重复的 我就没有粘代码了
    ctx.fillStyle = '#ffffff';
    ctx.font = "normal bold 25px PingFangSC-Regular"
    that.dealWords({
      ctx: ctx,              	    //画布上下文 canvasID
      fontSize: '25',         	   //字体大小
      word: that.data.doctor.merchants,  				  //需要处理的文字
      maxWidth: 240 * rpx, 			 //一行文字最大宽度
      x: 16 * rpx,  					//文字在x轴要显示的位置
      y: 60 * rpx, 				 	   //文字在y轴要显示的位置
      maxLine: 1
    })
    //  二维码
    let qcode = wx.getStorageSync('qcode_canvas');
    if (qcode) {
      ctx.drawImage(qcode, 55 * rpx, 250 * rpx, 190 * rpx, 190 * rpx)
    }
    //  画图
    ctx.draw();//必须调用这个方法,才能绘图
    //  生成图片 —— 我这里是直接先生成好图片,防止保存时出现不必要的延时 可以自行调整
    that.completeImg();
    wx.hideLoading();
  },

生成图片( wx.canvasToTempFilePath )

 // 生成名片图片
  completeImg() {
    let that = this;
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      canvasId: 'myCanvas',
      fileType: 'jpg',
      success: function (res) {
        let shareImg = res.tempFilePath;
        that.setData({
          shareImg: shareImg
        });

      },
      fail: function (res) {
      }
    })
  },

保存图片(wx.saveImageToPhotosAlbum)

 // 保存名片图片到相册
  saveImg() {
    let that = this;
    wx.authorize({
      scope: 'scope.writePhotosAlbum',
      success() {
        if (that.data.shareImg) {
          wx.saveImageToPhotosAlbum({
            filePath: that.data.shareImg,
            success(res) {
              let isOK = res.errMsg.search('ok');
              if (isOK != -1) {
                wx.showLoading({
                  title: '保存成功',
                })
                setTimeout(wx.hideLoading, 1000)
              }
            }
          })
        } else {
          that.completeImg();
        }

      },
      fail(res) {
      //如果授权失败,判断一下返回语句中有没有 deny 更换一下显示按钮
        let isDeny = res.errMsg.search('deny');
        if (isDeny>0) {
          that.setData({
            saveImgRight: false
          })
        }
      }
    })
  },

因为我这里还需要单独保存二维码,所以我的页面上增加了一个canvas
想要隐藏canvas不可以直接在标签内直接 display:none,会影响canvas的绘制,我们需要给它加个外壳,对外部的view隐藏处理就可以了,但是如果这个canvas 展示在可视区内,在手机上看的时候,还是会展示出来,我这里就把这个需要隐藏的canvas,位置left:-9999px

最后写法是下面这样的

<view style='width:0px;height:0px;overflow:hidden;'>
      <canvas canvas-id="qrCanvas" style='width: 200px;height:200px;position:relative; top:-160px;left:-9999px;'></canvas>
    </view>

至此,我的首次canvas开发就结束啦~~ 希望对你有用!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值