uniapp微信小程序canvse签名

uniapp yekong

wanjunshijiecom20220611TZbLsS

代码改自用户签名签字组件-兼容H5、小程序、APP、可导出SVG

用户签名签字组件-兼容H5、小程序、APP、可导出SVG

代码

<template>
	<view class="canvas-container">
		<u-navbar :title="$t('transportAgreementSigned')" :safeAreaInsetTop="true" :placeholder='true' :autoBack="true">
		</u-navbar>
		<autograph v-show="status==0" @getdata="getdata"></autograph>
		<div class="write-box" :class="{show:status==1}">
			<view class="head">
				<view class="title">
					{{$t('autograph.tips')}}
				</view>
			</view>
			<view class="canvas-wrap">
				<div class="write-block">
					<canvas disable-scroll="true" class="signature" canvas-id="myCanvas" @touchstart="touchstart"
						id="myCanvas" @touchmove="touchmove" @touchend="touchend"></canvas>
				</div>
			</view>
			<view class="foot">
				<button type="default" class="btn" @tap="clearSignature()">{{$t('rewrite')}}</button>
				<button type="default" class="btn" @tap="handleSaveCanvas()">{{$t('submit')}}</button>
			</view>
		</div>
	</view>
</template>
<script>
	import autograph from "@/components/autograph/autograph.vue"
	import {
		singlog
	} from '@/config/api.js'
	export default {
		cxt: null,
		components: {
			autograph
		},
		data() {
			return {
				canvas: null,
				status: 0,
				v: '',
				url: '',
				openSmooth: true,
				data: {
					img: '',
					email: '',
					sms_code: '',
					mobile: '',
					username: ''
				},
				VERSION: '1.0.0',
				cid: 'myCanvas',
				show: true,
				ctrl: null,
				listeners: [],
				prevView: '',
				draws: [],
				lines: [],
				line: null,
				value: '',
				disabled: false,
			};
		},
		onReady: function() {
			var that = this;
			wx.showShareMenu({
				withShareTicket: true,
				menus: ["shareAppMessage", "shareTimeline"]
			})
		},
		mounted() {
			this.prevView = this.value;
			this.touchSignature()
		},
		watch: {
			value() {
				this.prevView = this.value;
			}
		},
		computed: {
			absPrevView() {
				var pv = this.prevView;
				// if(pv){
				// 	pv = this.$wrapUrl(pv)
				// }
				return pv;
			}
		},
		methods: {
			async startSign() {
				let s = await this.$refs.sig.getSyncSignature();
				console.log('组件版本', this.$refs.sig.VERSION);
				console.log('签名数据', s);
			},
			handleSaveCanvas() {
				var that = this;
				uni.canvasToTempFilePath({
					canvasId: 'myCanvas',
					success(res) {
						console.log(res)
						wx.getFileSystemManager().readFile({
							filePath: res.tempFilePath, //图片路径
							encoding: 'base64', //编码格式
							success: res => { //成功的回调
								var data = 'data:image/png;base64,' + res.data
								console.log(data)
								that.data.img = data
								that.singlog()
							}
						})
					}
				})
			},
			onOK() {
				let data = this.ctrl.getValue();
				this.$emit('input', data);
				this.prevView = data;
				let f = this.listeners.shift();
				if (f) {
					f(data);
				}
				this.data.img = data
				this.singlog()
			},
			touchSignature() {
				let sig = this.prevView
				if (!sig || !sig.length) {
					this.showSignature()
				}
			},
			showSignature() {
				if (this.disabled)
					return;
				if (!this.ctrl) {
					this.initCtrl();
				} else if (!this.show) {
					this.clearSignature();
					this.show = true;
				}
			},
			async getSyncSignature() {
				this.showSignature();
				return await new Promise(async (resolve, reject) => {
					this.listeners.push((res) => {
						resolve(res);
					});
				});
			},
			cancelSignature() {
				this.listeners.map((f) => {
					f(null);
				})
				this.hideSignature();
			},
			hideSignature() {
				this.ctrl && this.ctrl.clear();
				this.show = false;
			},
			clearSignature() {
				this.ctrl && this.ctrl.clear();
			},
			async initCtrl() {
				this.show = true;
				let cxt = uni.createCanvasContext(this.cid, this);
				this.cxt = cxt;
				// cxt.clearRect(0,0,c.width,c.height);
				this.ctrl = {
					width: 0,
					height: 0,
					clear: () => {
						this.lines = [];
						let info = uni.createSelectorQuery().in(this).select("." + this.cid);
						info.boundingClientRect((data) => {
							if (data) {
								cxt.clearRect(0, 0, data.width, data.height);
								if (data.width && data.height) {
									this.ctrl.width = data.width;
									this.ctrl.height = data.height;
								}
							}
						}).exec();
						this.redraw();
					},
					getValue: () => {
						if (!this.lines.length)
							return '';
						let svg = this._get_svg();
						// new Buff
						let b64 = base64encode(svg);
						let data = 'data:image/svg+xml;base64,' + b64;
						// console.log(svg);
						// console.log(data);
						return data;
					},
				};
				this.$nextTick(function() {
					this.ctrl.clear();
				})
			},
			_get_svg() {
				let r = -90;
				let paths = [];
				let raww = this.ctrl.width;
				let rawh = this.ctrl.height;
				let width = Math.abs(r) != 90 ? raww : rawh;
				let height = Math.abs(r) == 90 ? raww : rawh;
				let cx = raww / 2;
				let cy = rawh / 2;
				let PI = Math.PI;
				let R = (r || 0) % 360;
				let cosv = Math.cos(R * PI / 180);
				let sinv = Math.sin(R * PI / 180);
				let dcx = (width - raww) / 2;
				let dcy = (height - rawh) / 2;
				let trans = function(p) {
					if (!R) {
						return p;
					} else {
						let nx = (p.x - cx) * cosv - (p.y - cy) * sinv + cx;
						let ny = (p.x - cx) * sinv + (p.y - cy) * cosv + cy;
						return {
							x: nx + dcx,
							y: ny + dcy
						};
					}
					return p;
				}
				this.lines.map(l => {
					if (l.points.length < 2) {
						return;
					}
					let sp = trans(l.start)
					let pts = [`M ``{sp.x} ``{Number(sp.y)}`];
					l.points.map(p => {
						let np = trans(p)
						pts.push(`L ``{np.x} ``{Number(np.y)}`);
					});
					paths.push(
						`<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(' ')}"/>`
					);
				})
				let svg =
					`<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="``{width}" height="``{height}">${paths.join('\n')}</svg>`;
				return svg;
			},
			_get_svg_raw() {
				let paths = [];
				this.lines.map(l => {
					if (l.points.length < 2) {
						return;
					}
					let pts = [`M ``{l.start.x} ``{Number(l.start.y)}`];
					l.points.map(p => {
						pts.push(`L ``{p.x} ``{Number(p.y)}`);
					});
					paths.push(
						`<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(' ')}"/>`
					);
				})
				let width = this.ctrl.width;
				let height = this.ctrl.height;
				let svg =
					`<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="``{width}" height="``{height}" transform="rotate(-90)">${paths.join('\n')}</svg>`;
				return svg;
			},
			_get_point(e) {
				return {
					x: e.changedTouches[0].x.toFixed(1),
					y: e.changedTouches[0].y.toFixed(1),
				}
			},
			touchstart(e) {
				let p = this._get_point(e);
				this.line = {
					start: p,
					points: [p],
				}
				this.lines.push(this.line);
			},
			touchmove(e) {
				let p = this._get_point(e);
				this.line.points.push(p)
				if (!this.tm) {
					this.tm = setTimeout(() => {
						this.redraw();
						this.tm = 0;
					}, 10)
				}
			},
			touchend(e) {
				let p = this._get_point(e);
				this.line.points.push(p)
				this.line.end = p
				this.redraw()
			},
			redraw() {
				let cxt = this.cxt;
				cxt.setStrokeStyle("#000");
				cxt.setLineWidth(3);
				var last = null;
				this.lines.map(l => {
					cxt.beginPath();
					if (l.points.length < 2) {
						return;
					}
					cxt.moveTo(l.start.x, l.start.y);
					l.points.map(p => {
						cxt.lineTo(p.x, p.y)
					})
					cxt.stroke()
				})

				cxt.draw()
			},
			canvasIdErrorCallback: function(e) {
				console.error(e.detail.errMsg)
			},
			getdata(e) {
				this.data = e
				this.status = 1
			},
			singlog() {
				var that = this;
				singlog(this.data, {
					custom: {
						auth: true
					}
				}).then(res => {
					if (res.status == 200) {
						uni.showToast({
							title: res.msg,
							icon: 'none'
						})
						uni.navigateBack({

						})
					} else {
						uni.showToast({
							title: res.msg,
							icon: 'none'
						})
						that.status = 0
					}
				}).catch(err => {

				})
			},
			handleClearCanvas(event) {
				this.signaturePad.clear();
			}
		}
	};
