<template>
<canvas id="canvas" :width="canvasWidth" :height="canvasHeight" :style="`background:${canvasBackgroung}`"></canvas>
</template>
<script>
/**
* @canvasWidth : 画布宽度 type: Number
* @canvasHeight : 画布高度 type: Number
* @canvasBackgroung : 画布颜色 type: String, 颜色值
* @lineWidth : 画笔粗细 type: Number
* @stokeColor : 画笔颜色 type: String, 颜色值
* save() : url: base64格式图片,file:png图片文件 调用保存方法并返回签名图片文件及base64格式图片
* clear() : 清除画板
*/
var draw;
var preHandler = function(e) {
e.preventDefault(); //阻止默认事件
};
class Draw {
constructor(el) {
this.el = el;
this.canvas = document.getElementById(this.el);
this.cxt = this.canvas.getContext("2d"); //设置绘图环境为2D
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
this.stage_info = canvas.getBoundingClientRect(); //用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
this.path = {
beginX: 0,
beginY: 0,
endX: 0,
endY: 0
};
}
init(btn) {
var that = this;
this.canvas.addEventListener("touchstart", function(event) { //给canvas添加触摸开始事件
document.addEventListener("touchstart", preHandler, false); //当点击画布进行绘制时,禁止canvas外部默认事件
that.drawBegin(event);
});
this.canvas.addEventListener("touchend", function(event) { //给canvas添加触摸结束事件
document.addEventListener("touchend", preHandler, false); //当触摸离开时,禁止canvas外部默认事件
that.drawEnd();
});
this.clear(btn); //清除画布
}
drawBegin(e) {
var that = this;
window.getSelection() //双击禁止选中文字 || (),返回一个Selection对象,表示用户选择的文本范围或光标的当前位置。
? window.getSelection().removeAllRanges() //将所有的区域都从选区中移除
: document.selection.empty(); //让选中的内容不选中
this.cxt.beginPath(); //起始一条路径,或重置当前路径
this.cxt.moveTo( //把路径移动到画布中的指定点,不创建线条
e.changedTouches[0].clientX - this.stage_info.left,
e.changedTouches[0].clientY - this.stage_info.top
);
this.path.beginX = e.changedTouches[0].clientX - this.stage_info.left;
this.path.beginY = e.changedTouches[0].clientY - this.stage_info.top;
canvas.addEventListener("touchmove", function() {
that.drawing(event);
});
}
drawing(e) {
this.cxt.lineTo( //添加一个新点,然后在画布中创建从该点到最后指定点的线条
e.changedTouches[0].clientX - this.stage_info.left,
e.changedTouches[0].clientY - this.stage_info.top
);
this.path.endX = e.changedTouches[0].clientX - this.stage_info.left;
this.path.endY = e.changedTouches[0].clientY - this.stage_info.top;
this.cxt.stroke(); //绘制已定义的路径
}
drawEnd() {
document.removeEventListener("touchstart", preHandler, false); //触摸开始时移除阻止默认事件
document.removeEventListener("touchend", preHandler, false); //触摸结束时移除阻止默认事件
document.removeEventListener("touchmove", preHandler, false); //手指在屏幕上移动时移除阻止默认事件
}
clear(btn) {
this.cxt.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight); //在给定的矩形内清除指定的像素
}
save() {
let url = canvas.toDataURL("image/png") //base64格式的签名图片文件
let file = this.dataURLtoFile(url) //base64转换后获得的签名图片文件
let imgData = {
url,
file
}
return imgData
}
//将base64转换为文件
dataURLtoFile(dataurl, filename) {
let arr = dataurl.split(',') //得到base64后面的文件数据
let mime = arr[0].match(/:(.*?);/)[1]; //得到文件类型 image/png
if(!filename) {//若无文件名则取当前时间戳
filename = Date.parse(new Date()) + '.png';
}
let bstr = atob(arr[1]) //将base64文件数据进行解码
let n = bstr.length //得到解码后数据的长度
let u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}
}
export default {
props: {
canvasWidth: {
type: Number,
default: 0
},
canvasHeight: {
type: Number,
default: 0
},
canvasBackgroung: {
type: String,
default: '#fff'
},
lineWidth: {
type: Number,
default: 1
},
stokeColor: {
type: String,
default: 'black'
}
},
data () {
return {
url: "", //签名的base64格式
imgFile:'', //签名图片文件
}
},
mounted() {
draw = new Draw("canvas");
draw.cxt.strokeStyle = this.stokeColor; //画笔颜色
draw.cxt.lineWidth = this.lineWidth; //画笔粗细
draw.init();
},
methods: {
//清除签名画板
clear: function() {
draw.clear();
},
//获取到签名文件
save: function() {
var data = draw.save();
this.url = data.url; //base64格式的签名图片
this.imgFile = data.file //签名的图片文件
return data;
},
}
}
</script>
<style lang="scss" scoped>
#canvas {
touch-action: none; //去掉滑动的默认样式
cursor: default; //鼠标样式为默认样式
}
</style>