canvas实现电子签名功能

387 阅读3分钟

前言

  • 之前做了一个需求,要实现【微信小程序】实现【电子签名】的效果,所以就直接开始埋头写,然后上线了。上线之后却是有问题,这边的话对开发过程中遇到的问题进行总结记录一下!

初始开发

  1. 刚开始的时候,遇到需要绘制电子签名的功能,咱就是直接一个百度,到处搜索别人是怎么做的,后面看大家大体上都是通过canvas进行绘制的。所以就直接通过canvas直接写起来了,写完之后功能实现没啥问题,测试却告诉我他测试过程中画着画着有闪退的问题。。。然而我这边没法复现出来,测试也是偶现的状态,一下子就不知道是什么问题,因为考虑到这个功能可能客户初始也没什么人用,就先上线一下吧~
  2. 【问题1】然而,一上线,就懵了,这个绘制的canvas弹窗直接就卡住,根本出不来,要等到5s左右之后才出现且所有页面直接卡死,然后就开始排查,发现这个const context = wx.createCanvasContext('myCanvas')api已经不用了,有点问题
  3. 【问题2】然后就还有另一个问题,就是提交的时候,进程阻塞,一直处于转圈的情况.排查之后是因为要把加密的图片流传给后端,要先下载图片。然后图片是http格式的,不是合法域名

问题解决方案

  1. 【问题1】:对于canvas绘制的效率问题,微信官方文档已经给出了方案使用<canvas type='2d'></canvas>的绘图方式,所以将绘图方式改动就可。
  2. 【问题2】:对于提交时转圈问题,解决方案就是让后端将图片路径改为https的,然后再在微信公众平台进行配置一下域名就可以了。
  3. 上线之后,finally, 问题修复了.

代码实现

这边贴一下主要的代码,如需要完整代码,可联系我~

// 有竖屏和横屏绘制,可切换
// 绘制时如背景页面是长页面可滑动的情况,滑动画布会移动, 可设置最外层容器catchtouchmove="true"
<canvas type='2d' id="canvas-vertical" disable-scroll="true" class="cavas" catchtouchstart="catchtouchstart" catchtouchmove="catchtouchmove" catchtouchend="catchtouchend"></canvas>
<canvas type='2d' id="canvas-level" class="cavas" catchtouchstart="catchtouchstart" catchtouchmove="catchtouchmove" catchtouchend="catchtouchend"></canvas>

初始化画布对象

initCanvas(canvasId = 'canvas-vertical') {
    this.canvasId = canvasId
    const nodeId = '#' + canvasId
    wepy.nextTick(() => { // 获取节点问题(需要延时获取)
      wx.createSelectorQuery()
        .select(nodeId) // 在 WXML 中填入的 id
        .fields({ node: true, size: true })
        .exec(res => {
          console.log(res, 'res------')
          // Canvas 对象
          const canvas = res[0].node
          this.canvas = canvas
          // Canvas 画布的实际绘制宽高
          const renderWidth = res[0].width
          const renderHeight = res[0].height
          // Canvas 绘制上下文
          const ctx = canvas.getContext('2d')
          this.ctx = ctx

          // 初始化画布大小
          const dpr = wx.getWindowInfo().pixelRatio
          canvas.width = renderWidth * dpr
          canvas.height = renderHeight * dpr
          this.width = canvas.width
          this.height = canvas.height
          ctx.scale(dpr, dpr)
          this.isDrawed = false
        })
    })
  }

绘制过程中记录绘制路径,进行绘制

catchtouchstart(e) {
      // 竖屏与横屏绘画位置计算
      if (this.canvasId === 'canvas-vertical') {
        this.ctx.moveTo(e.changedTouches[0].clientX - e.currentTarget.offsetLeft, e.changedTouches[0].clientY - e.currentTarget.offsetTop)
      } else {
        this.ctx.moveTo(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
      }
    },
    catchtouchmove(e) {
      // if (this.drawState == "stop") { return }
      // this.drawState = "ing"
      if (e.touches.length > 1) {
        return
      }
      this.ctx.strokeStyle = '#000000'
      this.ctx.lineWidth = 3
      this.ctx.lineCap = 'round'
      this.ctx.lineJoin = 'round'
      if (this.canvasId === 'canvas-vertical') {
        this.ctx.lineTo(e.changedTouches[0].clientX - e.currentTarget.offsetLeft, e.changedTouches[0].clientY - e.currentTarget.offsetTop)
      } else {
        this.ctx.lineTo(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
      }
      if (this.canvasId === 'canvas-vertical') {
        this.ctx.moveTo(e.changedTouches[0].clientX - e.currentTarget.offsetLeft, e.changedTouches[0].clientY - e.currentTarget.offsetTop)
      } else {
        this.ctx.moveTo(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
      }
      this.ctx.stroke()
    },

绘制结束,生成图片

canvasToImg() {
      const id = this.canvasId
      let picUrl
      // if (this.drawState == "init") { return }
      const that = this
      this.ctx.fillStyle = '#F7F7F7'
      if (this.isDrawed) {
        setTimeout(() => {
          wx.canvasToTempFilePath({
            fileType: 'png',
            canvas: this.canvas,
            success: res => {
              const obj = {}
              // 让后端进行图片的翻转,因为横屏时绘制的签名是横的
              if (that.canvasId === 'canvas-vertical') {
                obj.isFlip = 0
                obj.angle = 0
              } else {
                obj.isFlip = 1 // 是否翻转
                obj.angle = -90 // 翻转角度
              }
              uploadPicture(res.tempFilePath, 'relation', obj).then(res => {
                // that.drawState = "stop"
                that.isShow = false
                picUrl = res
                // that.clearRefer()
                that.$apply()
                that.$emit('ok', res)
              })
            }
          })
        })
      } else {
        this.$toast('请进行签名')
      }
    },

结语

大体的实现就是差不多如上所述。今天还是一个情人节哎,祝所有天下的有情人💕都能终成眷属,也祝所有的单身狗😼可以早日找到自己的意中人~ 完结撒花~