微信小程序canvas实现签名
话不多说,先看效果
图1.签名样式
图2.页面展示效果
下面是具体代码
canvas.wxml
<view class="signBox border">
<view class="flex-center">
<view>商户签字</view>
<van-image style="padding-left:30rpx" wx:if="{{sign}}" src="{{sign}}" width="100" height="50" fit="contain"/>
</view>
<van-button type="primary" size="small" color="#12b2a8" bind:click="toSign">{{form.sign == '' ? '点击签名' : '点击重签'}}
</van-button>
<!-- <button style="margin-top: 30rpx;" bindtap="submitSignature" disabled="{{!isSignatureFinish}}">提交保存</button> -->
</view>
<view class="bottom">
<van-button block round type="primary" color="#12b2a8" bind:click="makeEOrder">
完成</van-button>
</view>
<page-container show="{{showPage}}" overlay="{{false}}" round="{{false}}" close-on-slideDown="{{false}}" z-index="1000">
<view class="flex" style="height: 100vh;">
<view class="sign-btn-container">
<view class="cu-btn" bindtap="hideSignPage">取消/返回</view>
<view class="cu-btn {{isSignatureFinish?'bg-blue light':''}}" bindtap="clearCanvas">重新签名</view>
<view class="cu-btn {{isSignatureFinish?'bg-blue light':''}}" bindtap="confirmSign">完成签名</view>
</view>
<canvas id="canvas" style="position:{{showPage?'relative':'fixed'}};left:{{showPage?'':'100%'}};" canvas-id="canvas" class="canvas" :disable-scroll="true" bindtouchstart="handleTouchStart" bindtouchmove="handleTouchMove" bindtouchend="handleTouchEnd" bindtouchcancel="handleTouchCancel" disable-scroll="true" />
</view>
</page-container>
<canvas id="canvas-temp" style="width: {{canvasTempWidth}}px; height: {{canvasTempHeight}}px;" canvas-id="canvas-temp" class="canvas-temp"></canvas>
<van-dialog id="van-dialog" />
<van-notify id="van-notify" />
canvas.js
var util = require('../../utils/util.js');
import Notify from '@vant/weapp/notify/notify';
Page({
/**
* 页面的初始数据
*/
data: {
showPage:false,
isSignatureFinish: false,
moveLength: 0, //移动一定距离后才能提交保存
canvasTempWidth: wx.getSystemInfoSync().screenWidth,
canvasTempHeight: wx.getSystemInfoSync().screenWidth * 0.5,
},
//跳转签名页面
toSign() {
this.setData({
showPage: true
});
},
//生成电子巡检单
makeEOrder() {
if (this.data.sign == '') {
wx.showToast({
title: '请先完成商户签字',
icon: 'none'
})
} else {
}
},
// 签名部分
hideSignPage() {
this.setData({
showPage: false
});
},
confirmSign() {
let _this = this
_this.generateSignImage('canvas').then(res => {
console.log('图片地址:', res)
wx.getImageInfo({
src: res,
success(info) {
let width = info.width
let height = info.height
//先重置canvas-temp
_this.ctx2.draw(false, ()=>{
let dx = _this.data.canvasTempWidth
let dy = _this.data.canvasTempHeight
//把原点移动到中心点位置
_this.ctx2.translate(dx / 2, dy / 2)
_this.ctx2.rotate(270 * Math.PI / 180)
let dWidth = dx / height * width
let dHeight = dx
//drawImage参数说明
//imageResource
//imageResource的左上角在目标 canvas 上 x 轴的位置
//imageResource的左上角在目标 canvas 上 y 轴的位置
//在目标画布上绘制 imageResource 的宽度,允许对绘制的 imageResource 进行缩放
//在目标画布上绘制 imageResource 的高度,允许对绘制的 imageResource 进行缩放
_this.ctx2.drawImage(res, -dWidth / 2,-dHeight / 2, dWidth, dHeight)
//canvas-temp图片绘制完成后
_this.ctx2.draw(false, ()=>{
_this.generateSignImage('canvas-temp').then(res => {
console.log('图片地址:', res)
_this.setData({
sign:res
})
_this.hideSignPage()
})
})
})
}
})
})
},
// submitSignature(){
// console.log(this.data.sign)
// wx.showToast({
// icon:'none',
// title: '获取sign变量图片地址提交到自己的服务器',
// })
// },
initCanvas() {
/* 设置线条颜色 */
this.canvasContext.setStrokeStyle('#0081ff'); //2A2A2A
/* 设置线条粗细 */
this.canvasContext.setLineWidth(4);
/* 设置线条的结束端点样式 */
this.canvasContext.setLineCap('round');
},
/* 触摸开始 */
handleTouchStart(e) {
console.log(e)
this.drawStartX = e.changedTouches[0].x;
this.drawStartY = e.changedTouches[0].y;
console.log('触摸开始', this.drawStartX, this.drawStartY)
this.canvasContext.beginPath();
},
/* 触摸移动 */
handleTouchMove(e) {
/* 记录当前位置 */
const tempX = e.changedTouches[0].x;
const tempY = e.changedTouches[0].y;
// console.log('触摸移动', tempX, tempY)
this.data.moveLength += Math.abs(this.drawStartX - tempX) + Math.abs(this.drawStartY - tempY)
/* 画线 */
this.canvasContext.moveTo(this.drawStartX, this.drawStartY);
this.canvasContext.lineTo(tempX, tempY);
this.canvasContext.stroke();
/* 旧版draw方法,新版本不需要draw */
this.canvasContext.draw(true);
/* 重新记录起始位置 */
this.drawStartX = tempX;
this.drawStartY = tempY;
},
/* 触摸结束 */
handleTouchEnd(e) {
console.log('触摸结束')
this.canvasContext.save();
this.setData({
isSignatureFinish: this.data.moveLength > 100
})
},
/* 触摸取消 */
handleTouchCancel(e) {
console.log('触摸取消')
this.canvasContext.save();
},
/* 清空画布 */
clearCanvas() {
console.log('清空画布')
this.canvasContext.draw()
this.initCanvas()
this.data.moveLength = 0
this.setData({
isSignatureFinish: false
})
},
/* 生成签名图片 */
generateSignImage(canvasId) {
console.log('Canvas生成图片')
return new Promise((resolve, reject) => {
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: canvasId, // 旧版使用id
fileType: 'png',
quality: 1,
success: res => {
resolve(res.tempFilePath)
},
fail: err => {
reject(err);
}
})
})
},
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
//第一个canvas
this.canvasContext = wx.createCanvasContext('canvas');
this.initCanvas()
//第二个canvas
this.ctx2 = wx.createCanvasContext('canvas-temp');
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
// if (this.data.sign) {
// //商户签字上传服务器
// this.upLoadImg(this.data.sign, 'form.sign');
// }
}
})
canvas.wxss
.signBox {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 30rpx;
}
.bottom {
margin: 100rpx 20rpx;
padding-bottom: 20px;
}
.title {
padding: 20rpx 30rpx 0;
}
.border {
margin-top: 20rpx;
border-top: 1px solid #b3b3b3;
}
.flex-center {
display: flex;
align-items: center;
}
.canvas {
width: 90vw;
height: 100vh;
}
.canvas-temp {
position:fixed;left:100%;
}
/* 签名部分 */
.sign-btn-container {
display: flex;
flex-direction: column;
height: 100%;
width: 10vw;
justify-content: space-around;
}
.sign-btn-container view {
transform: rotate(90deg);
width: 100px;
margin-left: -8vw;
}
.cu-btn {
position: relative;
border: 0rpx;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 0 30rpx;
font-size: 28rpx;
height: 64rpx;
line-height: 1;
text-align: center;
text-decoration: none;
overflow: visible;
margin-left: initial;
transform: translate(0rpx, 0rpx);
margin-right: initial;
}
.bg-blue{
background-color: #0081ff;
color: #ffffff;
}
.light{
color:#0081ff;
background-color:#cce6ff;
}
canvas.json
{
"usingComponents": {
"van-radio": "@vant/weapp/radio/index",
"van-radio-group": "@vant/weapp/radio-group/index",
"van-uploader": "@vant/weapp/uploader/index",
"van-image": "@vant/weapp/image/index"
},
"navigationBarTitleText": "签名"
}