微信小程序画布canvas(新版)实现签名功能

wxml文件:

 
   <canvas class="canvas" id="signature-board" disable-scroll="true" bindtouchstart="canvasStart"
     bindtouchmove="canvasMove" bindtouchend="canvasEnd" touchcancel="canvasEnd" type="2d">
   canvas>

新版使用id获取canvas组件即可,旧版需要使用canvas-id。

wxss文件:

/* pages/signature/signature.wxss */
.container {
  padding: 20rpx;
  height: 100vh;
  width: 100vw;
  overflow: hidden; 
  display: flex;
  align-items:  center;
  /* background: radial-gradient(#fff, #000); */
  background-repeat: no-repeat;
  background-size: cover;
}
.block {
  height: calc(calc(100vw - 60rpx - 40rpx) / 2);
  /* max-height: 100%; */
  width: 100%;
  border-radius: 5rpx;
  overflow: hidden;
  display: flex;
  align-items:  center;
  background: rgba(255,255,255,.5);
  box-shadow: 0 0 30rpx 0 rgba(0,0,0,.3);
}
.drawarea {
  flex-grow: 2;
  height: 100%;
  width: 100%;
  position: relative;
}
.sign-hint {
  position: absolute;
  top: 0;
  left: 10rpx;
  right: 0;
  bottom: 0;
  z-index: 0;
  margin: auto;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  font-size: 40rpx;
  letter-spacing: .2em;
  color: rgba(0,0,0,.2);
  word-break: keep-all;
  white-space: pre-line;
}
.canvas {
  flex-grow: 2;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
} 
.button-box {
  flex-grow: 0;
  flex-shrink: 0;
  height: 100%;
  width: 40rpx;
  padding: 30rpx 10rpx 30rpx 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.cu-btn {
  width: 100%!important;
  height: 50%!important;
  padding: 0 2.5rpx 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 15rpx;
}
.cu-btn:first-of-type {
  margin: 0 0 30rpx 0;
}
.btn-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  writing-mode: vertical-rl;
  color: #fff;
  font-size: 14px;
}

json文件:

{
    "usingComponents": {},
    "pageOrientation": "landscape"
}

js文件:

const MAX_V = 1; // 最大书写速度
const MIN_V = 0; // 最小书写速度
const MAX_LINE_WIDTH = 16; // 最大笔画宽度
const MIN_LINE_WIDTH = 4; // 最小笔画宽度
const MAX_LINE_DIFF = .03; // 两点之间笔画宽度最大差异
let context = null; // canvas上下文
let lastPoint = null; // 包含上一点笔画信息的对象
Page({
  data: {
    drawn: false,
  },
  onShow: function (options) {
    this.canvasInit();
  },
  canvasInit: function () {
    wx.createSelectorQuery() 
    .select('#signature-board') // 在 WXML 中填入的 id
    .fields({ node: true, size: true })
    .exec((res) => {
      res[0].node.width = res[0].width;
      res[0].node.height = res[0].height;
        context = res[0].node.getContext("2d")
    })

  },
  canvasMove: function (e) {
    this.setData({
      drawn: true
    })
    let currPoint = {
      x: e.changedTouches[0].x, // X坐标
      y: e.changedTouches[0].y, // Y坐标
      t: new Date().getTime(), // 当前时间
      w: (MAX_LINE_WIDTH + MIN_LINE_WIDTH) / 2 /*默认宽度 */
    };
    if (lastPoint) {
      currPoint.w = this.calcLineWidth(currPoint); // 重新赋值宽度,覆盖默认值 
      context.beginPath();
      context.strokeStyle = '#000';
      context.lineCap = 'round';
      context.lineJoin = 'round';
      context.lineWidth = currPoint.w;
      context.moveTo(lastPoint.x, lastPoint.y);
      context.lineTo(currPoint.x, currPoint.y);
      context.stroke();
    }
    lastPoint = currPoint; // 结束前保存当前点为上一点
  },
  // 计算当前点的宽度,书写速度越快,笔画宽度越小,呈现出笔锋的感觉(笑)
  calcLineWidth: function (currPoint) {
    let consuming = currPoint.t - lastPoint.t; // 两点之间耗时
    if (!consuming) return lastPoint.w; // 如果当前点用时为0,返回上点的宽度。
    let maxWidth = Math.min(MAX_LINE_WIDTH, lastPoint.w * (1 + MAX_LINE_DIFF)); // 当前点的最大宽度
    let minWidth = Math.max(MIN_LINE_WIDTH, lastPoint.w * (1 - MAX_LINE_DIFF * 3)); // 当前点的最小宽度,变细时速度快所以宽度变化要稍快
    let distance = Math.sqrt(Math.pow(currPoint.x - lastPoint.x, 2) + Math.pow(currPoint.y - lastPoint.y, 2)); // 两点之间距离
    let speed = Math.max(Math.min(distance / consuming, MAX_V), MIN_V); /*当前点速度*/
    let lineWidth = Math.max(Math.min(MAX_LINE_WIDTH * (1 - speed / MAX_V), maxWidth), minWidth); /* 当前点宽度 */
    return lineWidth;
  },
  canvasEnd: function (e) {
    lastPoint = null; // 每笔画完清除缓存
  },
  canvasClear: function () {
    this.setData({
      drawn: false
    })
    context.clearRect(0, 0, context.canvas.width, context.canvas.height);
    // context.draw(false);
  },
  canvasOut: function () {
    wx.navigateBack({
      delta: 1,
    })
  },
  finish: function () {
    if (!this.data.drawn) {
      return;
    }
	//由于新版的canvas的wx.canvasToTempFilePath方法一直报错,只能通过以下方式来获取签名图片
    const res = context.canvas.toDataURL("image/png");
    const fsm = wx.getFileSystemManager();
    const FILE_BASE_NAME = "tmp_base64src_" + new Date().getTime();
    const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.png`;
    fsm.writeFile({
      filePath,
      data: res.replace(/^data:image\/\w+;base64,/, ""),
      encoding: "base64",
      success: () => {
          this.getOpenerEventChannel().emit('signature', filePath); //传签名图片的临时路径回上一页
          wx.navigateBack();
      },
      fail() {
        wx.showToast({ title: "生成签名失败", icon: "none" });
      },
    });
  },
})

签名效果:
微信小程序画布canvas(新版)实现签名功能_第1张图片

你可能感兴趣的:(小程序,微信小程序,小程序,前端)