公司業務須要實現電子簽名功能,當前我使用的是wepy框架。html
htmlredux
<template> <view class="wrap"> <view class="content-wrap" id="content"> <canvas class='myCanvas' canvas-id="myCanvas" @touchmove='move' @touchstart='start' @touchend='end' @touchcancel='cancel' @longtap='tap' disable-scroll='true' @error='error'></canvas> </view> <view class="bottom-wrap"> <view class="delete-btn" @tap="clearClick">清除</view> <view class="paint-brush"> <view class="thickness"> <repeat for="{{thicknessArr}}" index="index" item="item"> <text class="{{item}} {{activeIndex == index ? 'active':''}}" @tap="thicknessChange({{item}}, {{index}})"></text> </repeat> </view> <view class="paint-color"> <repeat for="{{paintColorArr}}" index="index" item="item"> <text class="{{item.className}}" @tap="selectColor({{item.color}})"></text> </repeat> </view> <view class="done" @tap="saveClick">完成</view> </view> </view> </view> </template>
lesscanvas
page { width: 100%; height: 100%; background: #fff; } .wrap { width: 100%; height: 100%; border-top: 1px solid #d5d5d5; box-sizing: border-box; } .content-wrap { width: 100%; height: calc(100% - 84rpx); .myCanvas { width: 100%; height: 100%; } } .bottom-wrap { width: 100%; height: 80rpx; overflow: hidden; color: #333; border-top: 1px solid #0068b1; .delete-btn { float: left; height: 80rpx; line-height: 80rpx; padding: 0 15rpx; font-size: 28rpx; } .paint-brush { float: right; height: 80rpx; line-height: 80rpx; overflow: hidden; .thickness { float: left; height: 80rpx; line-height: 80rpx; margin-right: 25rpx; text { display: inline-block; border: 1px solid #333; border-radius: 50%; margin: 0 15rpx; vertical-align: middle; } .small { width: 14rpx; height: 14rpx; } .medium { width: 22rpx; height: 22rpx; } .large { width: 30rpx; height: 30rpx; } .active { background: blue; } } .paint-color { float: left; text { display: inline-block; width: 54rpx; height: 54rpx; border-radius: 12rpx; margin: 12rpx 15rpx; } .red { background: red; } .blue { background: blue; } .black { background: #333; } } .done { float: left; height: 80rpx; line-height: 80rpx; padding: 0 15rpx; font-size: 28rpx; } } }
ts數組
import wepy from 'wepy'; import { connect } from 'wepy-redux'; import { uploadSignature } from '@/store/actions/index'; @connect({ userMeta: (state) => state.globle.userMeta, // 用戶數據 signInfo: (state) => state.seals.signInfo, // 上傳返回的簽章信息 }, { uploadSignature, // 上傳簽章 }) export default class ElectronicSignature extends wepy.page { config = { navigationBarTitleText: '手寫簽名', pageOrientation: 'landscape', // 手機橫屏展現 }; data = { thicknessArr: ['small', 'medium', 'large'], // 畫筆粗細 activeIndex: 0, // 畫筆當前粗細的key paintColorArr: [ // 畫筆顏色數組 { className: 'red', color: '#ff0000' }, { className: 'blue', color: '#0c00ff' }, { className: 'black', color: '#000000' }, ], signImage: '', // 生成的圖片地址 canvasContent: null, // 畫布 canvasw: 0, // 畫布的寬 canvash: 0, // 畫布的高 touchs: [], // 全部座標位置 }; methods = { uploadSignature, // 畫布觸摸開始觸發 start: (event) => { // 獲取觸摸開始的 x,y this.touchs.push({ x: event.changedTouches[0].x, y: event.changedTouches[0].y, }); }, // 畫布的觸摸移動手勢響應 move: (event) => { this.touchs.push({ x: event.touches[0].x, y: event.touches[0].y, }); if (this.touchs.length >= 2) { this.methods.draw(this.touchs); } }, draw: (touchs) => { const point1 = touchs[0]; const point2 = touchs[1]; touchs.shift(); this.canvasContent.moveTo(point1.x, point1.y); this.canvasContent.lineTo(point2.x, point2.y); this.canvasContent.stroke(); this.canvasContent.draw(true); }, // 選擇筆的粗細 thicknessChange: (type, index) => { this.activeIndex = index; this.methods.clearClick(); // 清除畫布 switch (type) { case 'small': this.canvasContent.setLineWidth(2); break; case 'medium': this.canvasContent.setLineWidth(4); break; case 'large': this.canvasContent.setLineWidth(6); break; } }, // 選擇畫筆顏色 selectColor: (color) => { this.methods.clearClick(); // 清除畫布 this.canvasContent.setStrokeStyle(color); }, clearClick: () => { // 清除畫布 this.canvasContent.clearRect(0, 0, this.canvasw, this.canvash); this.canvasContent.draw(true); }, async saveClick() { wepy.showLoading({title: '上傳中...'}); // 把當前畫布指定區域的內容導出生成指定大小的圖片 const imgResult = await wepy.canvasToTempFilePath({ canvasId: 'myCanvas' }); const imgPath = imgResult.tempFilePath; // 獲取生成的圖片大小 const fileInfo = await wepy.getFileInfo({ filePath: imgPath }); const imgSize = fileInfo.size; // 上傳 this.methods.uploadSignature({ path: imgPath, keyName: 'signature_file', params: { fileLength: imgSize, userId: this.userMeta.uuid }, }); }, backPrevPage: () => { wepy.navigateBack({ delta: 1, }); }, // 畫布的觸摸取消響應 cancel: (event) => { // console.log('觸摸取消' + event); }, // 畫布的長按手勢響應 tap: (event) => { // console.log('長按手勢' + event); }, error: (event) => { // console.log('畫布觸摸錯誤' + event); }, // 畫布的觸摸移動結束手勢響應 end: (event) => { // 清空軌跡數組 for (const item of this.touchs) { this.touchs.pop(); } }, }; onLoad() { // 得到Canvas的上下文 this.canvasContent = wepy.createCanvasContext('myCanvas'); // console.log(this.canvasContent); // 設置線的顏色 this.canvasContent.setStrokeStyle('#000000'); // 設置線的寬度 this.canvasContent.setLineWidth(2); // 設置線兩端端點樣式更加圓潤 this.canvasContent.setLineCap('round'); // 設置兩條線鏈接處更加圓潤 this.canvasContent.setLineJoin('round'); // 獲取畫布寬高 const self = this; const query = wx.createSelectorQuery(); query.select('#content').boundingClientRect(res => { self.canvasw = res.width; self.canvash = res.height; }).exec(); } watch = { signInfo(val) { val && wepy.showToast({title: '保存簽名成功!', icon: 'success'}); }, }; }