代码改自用户签名签字组件-兼容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>