小程序手写板功能实现

完整的demo代码在 https://github.com/lzcdev/handwrite-wechat-miniprogram

首先放一张效果图:

需要的组件和 API

近期做小程序需要用到手写签名的功能,大概研究了一下相关的组件和 API。要实现这个功能用到的组件主要是 canvas,相关的 API 为 CanvasContext 等几个相关的 API。

根据 canvas 的文档,需要设置的属性主要是 stylecanvas-id bindtouchstartbindtouchmovebindtouchend这几个。完整的 wxml 的主要代码如下:

<view>
  <canvas style='width:{{canvasWidth}}px;height:{{canvasHeight}}px' class="canvas" canvas-id="canvas" disable-scroll="true" bindtouchstart="canvasStart" bindtouchmove="canvasMove" bindtouchend="canvasEnd" touchcancle="canvasEnd" binderror="canvasIdErrorCallback"></canvas>

  <view class='control_view'>
    <button type='primary' size='mini' bindtap="cleardraw">清除画布</button>
    <button type='primary' size='mini' bindtap='getImg'>导出图片</button>
  </view>


  <image class='img' style='width:{{canvasWidth}}px;height:{{canvasHeight}}px' src="{{imgUrl}}"></image>
</view>

之后主要是 js 的逻辑了。

首先初始化几个用到的变量

let context = null;
var isButtonDown = false;
var arrx = [];
var arry = [];
var arrz = [];
Page({
  /**
   * 页面的初始数据
   */
  data: {
    canvasWidth: 0,
    canvasHeight: 0,
    imgUrl: ''
  },
})  

onLoad方法中设置宽高并初始化 context 对象

  onLoad: function(options) {
    var that = this;
    wx.getSystemInfo({
      success(res) {
        that.setData({
          canvasWidth: res.windowWidth,
          canvasHeight: res.windowHeight / 2 - 100
        })
      }
    })

    // 使用 wx.createContext 获取绘图上下文 context
    context = wx.createCanvasContext('canvas');

  },

然后是 canvasStart ,在这个方法中把初始坐标添加进数组

  canvasStart: function(event) {
    // console.log(event)
    isButtonDown = true;
    arrz.push(0);
    arrx.push(event.changedTouches[0].x);
    arry.push(event.changedTouches[0].y);
  },

主要的画图方法在 canvasMove 这个方法里面。把移动时的 xy 坐标都添加进数组中。之后遍历数组,调用 moveTo 画起点,调用 lineTo 画轨迹。并且调用 context 相关的属性做一些基本设置

  canvasMove: function(event) {
    // console.log(event)
    if (isButtonDown) {
      arrz.push(1);
      arrx.push(event.changedTouches[0].x);
      arry.push(event.changedTouches[0].y);
    };

    for (let i = 0; i < arrx.length; i++) {
      if (arrz[i] == 0) {
        context.moveTo(arrx[i], arry[i])
      } else {
        context.lineTo(arrx[i], arry[i])
      }
    }

    context.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight);
    context.setStrokeStyle('#000000');
    context.setLineWidth(4);
    context.setLineCap('round');
    context.setLineJoin('round');
    context.stroke();
    context.draw(false);
  },

到这里基本的功能就完成了。之后再做清除画布和导出图片的功能

清除画布

  cleardraw: function(e) {
    arrx = [];
    arry = [];
    arrz = [];
    context.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight);
    context.draw(true);
  },

导出图片用到了 canvasToTempFilePath 这个 API

  getImg: function() {
    if (arrx.length == 0) {
      wx.showModal({
        title: '提示',
        content: '签名内容不能为空!',
        showCancel: false
      });
      return;
    }
    // 生成图片
    var that = this
    wx.canvasToTempFilePath({
      canvasId: 'canvas',
      success: function(res) {
        // console.log(res.tempFilePath)
        that.setData({
          imgUrl: res.tempFilePath
        })
      }
    }, this)
  },

可以看到通过 canvas 画布这个组件以及相关 API 实现这个功能还是比较简单的。后续可以根据具体的界面设计和功能改造成想要的效果。

comments powered by Disqus