微信小程序新版canvas2d实现电子签名

384 阅读2分钟

效果

image.png

简单说明: 由于 canvas2D 的实例需要获取到 canvas 的容器元素,因此我们最早只能在页面 onReady 中调用初始化函数,如果在 onLoad 或者 onShow 中调用该函数,则无法获取到 canvas 容器元素

触摸开始的时候和旧版的canvas 接口是一样的,需要 moveTo 到起始点

在 canvas2D 绘制的时候和旧版的 canvas 不同:canvas2D 只需要 lineTo() > stroke() > moveTo() 即可,不需要显式的调用 draw() 方法,要比旧版的 canvas 更为细腻

完整代码如下: wxml

<canvas id="myCanvas" type="2d" class="canvas" style="width:{{width+'px'}};height:{{height+'px'}}" catchtouchstart="catchtouchstart" catchtouchmove="catchtouchmove" catchtouchend="catchtouchend"></canvas>
<view class="btn-reset" catchtap="clearCanvas">重新签名</view>
<view class="btn-ok" catchtap="canvasToImg">确认</view>

wxss

page{
  position: relative;
  background-color: #f2f2f2;
  width: 100%;
  height: 100%;
}
canvas{
  width: 100%;
  height: 100vh;
}
.myCanvas{
  background-color: red;
}
.btn-reset{
  width: 130rpx;
  position: absolute;
  bottom: 30rpx;
  right: 180rpx;
  padding: 8rpx;
  text-align: center;
  border: 1rpx solid #4965B3;
  color: #4965B3;
  font-size: 12px;
  border-radius: 24rpx;
  box-sizing: border-box;
}
.btn-ok{
  width: 130rpx;
  position: absolute;
  bottom: 30rpx;
  right: 30rpx;
  padding: 8rpx;
  text-align: center;
  background-color: #4965B3;
  border: 1rpx solid #4965B3;
  color: #fff;
  font-size: 12px;
  border-radius: 24rpx;
  box-sizing: border-box;
}

js

Component({
  data: {
    canvas:null,
    ctx: null,
    width: 385,
    height: 650,
    drawCount: 0,
    drawState: "init",
    points:[]
  },
  methods:{
    initCanvas() {
      wx.nextTick(()=>{
        const query = wx.createSelectorQuery().in(this)
        query.select('#myCanvas')
        .fields({ node: true, size: true })
        .exec((res) => {
            // Canvas 对象
            const canvas = res[0].node
            // Canvas 画布的实际绘制宽高
            const renderWidth = res[0].width
            const renderHeight = res[0].height
            // Canvas 绘制上下文
            const ctx = canvas.getContext('2d')
            this.data.ctx = ctx
            this.data.canvas = canvas

            // 初始化画布大小
            const dpr = wx.getWindowInfo().pixelRatio
            canvas.width = renderWidth * dpr
            canvas.height = renderHeight * dpr
            ctx.scale(dpr, dpr)
            this.clearCanvas()
        })
      })
    },
    clearCanvas() {
      const { ctx,canvas } = this.data
      this.data.drawCount = 0
      this.data.drawState = "ing"
      ctx.textBaseline = 'top'
      ctx.textAlign = 'center'
      ctx.fontSize = '20'
      ctx.font = '24px red'
      ctx.fillStyle = '#fff'
      ctx.fillRect(0, 0, canvas.width, canvas.height)
      ctx.fillStyle = '#616165'
      ctx.fillText("请在区域内完成签名", this.data.width / 2, this.data.height/2 - 40)
    },
    catchtouchstart(e) {
      const { canvas } = this.data
      if (this.data.drawCount == 0) {
        this.data.ctx.beginPath()
        this.data.ctx.clearRect(0,0,canvas.width,canvas.height)
      }
      this.data.drawCount++
      this.data.ctx.moveTo(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
    },
    catchtouchmove(e) {
      const { ctx } = this.data
      if (this.data.drawState == "stop") return
      this.data.drawState = "ing"
      if (e.touches.length > 1) {
        return
      }
      ctx.strokeStyle = '#000000';
      ctx.LineWidth = 4;
      ctx.shadowOffsetX = 0;
      ctx.shadowOffsetY = 0;
      ctx.shadowColor = '#000000';
      ctx.shadowBlur = 1;
      ctx.lineCap = 'round';
      ctx.lineJoin = 'round';
      ctx.lineTo(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
      ctx.stroke()
      ctx.moveTo(e.changedTouches[0].clientX, e.changedTouches[0].clientY)
    },
    catchtouchend(e) {
      this.data.points = []
    },
    canvasToImg() {
      const { canvas } = this.data
      if (this.data.drawState == "init") return
      this.data.drawState = "stop"
      wx.canvasToTempFilePath({
        canvas: canvas,
        success: (res) => {
          console.log(res.tempFilePath)
        },
        fail(rej){
          console.log(rej)
        }
      })
    }
  },
  pageLifetimes:{
    show: function () {
      this.initCanvas()
    },
  }
})