公司业务须要实现电子签名功能,当前我使用的是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'}); }, }; }