canvas绘制微信海报分享

举报
搞前端的半夏 发表于 2021/10/24 20:48:46 2021/10/24
【摘要】 前言最近公司在做一个面向餐饮的微信小程序,公司希望在小程序中嵌入关注公众号的功能,一开始是采用官方提供的official-account,配置公众号关注组件,方便用户快捷关注公众号,但是这个组件的场景限制比较多,需要扫码打开小程序才开始显示。在折腾了一番之后,最终决定提供二维码,供用户下载,扫码关注。这里我们有两种方案,第一种是让后台生成然后返回图片链接,只需要传后台所需要的参数就行了,第...

前言

最近公司在做一个面向餐饮的微信小程序,公司希望在小程序中嵌入关注公众号的功能,一开始是采用官方提供的official-account,配置公众号关注组件,方便用户快捷关注公众号,但是这个组件的场景限制比较多,需要扫码打开小程序才开始显示。

在折腾了一番之后,最终决定提供二维码,供用户下载,扫码关注。这里我们有两种方案,第一种是让后台生成然后返回图片链接,只需要传后台所需要的参数就行了,第二种方法,用canvas生成分享海报。最后我们选择了使用canvas制作分享海报的方式。

「注意:因为小程序基础版本比较老,导致本文使用的微信canvas版本比较老,学习思想即可!!!」

效果

主要步骤

1. 新建微信小程序,并添加图片

这一步真的太简单了,就不阐述了,直接展示项目结构。这里新建了一个resources文件,用来存放图片文件

2. 新建canvas容器

受各种环境的影响,图片加载的很慢,为了用户体验,不能一直白屏,我们加上一个正在加载的效果。当图片没有加载出来的时候,显示正在加载效果。

2.1 在pages\index\index.wxml中,先清空默认生成的代码,然后加入下面的代码。

<view class="generate-qorcode-container">
  <view class="generate-qorcode-loading" wx:if="{{loading}}">
    <view class="loading-text">加载中...</view>
  </view>
  <block hidden="{{!loading}}">
    <canvas class="canvas" style="{{'width: ' + (canvasW) + 'px; height: ' + (canvasH) + 'px;'}}" canvas-id="qrcodeCanvas" 
      hidden="{{canvasHidden}}"></canvas>
    <view class="generate-qorcode-save">
      <view class="save-btn-box">
        <view class="save-btn" bindtap="save">保存图片</view>
      </view>
    </view>
  </block>
</view>

使用loading变量来控制是否是正在加载。

2.2 在pages\index\index.wxss中

