使用的是
vue:vue-signature-pad
react:react-signature-canvas
看下效果
-
touchstart
:当用户在触摸设备上触摸屏幕时触发。相当于鼠标事件中的mousedown
,表示用户开始触摸屏幕。 -
touchmove
:当用户在触摸设备上滑动手指时触发。相当于鼠标事件中的mousemove
,表示用户正在移动手指。 -
touchend
:当用户在触摸设备上松开手指时触发。相当于鼠标事件中的mouseup
,表示用户结束触摸操作。
4.touchcancel
:当触摸事件被取消时触发,例如由于系统事件或触摸点超出了浏览器边界。类似于mouseleave
事件,表示触摸操作在某种情况下被取消
这里在切换成竖屏的时候会有偏移量
<template>
<div id="app">
<div style="background: #fff; border:1px solid red;">
<vue-signature-pad
id="signature"
width="95%"
height="400px"
ref="signaturePad"
:options="options"
v-if='fullScrean'
/>
<vue-signature-pad
id="signature"
width="95%"
height="200px"
ref="signaturePad"
:options="options"
v-if='!fullScrean'
/>
</div>
<div v-for="(item, index) in imgList" :key="index">
<img :src="item.src" alt="" width="100" />
</div>
<div class="buttons">
<button @click="fullScreanFuc" class="btn">全屏</button>
<button @click="save" class="btn">保存</button>
<button @click="resume" class="btn">重置</button>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
options: {
penColor: '#000',
},
imgList: [],
fileList: [],
fullScrean:false,
}
},
methods: {
fullScreanFuc(){
this.fullScrean = !this.fullScrean
this.imgList = []
this.fileList = []
this.resume()
if(this.fullScrean){
console.log(this.fullScrean)
console.log(this.$refs.signaturePad)
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
// 定义变量来跟踪绘画状态和偏移量
var isDrawing = false;
var offsetYPercent = 0.5; // 20%
// 计算偏移量
var offsetY = canvas.height * offsetYPercent;
// 监听鼠标按下事件
canvas.addEventListener('mousedown', function(event) {
isDrawing = true;
// 将绘制路径的起始点移动到鼠标点击位置
ctx.beginPath();
var x = event.clientX - canvas.offsetLeft;
var y = event.clientY - canvas.offsetTop + offsetY; // 添加偏移量
ctx.moveTo(x, y);
});
// 监听鼠标移动事件
canvas.addEventListener('mousemove', function(event) {
if (isDrawing) {
var x = event.clientX - canvas.offsetLeft;
var y = event.clientY - canvas.offsetTop + offsetY; // 添加偏移量
// 绘制线条到当前鼠标位置
ctx.lineTo(x, y);
ctx.stroke();
}
});
// 监听鼠标松开事件
canvas.addEventListener('mouseup', function() {
isDrawing = false;
});
// 监听鼠标离开 Canvas 区域事件
canvas.addEventListener('mouseleave', function() {
isDrawing = false;
});
}
},
save() {
const { isEmpty, data } = this.$refs.signaturePad.saveSignature()
console.log(isEmpty,data)
if(this.fullScrean){
this.rotateBase64Img(data, 90, (res) => {
console.log(res) // 旋转后的base64图片src
this.fileList.push({
file: this.dataURLtoFile(res, 'sign'),
name: 'sign',
})
this.imgList.push({
src: res,
})
})
}else{
this.imgList.push({
src: data,
})
}
},
// 清除重置
resume() {
this.$refs.signaturePad.clearSignature()
},
// 将base64转换为文件
dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, { type: mime })
},
// 通过canvas旋转图片
rotateBase64Img(src, edg, callback) {
var canvas = document.createElement('canvas')
var ctx = canvas.getContext('2d')
var imgW //图片宽度
var imgH //图片高度
var size //canvas初始大小
if (edg % 90 != 0) {
console.error('旋转角度必须是90的倍数!')
throw '旋转角度必须是90的倍数!'
}
edg < 0 && (edg = (edg % 360) + 360)
const quadrant = (edg / 90) % 4 //旋转象限
const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 } //裁剪坐标
var image = new Image()
image.crossOrigin = 'anonymous'
image.src = src
image.onload = function () {
imgW = image.width
imgH = image.height
size = imgW > imgH ? imgW : imgH
canvas.width = size * 2
canvas.height = size * 2
switch (quadrant) {
case 0:
cutCoor.sx = size
cutCoor.sy = size
cutCoor.ex = size + imgW
cutCoor.ey = size + imgH
break
case 1:
cutCoor.sx = size - imgH
cutCoor.sy = size
cutCoor.ex = size
cutCoor.ey = size + imgW
break
case 2:
cutCoor.sx = size - imgW
cutCoor.sy = size - imgH
cutCoor.ex = size
cutCoor.ey = size
break
case 3:
cutCoor.sx = size
cutCoor.sy = size - imgW
cutCoor.ex = size + imgH
cutCoor.ey = size + imgW
break
}
ctx.translate(size, size)
ctx.rotate((edg * Math.PI) / 180)
ctx.drawImage(image, 0, 0)
var imgData = ctx.getImageData(
cutCoor.sx,
cutCoor.sy,
cutCoor.ex,
cutCoor.ey
)
if (quadrant % 2 == 0) {
canvas.width = imgW
canvas.height = imgH
} else {
canvas.width = imgH
canvas.height = imgW
}
ctx.putImageData(imgData, 0, 0)
callback(canvas.toDataURL())
}
},
},
}
</script>
<style lang="scss">
html,
body {
padding: 0;
margin: 0;
}
#app {
width: 100vw;
height: 100vh;
background: #ececec;
}
.btn {
width: 35%;
color: #fff;
background: #5daaf3;
border: none;
height: 40px;
border-radius: 20px;
margin-top: 20px;
margin-left: 40px;
}
</style>
就要设置偏移量,但是这个组件内部封装了canvas,,不太好设置
于是自己写了个
<template>
<view class="content">
<view class="text-area">
<canvas
id="drawCol"
ref="drawCol"
v-if="isCol"
width="400"
height="400"
></canvas>
<canvas
id="drawRow"
ref="drawRow"
v-if="!isCol"
width="400"
height="800"
></canvas>
</view>
<img
:src="src"
v-if="isCol"
style="border: 1px solid red; width: 200px; height: 200px"
/>
<img
:src="src"
v-if="!isCol"
style="border: 1px solid red; width: 400px; height: 200px"
/>
<br />
<button @click="drawCol('drawCol')">横屏</button>
<br />
<button @click="drawRow('drawRow')">竖屏</button>
<br />
<button @click="submit">提交</button>
<br />
<button @click="hasContentFuc">有值吗</button>
{{ hasContent }}
</view>
</template>
<script>
export default {
data() {
return {
title: "Hello",
isCol: true,
src: "",
hasContent: false,
};
},
mounted() {},
methods: {
rotateBase64Img(src, edg, callback) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var imgW; //图片宽度
var imgH; //图片高度
var size; //canvas初始大小
if (edg % 90 != 0) {
console.error("旋转角度必须是90的倍数!");
throw "旋转角度必须是90的倍数!";
}
edg < 0 && (edg = (edg % 360) + 360);
const quadrant = (edg / 90) % 4; //旋转象限
const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 }; //裁剪坐标
var image = new Image();
image.crossOrigin = "anonymous";
image.src = src;
image.onload = function () {
imgW = image.width;
imgH = image.height;
size = imgW > imgH ? imgW : imgH;
canvas.width = size * 2;
canvas.height = size * 2;
switch (quadrant) {
case 0:
cutCoor.sx = size;
cutCoor.sy = size;
cutCoor.ex = size + imgW;
cutCoor.ey = size + imgH;
break;
case 1:
cutCoor.sx = size - imgH;
cutCoor.sy = size;
cutCoor.ex = size;
cutCoor.ey = size + imgW;
break;
case 2:
cutCoor.sx = size - imgW;
cutCoor.sy = size - imgH;
cutCoor.ex = size;
cutCoor.ey = size;
break;
case 3:
cutCoor.sx = size;
cutCoor.sy = size - imgW;
cutCoor.ex = size + imgH;
cutCoor.ey = size + imgW;
break;
}
ctx.translate(size, size);
ctx.rotate((edg * Math.PI) / 180);
ctx.drawImage(image, 0, 0);
var imgData = ctx.getImageData(
cutCoor.sx,
cutCoor.sy,
cutCoor.ex,
cutCoor.ey
);
if (quadrant % 2 == 0) {
canvas.width = imgW;
canvas.height = imgH;
} else {
canvas.width = imgH;
canvas.height = imgW;
}
ctx.putImageData(imgData, 0, 0);
callback(canvas.toDataURL());
};
},
hasContentFuc() {
let canvas = document.getElementsByTagName("canvas");
console.log(1, canvas);
let ctx = canvas.getContext("2d");
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let data = imgData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i + 3] > 0) {
this.hasContent = true;
break;
}
}
},
submit() {
if (this.isCol) {
this.src = this.$refs.drawCol?.toDataURL();
} else {
this.rotateBase64Img(this.$refs.drawRow?.toDataURL(), 270, (res) => {
this.src = res;
});
}
console.log(this.$refs.drawCol, this.$refs.drawCol?.toDataURL());
console.log(this.$refs.drawRow, this.$refs.drawRow?.toDataURL());
},
drawCol(e) {
this.isCol = true;
this.$nextTick(() => {
this.startDrawn(e);
});
},
drawRow(e) {
this.isCol = false;
this.$nextTick(() => {
this.startDrawn(e);
});
},
startDrawn(e) {
var canvas = document.getElementById(e);
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
canvas.addEventListener("touchstart", startDrawing);
canvas.addEventListener("touchmove", continueDrawing);
canvas.addEventListener("touchend", stopDrawing);
var isDrawing = false;
function startDrawing(e) {
isDrawing = true;
var touch = e.touches[0];
var x = touch.clientX;
var y = touch.clientY;
ctx.beginPath();
ctx.moveTo(x, y);
}
function continueDrawing(e) {
if (!isDrawing) return;
var touch = e.touches[0];
var x = touch.clientX;
var y = touch.clientY;
ctx.lineTo(x, y);
ctx.stroke();
}
function stopDrawing() {
isDrawing = false;
}
// canvas.addEventListener("touchcancel", function () {
// isDrawing = false;
// });
},
},
};
</script>
<style>
/* .text-area {
border:1px solid red;
} */
canvas {
border: #333 1px solid;
}
</style>