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
- Canvas implements handwritten signature: signature does not necessarily have continuity; Judge whether to sign; The signature needs to be obvious
- Wechat applet API implementation save as a picture
- 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