@mousedown=“mouseDown”
@mousemove=“mouseMove”
@mouseup=“mouseUp” 为pc端需求
@touchstart=“touchStart”
@touchmove=“touchMove”
@touchend=“touchEnd” 为移动端需求
将canvas转换成base64位编码格式的图片,压缩图片后,可将值进行异步请求
<template>
<div class="signatureBox">
<div class="visaDetailTop">
<p class="visaTitle">电子签名</p>
</div>
<div class="canvasBox" ref="canvasHW">
<canvas
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
ref="canvasF"
@mousedown="mouseDown"
@mousemove="mouseMove"
@mouseup="mouseUp"
></canvas>
<div class="btnBox">
<button @click="overwrite">重写</button>
<button @click="sunmitWrite">提交签名</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: "",
data() {
return {
points: [],
canvasTxt: null,
stage_info: [],
startX: 0,
startY: 0,
moveY: 0,
moveX: 0,
endY: 0,
endX: 0,
w: null,
h: null,
isDown: false,
X: [],
Y: []
};
},
created() {},
mounted() {
let canvas = this.$refs.canvasF;
canvas.height = this.$refs.canvasHW.offsetHeight - 60;
canvas.width = this.$refs.canvasHW.offsetWidth - 10;
this.canvasTxt = canvas.getContext("2d");
this.stage_info = canvas.getBoundingClientRect();
this.canvasTxt.lineWidth = 4;
},
components: {},
methods: {
mouseDown(ev) {
ev = ev || event;
ev.preventDefault();
if (1) {
let obj = {
x: ev.offsetX,
y: ev.offsetY
};
this.startX = obj.x;
this.startY = obj.y;
this.canvasTxt.beginPath();
this.canvasTxt.moveTo(this.startX, this.startY);
this.canvasTxt.lineTo(obj.x, obj.y);
this.canvasTxt.stroke();
this.canvasTxt.closePath();
this.points.push(obj);
this.isDown = true;
}
}, //移动设备事件
touchStart(ev) {
console.log("touchStart");
ev = ev || event;
ev.preventDefault();
if (ev.touches.length == 1) {
let obj = {
x: ev.targetTouches[0].clientX - this.stage_info.left,
y: ev.targetTouches[0].clientY - this.stage_info.top
};
this.startX = obj.x;
this.startY = obj.y;
this.canvasTxt.beginPath();
this.canvasTxt.moveTo(this.startX, this.startY);
this.canvasTxt.lineTo(obj.x, obj.y);
this.canvasTxt.stroke();
this.canvasTxt.closePath();
this.points.push(obj);
}
}, //电脑设备事件
mouseMove(ev) {
ev = ev || event;
ev.preventDefault();
if (this.isDown) {
let obj = {
x: ev.offsetX,
y: ev.offsetY
};
this.moveY = obj.y;
this.moveX = obj.x;
this.canvasTxt.beginPath();
this.canvasTxt.moveTo(this.startX, this.startY);
this.canvasTxt.lineTo(obj.x, obj.y);
this.canvasTxt.stroke();
this.canvasTxt.closePath();
this.startY = obj.y;
this.startX = obj.x;
this.points.push(obj);
}
}, //移动设备事件
touchMove(ev) {
console.log("touchMove");
ev = ev || event;
ev.preventDefault();
if (ev.touches.length == 1) {
let obj = {
x: ev.targetTouches[0].clientX - this.stage_info.left,
y: ev.targetTouches[0].clientY - this.stage_info.top
};
this.moveY = obj.y;
this.moveX = obj.x;
this.canvasTxt.beginPath();
this.canvasTxt.moveTo(this.startX, this.startY);
this.canvasTxt.lineTo(obj.x, obj.y);
this.canvasTxt.stroke();
this.canvasTxt.closePath();
this.startY = obj.y;
this.startX = obj.x;
this.points.push(obj);
}
}, //电脑设备事件
mouseUp(ev) {
ev = ev || event;
ev.preventDefault();
if (1) {
let obj = {
x: ev.offsetX,
y: ev.offsetY
};
this.canvasTxt.beginPath();
this.canvasTxt.moveTo(this.startX, this.startY);
this.canvasTxt.lineTo(obj.x, obj.y);
this.canvasTxt.stroke();
this.canvasTxt.closePath();
this.points.push(obj);
this.points.push({ x: -1, y: -1 });
this.isDown = false;
}
}, //移动设备事件
touchEnd(ev) {
console.log("touchEnd");
ev = ev || event;
ev.preventDefault();
if (ev.touches.length == 1) {
let obj = {
x: ev.targetTouches[0].clientX - this.stage_info.left,
y: ev.targetTouches[0].clientY - this.stage_info.top
};
this.canvasTxt.beginPath();
this.canvasTxt.moveTo(this.startX, this.startY);
this.canvasTxt.lineTo(obj.x, obj.y);
this.canvasTxt.stroke();
this.canvasTxt.closePath();
this.points.push(obj);
this.points.push({ x: -1, y: -1 });
}
},
//重写
overwrite() {
this.canvasTxt.clearRect(
0,
0,
this.$refs.canvasF.width,
this.$refs.canvasF.height
);
this.points = [];
this.Y = [];
this.X = [];
},
//提交图片
sunmitWrite() {
this.points.map(item => {
this.X.push(item.x);
this.Y.push(item.y);
});
/**
* 签名所辐射的区域如果小于总屏幕的1/4,则签名太小,重新签名
*/
let baseAcreage =
(Math.max.apply(null, this.X) - Math.min.apply(null, this.X)) *
(Math.max.apply(null, this.Y) - Math.min.apply(null, this.Y));
if (baseAcreage == Infinity) {
alert("请签名");
return
}
let canvasAcreage = this.$refs.canvasF.width * this.$refs.canvasF.height;
if (canvasAcreage / baseAcreage >= 4) {
alert("亲,签名太小啦,请重新签名嘛!!!");
this.overwrite();
} else {
let baseImg = this.$refs.canvasF.toDataURL();
this.dealImage(baseImg, 200, callback => {
/**
* 200为base64转码后,图片的宽度大小
*/
console.log(callback, "在这里提交数据");
});
}
},
//压缩图片
dealImage(base64, w, callback) {
var newImage = new Image();
var quality = 0.6; //压缩系数0-1之间
newImage.src = base64;
newImage.setAttribute("crossOrigin", "Anonymous"); //url为外域时需要
var imgWidth, imgHeight;
newImage.onload = function() {
imgWidth = this.width;
imgHeight = this.height;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
if (Math.max(imgWidth, imgHeight) > w) {
if (imgWidth > imgHeight) {
canvas.width = w;
canvas.height = (w * imgHeight) / imgWidth;
} else {
canvas.height = w;
canvas.width = (w * imgWidth) / imgHeight;
}
} else {
canvas.width = imgWidth;
canvas.height = imgHeight;
quality = 0.6;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
var base64 = canvas.toDataURL("image/png", quality); //压缩语句
// 如想确保图片压缩到自己想要的尺寸,如要求在50-150kb之间,请加以下语句,quality初始值根据情况自定
// while (base64.length / 1024 > 150) {
// quality -= 0.01;
// base64 = canvas.toDataURL("image/png", quality);
// }
// // 防止最后一次压缩低于最低尺寸,只要quality递减合理,无需考虑
// while (base64.length / 1024 < 50) {
// quality += 0.001;
// base64 = canvas.toDataURL("image/png", quality);
// }
callback(base64);
};
}
}
};
</script>
<style scoped>
.signatureBox {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
box-sizing: border-box;
overflow: hidden;
background: #fff;
z-index: 100;
display: flex;
flex-direction: column;
}
.visaDetailTop {
width: 100%;
padding: 5px;
box-sizing: border-box;
z-index: 2;
border-bottom: 1px solid #e5e5e5;
}
.visaDetailTop p {
margin: 0px;
text-align: center;
color: #000;
font-size: 1em;
}
p.visaTitle {
width: 100%;
text-align: center;
font-size: 1.2em;
}
.btnBack {
display: block;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 1;
background: transparent;
border-color: transparent;
outline: none;
}
.btnDaoHang {
display: block;
position: absolute;
left: 0px;
top: 0px;
height: 2.2em;
width: 2em;
z-index: 1;
background: transparent;
border-color: transparent;
outline: none;
}
.visaDetailTop p span {
color: #fff;
font-size: 1.2em;
}
.canvasBox {
padding: 10px 5px;
padding-top: 2px;
box-sizing: border-box;
flex: 1;
}
canvas {
border-bottom: 1px solid #e5e5e5;
}
.btnBox {
height: 30px;
padding: 5px;
text-align: right;
line-height: 30px;
}
.btnBox button:first-of-type {
border: 1px solid #71b900;
background: transparent;
border-radius: 4px;
padding: 5px 10px;
}
.btnBox button:last-of-type {
border: 1px solid #71b900;
background: #71b900;
color: #fff;
border-radius: 4px;
padding: 5px 10px;
}
@media only screen and (min-width: 750px) {
.signatureBox {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
min-height: 100%;
box-sizing: border-box;
overflow: visible;
}
}
</style>