</script>
<style scoped lang="scss">
	page {
		width: 100%;
		height: 100%;
	}

	.canvas-container {
		width: 100%;
		height: 100%;
		display: flex;
		flex-direction: column;
	}

	.canvas-wrap {
		flex: 1;
	}

	.canvas-btn-wrap {
		margin: 20rpx 0;
		display: flex;
		justify-content: space-around;
		align-items: center;
	}

	.canvas-btn {
		display: inline-block;
	}

	.write-box {
		background-color: #fff;
		border-radius: 20rpx;
		padding: 0 30rpx;
		position: fixed;
		top: -100000rpx;
		left: -10000rpx;


		.title {
			font-size: 30rpx;
			color: #333333;
			text-align: center;
			line-height: 88rpx;
			height: 88rpx;
		}

		.write-block {
			border: 1rpx dashed #aaaaaa;
			border-radius: 10rpx;
			height: 572rpx;
			width: 689rpx;

			canvas {
				height: 572rpx;
				width: 689rpx;
			}

		}

		.foot {
			padding: 30rpx;
			display: flex;
			align-items: center;
			justify-content: space-between;

			.btn {
				font-size: 30rpx;
				color: #fff;
				background-color: #cccccc;
				border-radius: 10rpx;
				height: 74rpx;
				line-height: 74rpx;
				width: 196rpx;
				margin: 0 30rpx;
			}
		}
	}

	.write-box.show {
		position: relative;
		top: 0rpx;
		left: 0rpx;
	}

	.body {
		height: 400rpx;
	}
</style>

喜欢