Wechat small program Canvas to achieve handwritten signature

Functional description

Click the button to display a pop-up window. The main body of the pop-up window is the signature board, and the bottom two buttons are clear and save. Clear button: clears the signature board. Save button: Saves the signature as a picture and closes the popup window

Critical point analysis

  1. Canvas implements handwritten signature: signature does not necessarily have continuity; Judge whether to sign; The signature needs to be obvious
  2. Wechat applet API implementation save as a picture
  3. Because the popup window shows the signature board, it is convenient to encapsulate it as a small program component later on

Function implementation

1. WXML signature component

<view class="signature-modal" hidden="{{hideModal}}"> <view class="modal-mask" bindtap="closeModal"></view> <view Class =" modal-Content-area "> <view class="modal-title"> Signature board </view> <view class=" modal-Content "> <canvas canvas-id="signature" class="modal-canvas" disable-scroll="{{true}}" id="handWriting" bindtouchstart="scaleStart" bindtouchmove="scaleMove" bindtouchend="scaleEnd" ></canvas> <view class="modal-bottom"> <view class="modal-btn Modal-clear "bindtap="clearCanvas"> Clear </view> <view class="modal-btn modal-confirm" bindtap="saveToImage"> Upload </view> </view> </view> </view> </view>Copy the code

2. Signature component style

.signature-modal {
 position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal-mask{
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 4;
  background-color: rgba(0, 0, 0, .5);
}
.modal-content-area{
  position: relative;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  width: 700rpx;
  min-height: 550rpx;
  background-color: #ffffff;
  border-radius: 18rpx;
}
.modal-content {
  width: 100%;
  height: 100%;
}
.modal-canvas {
  width: 650rpx;
  height: 420rpx;
  margin: 0 auto;
  margin-bottom: 30rpx;
  border-radius: 18rpx;
  box-sizing: border-box;
  overflow: hidden;
  background-color: rgba(0, 0, 0, .1);
}
.modal-bottom {
  display: flex;
  width: 100%;
  height: 70rpx;
  justify-content: space-between;
  align-items: center;
  background-color: #869ee9;
  color: #ffffff;
}
.modal-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 50%;
  height: 100%;
}
.modal-btn:nth-child(1) {
  border-right: 1rpx solid #ffffff;
}
Copy the code

3. Signature component JS file

/ / component/people/index. Js component ({/ * * * a list of attributes for the component * / properties: {}, * * * / components of the initial data * / data: { tempFilePath:'', hideModal: true, hasDraw: false, canvasName: '#handWriting', ctx: '', canvasWidth: 0, canvasHeight: 0, startPoint: {x: 0, y: 0,}, selectColor: 'black', lineColor: '#1A1A1A', // lineSize: 1, // Note multiple radius: 5, // Draw circle radius}, lifeTimes: {ready() {let that = this let query = wx.createsElectorQuery ().in(this); This.canvasctx = wx.createcanvasContext ('signature', . / / set the line style enclosing canvasCtx. SetLineCap (" round "); this.canvasCtx.setLineJoin("round"); / / initializes the color this. CanvasCtx. SetStrokeStyle (that) the data) selectColor); Query. Select ('.modal-canvas').boundingClientRect(rect => {this.setData({canvasWidth: rect.width, canvasHeight: rect.height, }); }).exec(); }}, /** * list of components */ methods: {show() {this.setdata ({hideModal: false }) }, closeModal() { this.clearCanvas() this.setData({ hideModal: true }) this.triggerEvent('closeSignature') }, scaleStart(event) { if (event.type ! = 'touchstart') return false; let currentPoint = { x: event.touches[0].x, y: event.touches[0].y } // this.data.ctx.moveTo(currentPoint.x, currentPoint.y) this.drawCircle(currentPoint); This.setdata ({startPoint: currentPoint, hasDraw: true, // signed}); }, mouseDown() {}, scaleEnd(e) { this.setData({ isStart: true }) }, scaleMove(event) { if (event.type ! = "touchmove") return false; let { startPoint } = this.data let currentPoint = { x: event.touches[0].x, y: event.touches[0].y } this.drawLine(startPoint, currentPoint) this.setData({ startPoint: DrawCircle (point) {this.canvasctx = this.canvasctx; ctx.beginPath(); // ctx.fillStyle = this.data.lineColor; Arc (point.x, point.y, this.data.radius, 0, 2 * math.pi); ctx.setFillstyle (this.data.linecolor); ctx.fill(); ctx.closePath(); ctx.draw(true) }, drawLine(sourcePoint, targetPoint) { let ctx = this.canvasCtx; this.drawCircle(targetPoint); ctx.beginPath(); // ctx.strokeStyle = this.data.lineColor; ctx.setStrokeStyle(this.data.lineColor) // ctx.lineWidth = this.data.radius * 2; Ctx.setlinewidth (this.data.radius*2) ctx.moveto (sourcePoint.x, sourcePoint.y); ctx.lineTo(targetPoint.x, targetPoint.y); ctx.stroke(); ctx.closePath(); // ctx.draw()}, clearCanvas() {// let CTX = this.canvasctx; ctx.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight); ctx.fillStyle = 'rgba(0, 0, 0, .1)'; ctx.draw() this.setData({ hasDraw: False / / not signature})}, getTempFile () {return {tempFilePath: this. Data. TempFilePath}}, saveToImage () {let {hasDraw, canvasHeight, canvasWidth } = this.data let that=this if (! HasDraw) {wx.showtoast ({title: 'not yet signed! ', icon: 'none', mask: true }) return } wx.canvasToTempFilePath({ x: 0, y: 0, width: canvasWidth, height: canvasHeight, canvasId: 'signature', success(res) { if(res.tempFilePath){ that.setData({ tempFilePath:res.tempFilePath }) that.triggerEvent('confirm') } console.log(res.tempFilePath) }, fail(err) { console.log(err); } },that) } } })Copy the code

Ps: Considering that it is an old project, the Canvas version selected here is the API of the old version, and it will be implemented with the new Canvas when it is free

Refer to the article