因业务需要,我用canvas写了一个签名板

3,810 阅读1分钟

Y4B4FlsiyBkOxV3bHSNSdQXKHlxcOWPF.gif

需求做不完了

需求是做不完了,福利也被砍了,旅游也泡汤了,手上有2个需求,还没做完,PM就来新需求了。开发一个签名板:要求PC端/移动端都能用、扫码签名、实时同步、可以改变笔画粗细、笔画颜色、可以生成base64图片。

方案分析canvas

  1. 获取页面[canvas]元素,设置宽高(800*200)
  2. 通过**HTMLCanvasElement.getContext()**  方法返回[canvas] 的上下文ctx
  3. 初始化ctx基础属性
    • 线条颜色
    • 线条宽度
    • 线条末端形状
  4. 开始绘画
    • 监听鼠标事件
    • 绘制起点、终点
  5. 生成一个移动端链接二维码
  6. 在移动端签名时,通过WebSocket,实时传递数据给PC端。

涉及知识点

Canvas涉及特性:

  • 基本属性

    • getContext()
    • strokeStyle
    • fillStyle
    • lineCap
    • lineJoin
  • 路径绘制

    • beginPath()
    • lineTo()
    • moveTo()
  • 其他方法(生成base64,清除画板)

    • toDataURL()
    • clearRect()

涉及鼠标事件:

  • mousemove
  • mousedown
  • mouseup
  • mouseout

涉及移动端触摸事件:

  • touchstart
  • touchend
  • touchmove

代码

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>canvas-sign</title>
	<style>
		html,
		body {
			margin: 0;
		}

		.container {
			width: calc(100vw - 40px);
			height: calc(100vh - 40px);
			padding: 20px;
		}

		.canvas-body {
			width: calc(80vw);
			height: calc(80vh);
			margin: 20px auto;
		}

		#sign {
			background-color: #f3f5f7;
			border-radius: 4px;
			border: 1px dashed #0F6BFF;
		}

		#img {
			margin: 20px;
			border-radius: 4px;
			background-color: #f3f5f7;
			display: none;
		}

		#img.show {
			display: inline-block;
		}

		.btns {
			width: calc(80vw - 40px);
			text-align: right;
			margin: 0 auto;
		}

		@media screen and (orientation: portrait) {
			.qrcode {
				display: none;
			}
		}
	</style>
	<script type="text/javascript" src="https://static.runoob.com/assets/qrcode/qrcode.min.js"></script>
</head>

<body>
	<div class="container">
		<div id="canvas-body" class="canvas-body">
			<canvas id="sign" style="width: 100%; height: 100%;"></canvas>
			<div class="qrcode">
				扫码签名
				<div id="qrcode"></div>
			</div>
		</div>
		<div class="btns">
			<button id="reset">重置</button>
			<button id="showImg">生成图片</button>
		</div>
	</div>
	<div id="img">

	</div>
	<script>
		let canvasBody = document.getElementById('canvas-body');
		let canvas = document.getElementById('sign');
		let reset = document.getElementById('reset');
		let showImg = document.getElementById('showImg');
		let img = document.getElementById('img');
		canvas.width = canvasBody.clientWidth;
		canvas.height = canvasBody.clientHeight;
		let ctx = canvas.getContext('2d');
		ctx.lineWidth = 10;
		ctx.strokeStyle = '#333';
		ctx.lineCap = 'round';
		ctx.lineJoin = 'round';
		let isDrawing = false;
		let dataURL = '';
		let initX;
		let initY;
		// 事件监听
		canvas.addEventListener('mousedown', (e) => {
			isDrawing = true;
			initX = e.offsetX;
			initY = e.offsetY
		});
		canvas.addEventListener('mousemove', draw);
		canvas.addEventListener('mouseup', () => isDrawing = false);
		canvas.addEventListener('mouseout', () => isDrawing = false);

		// 绘制
		function draw(e) {
			if (!isDrawing) return
			ctx.beginPath();
			// 起点
			ctx.moveTo(initX, initY);
			// 终点
			ctx.lineTo(e.offsetX, e.offsetY);
			ctx.stroke();
			initX = e.offsetX;
			initY = e.offsetY
		}

		function clear() {
			ctx.clearRect(0, 0, canvas.width, canvas.height);
			if (dataURL) {
				dataURL = '';
				img.innerHTML = '';
				img.classList.remove('show');
			}
		}

		function canvasToBase64() {
			dataURL = canvas.toDataURL();
			// let oGrayImg = new Image();
			// oGrayImg.src = dataURL;
			// img.classList.add('show');
			// img.appendChild(oGrayImg)
			alert(`${dataURL}`)
		}

		reset.addEventListener('click', clear);
		showImg.addEventListener('click', canvasToBase64);
	</script>
	<script>
		let qrcode = new QRCode(document.getElementById('qrcode'), {
			width: 96,
			height: 96
		})

		qrcode.makeCode('https://canvas-sign.vercel.app/');

	</script>
</body>

</html>

码上掘金

code.juejin.cn/pen/7126443…

以上代码,未开发的点

  1. 移动端触摸事件,禁止移动端屏幕,修改笔画粗细、笔画颜色
  2. 实时同步WebSocket
  3. 实时同步笔画时,如何让笔画有实时同步一笔一画的效果?下图

Y4B4FlsiyBkOxV3bHSNSdQXKHlxcOWPF.gif