引用页面
<template><view><signature :showCanvas="showCanvas" @closeCanvas="closeCanvas"></signature><u-button @click="sign">签名</u-button></view>
</template>
<script>
import signature from '@/components/signature.vue';
export default {components: {signature},data() {return {//打开canvas绘制签名showCanvas: false,//是否展示操作菜单completionSignPath: '' //签名}},methods: {//隐藏canvas签名组件closeCanvas(e) {this.showCanvas = false;if (!this.$isEmpty(e)) {this.completionSignPath = e}},sign() {this.showCanvas = true;}}
}
</script>
sagnature.vue
<template><view class="signature-box"><!-- 签名 --><view class="signature" v-show="showCanvas"><canvas class="mycanvas" canvas-id="mycanvas" @touchstart="touchstart" @touchmove="touchmove"@touchend="touchend"></canvas><view class="footer"><u-button @click="finish" type="primary" :plain="true" :ripple="true" ripple-bg-color="#909399">保存</u-button><u-button @click="clear" type="warning" :plain="true" :ripple="true" ripple-bg-color="#909399">清除</u-button><u-button @click="close" type="error" :plain="true" :ripple="true" ripple-bg-color="#909399">关闭</u-button></view></view><!-- 签完名后生成的图片 --><view v-show="SignatureImg" class="SignatureImg"><image :src="SignatureImg" mode=""></image></view><!-- 清除签完名后生成的图片 --><u-button v-show="SignatureImg" @click="obliterate" type="error" :plain="true" :ripple="true"ripple-bg-color="#909399" size="medium">清除签名</u-button></view>
</template>
<script>import { pathToBase64 } from '@/common/js/jssdk_image_tools.js'var x = 20;var y = 20;export default {data() {return {//绘图图像ctx: '',//路径点集合points: [],//签名图片SignatureImg: '',hasSign: false};},props: ['showCanvas'],methods: {//清除签名的图片obliterate() {if (this.SignatureImg) {this.SignatureImg = '';}this.close();},//关闭并清空画布close() {this.$emit('closeCanvas');this.clear();},//创建并显示画布createCanvas() {this.ctx = uni.createCanvasContext('mycanvas', this); //创建绘图对象this.ctx.setFillStyle('#000000')this.ctx.fillStyle = '#000000'//设置画笔样式this.ctx.lineWidth = 4;this.ctx.lineCap = 'round';this.ctx.lineJoin = 'round';console.log(this.ctx)},//触摸开始,获取到起点touchstart(e) {let startX = e.changedTouches[0].x;let startY = e.changedTouches[0].y;let startPoint = {X: startX,Y: startY};this.points.push(startPoint);//每次触摸开始,开启新的路径this.ctx.beginPath();},//触摸移动,获取到路径点touchmove(e) {let moveX = e.changedTouches[0].x;let moveY = e.changedTouches[0].y;let movePoint = {X: moveX,Y: moveY};this.points.push(movePoint); //存点let len = this.points.length;if (len >= 2) {this.draw(); //绘制路径}},// 触摸结束,将未绘制的点清空防止对后续路径产生干扰touchend() {this.points = [];},//绘制笔迹draw() {let point1 = this.points[0];let point2 = this.points[1];this.points.shift();this.ctx.moveTo(point1.X, point1.Y);this.ctx.lineTo(point2.X, point2.Y);this.ctx.stroke();this.ctx.draw(true);this.hasSign = true},//清空画布clear() {this.hasSign = falselet that = this;uni.getSystemInfo({success: function(res) {let canvasw = res.windowWidth;let canvash = res.windowHeight;that.ctx.clearRect(0, 0, canvasw, canvash);that.ctx.draw(true);}});},//完成绘画并保存到本地finish() {if (!this.hasSign) {uni.showToast({title: '签名为空不能保存',icon: 'none',duration: 2000})return}let that = this;uni.canvasToTempFilePath({canvasId: 'mycanvas',success: function(res) {if(!res || !res.tempFilePath) {console.log(res.tempFilePath);that.SignatureImg = res.tempFilePath;that.$emit('closeCanvas', that.SignatureImg);that.close();}else{//用来解决安卓真机获取到的是canvas图片的临时路径,转成base64格式pathToBase64(res.tempFilePath).then(re => {console.log(re);that.SignatureImg = re;that.$emit('closeCanvas', that.SignatureImg);that.close();})}}});}},mounted() {this.createCanvas();}};
</script>
<style lang="less" scoped>.signature-box {display: flex;flex-direction: column;align-items: center;background: // height: calc(100vh-44rpx);//签名模块.signature {position: fixed;top: 10px;left: 2%;z-index: 999;width: 96%;//canvas.mycanvas {width: 100%;// height: calc(100vh - 200upx);height: calc(100vh - 180rpx);background-color: border-radius: 10px 10px 0 0;}//底部按钮.footer {font-size: 14px;height: 150upx;display: flex;justify-content: space-around;align-items: center;background-color: border-radius: 0 0 10px 10px;border-top: 1px solid }}//生成的图片.SignatureImg {image {width: 750rpx;height: 750rpx;}}}
</style>
jssdk_image_tools.js(用来解决安卓真机获取到的是canvas图片的临时路径,转成base64格式)
function getLocalFilePath(path) {if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {return path}if (path.indexOf('file://') === 0) {return path}if (path.indexOf('/storage/emulated/0/') === 0) {return path}if (path.indexOf('/') === 0) {var localFilePath = plus.io.convertAbsoluteFileSystem(path)if (localFilePath !== path) {return localFilePath} else {path = path.substr(1)}}return '_www/' + path
}function dataUrlToBase64(str) {var array = str.split(',')return array[array.length - 1]
}var index = 0
function getNewFileId() {return Date.now() + String(index++)
}function biggerThan(v1, v2) {var v1Array = v1.split('.')var v2Array = v2.split('.')var update = falsefor (var index = 0; index < v2Array.length; index++) {var diff = v1Array[index] - v2Array[index]if (diff !== 0) {update = diff > 0break}}return update
}export function pathToBase64(path) {return new Promise(function(resolve, reject) {if (typeof window === 'object' && 'document' in window) {if (typeof FileReader === 'function') {var xhr = new XMLHttpRequest()xhr.open('GET', path, true)xhr.responseType = 'blob'xhr.onload = function() {if (this.status === 200) {let fileReader = new FileReader()fileReader.onload = function(e) {resolve(e.target.result)}fileReader.onerror = rejectfileReader.readAsDataURL(this.response)}}xhr.onerror = rejectxhr.send()return}var canvas = document.createElement('canvas')var c2x = canvas.getContext('2d')var img = new Imageimg.onload = function() {canvas.width = img.widthcanvas.height = img.heightc2x.drawImage(img, 0, 0)resolve(canvas.toDataURL())canvas.height = canvas.width = 0}img.onerror = rejectimg.src = pathreturn}if (typeof plus === 'object') {plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {entry.file(function(file) {var fileReader = new plus.io.FileReader()fileReader.onload = function(data) {resolve(data.target.result)}fileReader.onerror = function(error) {reject(error)}fileReader.readAsDataURL(file)}, function(error) {reject(error)})}, function(error) {reject(error)})return}if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {wx.getFileSystemManager().readFile({filePath: path,encoding: 'base64',success: function(res) {resolve('data:image/png;base64,' + res.data)},fail: function(error) {reject(error)}})return}reject(new Error('not support'))})
}export function base64ToPath(base64) {return new Promise(function(resolve, reject) {if (typeof window === 'object' && 'document' in window) {base64 = base64.split(',')var type = base64[0].match(/:(.*?);/)[1]var str = atob(base64[1])var n = str.lengthvar array = new Uint8Array(n)while (n--) {array[n] = str.charCodeAt(n)}return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))}var extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/)if (extName) {extName = extName[1]} else {reject(new Error('base64 error'))}var fileName = getNewFileId() + '.' + extNameif (typeof plus === 'object') {var basePath = '_doc'var dirPath = 'uniapp_temp'var filePath = basePath + '/' + dirPath + '/' + fileNameif (!biggerThan(plus.os.name === 'Android' ? '1.9.9.80627' : '1.9.9.80472', plus.runtime.innerVersion)) {plus.io.resolveLocalFileSystemURL(basePath, function(entry) {entry.getDirectory(dirPath, {create: true,exclusive: false,}, function(entry) {entry.getFile(fileName, {create: true,exclusive: false,}, function(entry) {entry.createWriter(function(writer) {writer.onwrite = function() {resolve(filePath)}writer.onerror = rejectwriter.seek(0)writer.writeAsBinary(dataUrlToBase64(base64))}, reject)}, reject)}, reject)}, reject)return}var bitmap = new plus.nativeObj.Bitmap(fileName)bitmap.loadBase64Data(base64, function() {bitmap.save(filePath, {}, function() {bitmap.clear()resolve(filePath)}, function(error) {bitmap.clear()reject(error)})}, function(error) {bitmap.clear()reject(error)})return}if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {var filePath = wx.env.USER_DATA_PATH + '/' + fileNamewx.getFileSystemManager().writeFile({filePath: filePath,data: dataUrlToBase64(base64),encoding: 'base64',success: function() {resolve(filePath)},fail: function(error) {reject(error)}})return}reject(new Error('not support'))})
}