<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>前端实现电子签名(web、移动端)通用</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas></canvas>
<div>
<button onclick="cancel()">取消</button>
<button onclick="save()">保存</button>
</div>
<script type="text/javascript">
const config = {
width: 400, // 宽度
height: 200, // 高度
lineWidth: 5, // 线宽
strokeStyle: 'red', // 线条颜色
lineCap: 'round', // 设置线条两端圆角
lineJoin: 'round', // 线条交汇处圆角
}
const canvas = document.querySelector("canvas");
canvas.width = config.width;
canvas.height = config.height;
canvas.style.border = '1px solid #000';
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'transparent';
ctx.fillRect(
0,
0,
config.width,
config.height
);
// 保存上次绘制的 坐标及偏移量
const client = {
offsetX: 0, // 偏移量
offsetY: 0,
endX: 0, // 坐标
endY: 0
};
// 判断是否为移动端
const mobileStatus = (/Mobile|Android|iPhone/i.test(navigator.userAgent));
console.log('mobileStatus 45', mobileStatus)
// 初始化后再监听鼠标的移动
const init = event => {
// 获取偏移量及坐标
// web端可以直接通过event中取到,而移动端则需要在event.changedTouches[0]中取到。
const { offsetX, offsetY, pageX, pageY } = mobileStatus ? event.changedTouches[0] : event
// 修改上次的偏移量及坐标
client.offsetX = offsetX
client.offsetY = offsetY
client.endX = pageX
client.endY = pageY
// 清除以上一次 beginPath 之后的所有路径,进行绘制
ctx.beginPath()
// 根据配置文件设置进行相应配置
ctx.lineWidth = config.lineWidth
ctx.strokeStyle = config.strokeStyle
ctx.lineCap = config.lineCap
ctx.lineJoin = config.lineJoin
// 设置画线起始点位
ctx.moveTo(client.endX, client.endY)
// 监听 鼠标移动或手势移动
window.addEventListener(mobileStatus ? "touchmove" : "mousemove", draw)
}
// draw方法,作为监听鼠标移动/触摸移动的回调方法
const draw = event => {
console.log('eventeventevent 68', event)
const { pageX, pageY } = mobileStatus ? event.changedTouches[0] : event;
// 修改最后一次绘制的坐标点
client.endX = pageX;
client.endY = pageY;
// 根据坐标点位移动添加线条
ctx.lineTo(pageX, pageY);
// 绘制
ctx.stroke();
};
// 结束绘制
const cloaseDraw = () => {
ctx.closePath()
// 移除鼠标移动或手势移动监听器
window.removeEventListener('mousemove', draw)
}
// 创建鼠标/手势按下监听器
window.addEventListener(mobileStatus ? 'touchstart' : 'mousedown', init)
// 创建鼠标/手势 弹起/离开 监听器
window.addEventListener(mobileStatus ? 'touchend' : 'mouseup', cloaseDraw);
const cancel = () => {
ctx.clearRect(0, 0, config.width, config.height);
}
const save = () => {
// 将canvas上的内容转成blob流
canvas.toBlob(blob => {
// 获取当前时间并转成字符串,用来当做文件名
const date = Date.now().toString();
// 创建一个a标签
const a = document.createElement('a');
// 设置a标签的下载文件名
a.download = `${date}.png`;
// 设置 a 标签的跳转路径为 文件流地址
a.href = URL.createObjectURL(blob);
// 手动触发 a 标签的点击事件
a.click();
// 移除 a 标签
a.remove();
})
}
</script>
</body>
</html>