.generate-qorcode-container {
  width: 100%;
  position: relative;
}
.generate-qorcode-container .generate-qorcode-loading {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1001;
  background-color: rgba(255, 255, 255, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}
.generate-qorcode-container .canvas {
  margin: 0 auto;
}
.generate-qorcode-container generate-qorcode-save {
  padding-top: 24rpx;
  padding-bottom: 30rpx;
  background-color: #fff;
}
.generate-qorcode-container .save-text {
  width: 100%;
  margin-bottom: 21rpx;
  font-size: 26rpx;
  line-height: 1.5;
  color: #999;
  text-align: center;
}
.generate-qorcode-container .save-btn-box {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.generate-qorcode-container .save-btn-box .save-btn {
  width: 300rpx;
  height: 60rpx;
  line-height: 60rpx;
  font-size: 25rpx;
  border-radius: 8rpx;
  text-align: center;
  color: #fff;
  background: -webkit-linear-gradient(left, #4a9eff, #24c1ff);
}

这里我们为了让加载可以居中,使用了position:relative属性,并且top/bottom/left/right均为0 ,这样可以在父元素未定宽高的情况下居中,并且使用了z-index,将整个loading,置于画面之上。

2.4 最终效果

3 核心代码

3.1 定义所需数据

「背景图片」 「logo」 「二维码」 「设备的图片像素比」 「是否加载中」 「canvs的宽」 「canvas的高」

  data: {
    bgImg: '/resources/images/bg.png',
    logoImg :'/resources/images/juejin.png', 
    QRCodeImg :'/resources/images/qrcode.png',
    pixelRatio: 2,
    loading: false,
    canvasW:0,
    canvasH:0
  },

3.2 初始化数据

通过微信官方提供的getSystemInfo方法,获取手机的图片像素比,屏幕的宽高,图片像素比在进行海报下载的时候会用到,主要是用来优化图片的像素,显示的更加清晰。

   // 在组件完全初始化完毕
  attached() {
    let that = this
    // 进入页面,出现开始加载的画面
    that.setData({
      loading: true,
    })
    // 获取设备宽度,计算canvas宽高
    wx.getSystemInfo({
      success: function (res) {
        // 这里没有设置canvas的宽高为100%
        that.setData({
          pixelRatio: res.pixelRatio, // 图片像素比
          canvasW:res.screenWidth * 0.8,
          canvasH:res.screenWidth * 0.8 *1.3
        })
      }
    })
  },

3.3 开始绘制

获取canvas对象
 let that = this
 const ctx = wx.createCanvasContext('qrcodeCanvas', that)
绘制背景图片
  ctx.drawImage(that.data.bgImg, 0, 0, that.data.canvasW, that.data.canvasH)

效果

绘制二维码下面的白底

首先找出各个顶点的位置, 为了好看,使用arcTo函数加上一点圆角。半径为5。

  // 设定起始位置,宽高
      let rect = {
        x:  ( that.data.canvasW-(that.data.canvasW*0.7))/2,
        y:100,
        width: that.data.canvasW*0.7,
        height: that.data.canvasW*0.7 *1.2
      }

      // 计算各个位置的坐标
      let ptA = that.point(rect.x + 5, rect.y)
      let ptB = that.point(rect.x + rect.width, rect.y)
      let ptC = that.point(rect.x + rect.width, rect.y + rect.height)
      let ptD = that.point(rect.x, rect.y + rect.height)
      let ptE = that.point(rect.x, rect.y)

      // 按照坐标开始绘制
      ctx.beginPath()
      ctx.moveTo(ptA.x, ptA.y)
      ctx.arcTo(ptB.x, ptB.y, ptC.x, ptC.y, 5)
      ctx.arcTo(ptC.x, ptC.y, ptD.x, ptD.y, 5)
      ctx.arcTo(ptD.x, ptD.y, ptE.x, ptE.y, 5)
      ctx.arcTo(ptE.x, ptE.y, ptA.x, ptA.y, )
      // 填充颜色,保存画笔位置
      ctx.strokeStyle = "#fff"
      ctx.stroke()
      ctx.setFillStyle('#fff')
      ctx.fill()
      ctx.save()
      
  //辅助函数
  point(x, y) {
      return {
        x,
        y
      }
    },

效果

绘制logo框

这里主要是用到了两个圆,一个大一个小,半径相差1,这样头像就有了边框。

绘制大圆

ctx.beginPath()   
ctx.arc(that.data.canvasW/2, 100,35, 0, Math.PI * 2, false)
ctx.setFillStyle('#eee')
ctx.fill()
ctx.save()

绘制小圆 这里绘制小圆之后, 使用clip方法 ,使得之后的绘图都会被限制在被剪切的区域内。

 // 画小圆
  ctx.beginPath()
  ctx.arc(that.data.canvasW/2, 100,34, 0, Math.PI * 2, false)
  ctx.setFillStyle('#fff')
  ctx.fill()
  ctx.clip()

绘制logo图片

ctx.drawImage(
  that.data.logoImg,
  that.data.canvasW / 2 - 34,
  66,
  68,
  68
)
// 恢复画布
ctx.restore()

效果

绘制二维码

 // 绘制二维码
ctx.drawImage(that.data.QRCodeImg,( that.data.canvasW -140 )/2,150, 140, 140)

// 说明文字
ctx.setTextAlign('center')
ctx.setFontSize(14)
ctx.setFillStyle('#666')
console.log(( that.data.canvasW -140 )/2)
ctx.fillText('长按小程序码,查看详情', that.data.canvasW-150 , 320)

效果

关闭加载动画

ctx.draw(true, () => {
    that.setData({
      loading: false
    })
  })

总结

至此使用canvas绘制海报的流程已经结束了,总体看来还是比较简单的,难一点的地方就是具体坐标的计算,建议大家在草稿纸上画个草图,方便计算坐标。

下面就开始实现用户下载的功能。

4. 两步走下载图片

4.1 canvasToTempFilePath

    // 保存图片
    save() {
      let that = this
      wx.canvasToTempFilePath({
        x: 0, // 起点横坐标
        y: 0, // 起点纵坐标
        width: that.data.canvasW, 
        height: that.data.canvasH, 
        destWidth: that.data.canvasW * that.data.pixelRatio, 
        destHeight: that.data.canvasH * that.data.pixelRatio, 
        canvasId: 'qrcodeCanvas',
        success: function (res) {
          //调取小程序当中获取图片
          wx.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success(res) {
              wx.showToast({
                title: '图片保存成功!',
                icon: 'none'
              })
            },
            fail: function (res) {
              console.log(res)
              if (res.errMsg === "saveImageToPhotosAlbum:fail auth deny" || res.errMsg === "saveImageToPhotosAlbum:fail:auth denied") {
                that.doAuth()
              }
            }
          })
        },
        fail: function (res) {
          console.log(res)
        }
      }, this)
    },

4.2 获取保存图片的权限

step1: 弹出授权对话框

step2: 打开seetting页面

step3: 判断

  // 获取授权
    doAuth() {
      wx.showModal({
        title: '获取授权',
        content: '同意重新授权保存图片?',
        cancelText: '不同意',
        confirmText: '同意',
        confirmColor: '#21c0ae',
        success: function (res) {
          if (res.confirm) {
            wx.openSetting({
              success(settingdata) {
                if (settingdata.authSetting["scope.writePhotosAlbum"]) {
                  console.log("获取权限成功")
                } else {
                  console.log("获取权限失败")
                }
              },
              fail: function (res) {
                console.log(res)
              }
            })
          }
        }
      })
    },
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。