<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js">
<!--<![endif]-->

<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title></title>
	<meta name="description" content="">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
		integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
	<style>
		* {
			margin: 0;
			padding: 0;
		}

		html,
		body {
			width: 100%;
			height: 100%;
			text-align: center;
		}

		canvas {
			max-width: 100%;
			border: 2px dotted #ccc;
		}
	</style>
</head>

<body>
	<script>
		/**
		* @github       https://github.com/929467350/draw
		* @description  手写签字版
		*/
		(function (global, factory) {
			typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
				typeof define === 'function' && define.amd ? define(factory) :
					(global = global || self, global.Draw = factory());
		}(this, (function () {
			'use strict';

			var classCallCheck = function (instance, Constructor) {
				if (!(instance instanceof Constructor)) {
					throw new TypeError("Cannot call a class as a function");
				}
			};

			var createClass = function () {
				function defineProperties(target, props) {
					for (var i = 0; i < props.length; i++) {
						var descriptor = props[i];
						descriptor.enumerable = descriptor.enumerable || false;
						descriptor.configurable = true;
						if ("value" in descriptor) descriptor.writable = true;
						Object.defineProperty(target, descriptor.key, descriptor);
					}
				}

				return function (Constructor, protoProps, staticProps) {
					if (protoProps) defineProperties(Constructor.prototype, protoProps);
					if (staticProps) defineProperties(Constructor, staticProps);
					return Constructor;
				};
			}();


			var Draw = function () {
				function Draw() {
					var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
					classCallCheck(this, Draw);
					this.el = params.el || document.createElement('canvas');
					this.state = {
						undopath: [],
						index: -1,
						old: void 0,
						isStart: false,
						width: params.width || 400,
						height: params.height || 400,
						lineWidth: params.lineWidth || 1,
						isTouch: 'ontouchstart' in window,
						strokeStyle: params.strokeStyle || '#333333'
					};
					var _state = this.state,
						width = _state.width,
						height = _state.height,
						lineWidth = _state.lineWidth;

					this.el.width = width * 2;
					this.el.height = height * 2;
					document.body.appendChild(this.el);
					this.ctx = this.el.getContext('2d');
					this.ctx.scale(2, 2);
					this.ctx.lineWidth = lineWidth;
					this.ctx.lineJoin = 'round';
					this.ctx.lineCap = 'round';
					this.init();
				}

				createClass(Draw, [{
					key: 'onStart',
					value: function onStart() {
						++this.state.index;
						this.state.isStart = true;
					}
				}, {
					key: 'onMove',
					value: function onMove(e) {
						e.preventDefault();
						if (!this.state.isStart) return;
						var pos = this.pos(e);
						var index = this.state.index;

						this.ctx.strokeStyle = this.state.strokeStyle;
						if (this.state.old) {
							this.ctx.beginPath();
							this.ctx.moveTo(this.state.old.x, this.state.old.y);
							this.ctx.lineTo(pos.x, pos.y);
							this.ctx.stroke();
						}
						this.state.old = pos;
						if (this.state.undopath[index]) {
							this.state.undopath[index].push({
								x: this.state.old.x,
								y: this.state.old.y
							});
						} else {
							this.state.undopath[index] = [{
								x: this.state.old.x,
								y: this.state.old.y,
								strokeStyle: this.ctx.strokeStyle,
								lineWidth: this.ctx.lineWidth
							}];
						}
					}
				}, {
					key: 'onEnd',
					value: function onEnd() {
						this.state.old = void 0;
						this.state.isStart = false;
					}
				}, {
					key: 'pos',
					value: function pos(e) {
						var x = 0,
							y = 0;
						if (e.touches) {
							x = e.touches[0].pageX;
							y = e.touches[0].pageY;
						} else {
							x = e.offsetX / 2;
							y = e.offsetY / 2;
						}
						return {
							x: x,
							y: y
						};
					}
				}, {
					key: 'ouput',
					value: function ouput() {
						// 输出图片
						return this.el.toDataURL();
					}
				}, {
					key: 'init',
					value: function init() {
						// 绑定事件
						var isTouch = this.state.isTouch;

						this.el.addEventListener(isTouch ? 'touchstart' : 'mousedown', this.onStart.bind(this), false);
						this.el.addEventListener(isTouch ? 'touchmove' : 'mousemove', this.onMove.bind(this), false);
						this.el.addEventListener(isTouch ? 'touchend' : 'mouseup', this.onEnd.bind(this), false);
						this.el.addEventListener(isTouch ? 'touchcancel' : 'mouseout', this.onEnd.bind(this), false);
					}
				}, {
					key: 'destroyed',
					value: function destroyed() {
						if (this.el) {
							var isTouch = this.state.isTouch;
							this.el.removeEventListener(isTouch ? 'touchstart' : 'mousedown', this.onStart.bind(this));
							this.el.removeEventListener(isTouch ? 'touchmove' : 'mousemove', this.onMove.bind(this));
							this.el.removeEventListener(isTouch ? 'touchend' : 'mouseup', this.onEnd.bind(this));
							this.el.removeEventListener(isTouch ? 'touchcancel' : 'mouseout', this.onEnd.bind(this));
						}
					}
				}, {
					key: 'clear',
					value: function clear() {
						// 清除画布
						this.state.index = -1;
						this.state.undopath = [];
						this.ctx.clearRect(0, 0, this.el.width, this.el.height);
					}
				}, {
					key: 'undo',
					value: function undo() {
						// 撤销
						this.state.index >= 0 && --this.state.index;
						this.state.undopath.pop();
						var undopath = this.state.undopath;
						this.ctx.clearRect(0, 0, this.el.width, this.el.height);
						if (undopath.length > 0) {
							this.ctx.beginPath();
							for (var z = 0; z < undopath.length; ++z) {
								this.ctx.moveTo(undopath[z][0].x, undopath[z][0].y);
								this.ctx.lineWidth = undopath[z][0].lineWidth;
								this.ctx.strokeStyle = undopath[z][0].strokeStyle;
								for (var i = 0; i < undopath[z].length; ++i) {
									this.ctx.lineTo(undopath[z][i].x, undopath[z][i].y);
								}
							}
							this.ctx.stroke();
							this.ctx.closePath();
						} else {
							this.state.undopath = [];
						}
					}
				}]);
				return Draw;
			}();

			return Draw;

		})));
	</script>
	<!--[if lt IE 7]>
            <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->
	<script>

		//初始化
		var sign = new Draw({
			// canvas:document.getElementById('canvas'),
			lineWidth: 1, // 线条宽度
			width: 400, // canvas 宽
			height: 400, //canvas 高
			strokeStyle: '#333333' // 线条颜色
		});
		// function downQrcode(url) {
		// 	let arr = url.split(","),
		// 		mime = arr[0].match(/:(.*?);/)[1],
		// 		bstr = atob(arr[1]),
		// 		n = bstr.length,
		// 		u8arr = new Uint8Array(n);
		// 	while (n--) {
		// 		u8arr[n] = bstr.charCodeAt(n);
		// 	}
		// 	var blob = new Blob([u8arr], { type: mime });
		// 	      const a = document.createElement("a");
		// 	      const event = new MouseEvent("click");
		// 	      a.download = "二维码";
		// 	      a.href = URL.createObjectURL(blob);
		// 	      a.target = "_blank";
		// 	      a.dispatchEvent(event);
		// }
		window.onload = function () {
			// 点击输出图片
			document.querySelector('.ouput').onclick = function () {
				var img = new Image();
				img.style.width = '200px';
				img.src = sign.ouput();
				// downQrcode(sign.ouput())
				img.onload = function () {
					document.body.appendChild(img);
				}
				document.querySelector('img') && document.querySelector('img').remove();
			}
			// 点击清除
			document.querySelector('.clear').onclick = function () {
				sign.clear();
			}
			// 点击撤销
			document.querySelector('.undo').onclick = function () {
				sign.undo();
			}
		}
	</script>
	<div class="buttons">
		<button type="button" class="btn btn-primary ouput">生成图片</button>
		<button type="button" class="btn btn-light undo">撤销</button>
		<button type="button" class="btn btn-light clear">清除画布</button>
	</div>
</body>

</html>
Copy the code