cy-plugin-signpad 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # cy-plugin-signpad
2
+
3
+ 手写签字板插件。宿主提供 `<canvas>`,插件负责笔迹采集、绘制与导出(支持 PC / 移动端)。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install cy-plugin-signpad
9
+ ```
10
+
11
+ ## 使用
12
+
13
+ ```html
14
+ <canvas id="sign-canvas" width="600" height="200"></canvas>
15
+ ```
16
+
17
+ ```ts
18
+ import { CySignPad } from 'cy-plugin-signpad';
19
+
20
+ const pad = new CySignPad({
21
+ canvasId: 'sign-canvas',
22
+ penColor: '#000000',
23
+ penWidth: 2,
24
+ backgroundColor: 'transparent',
25
+ debug: false
26
+ });
27
+
28
+ // 是否空签
29
+ pad.isEmpty();
30
+
31
+ // 清空
32
+ pad.clear();
33
+
34
+ // 保存(原画布尺寸;空签返回 null)
35
+ const dataUrl = pad.save(); // image/png
36
+ const jpegUrl = pad.save('image/jpeg', 0.92);
37
+
38
+ // 销毁(解绑事件)
39
+ pad.destroy();
40
+ ```
41
+
42
+ ## API
43
+
44
+ ### `new CySignPad(options)`
45
+
46
+ | 字段 | 类型 | 默认值 | 说明 |
47
+ | ----------------- | --------- | ------------- | ------------------------------------- |
48
+ | `canvasId` | `string` | - | 必填,canvas 元素 id |
49
+ | `penColor` | `string` | `#000000` | 笔触颜色 |
50
+ | `penWidth` | `number` | `2` | 笔触宽度(CSS 像素) |
51
+ | `backgroundColor` | `string` | `transparent` | 画布背景;jpeg 导出时若为透明会铺白底 |
52
+ | `debug` | `boolean` | `false` | 是否开启调试日志 |
53
+
54
+ ### 实例方法
55
+
56
+ | 方法 | 说明 |
57
+ | ----------------------- | ----------------------------------------- |
58
+ | `isEmpty()` | 是否尚未书写 |
59
+ | `clear()` | 清空画布 |
60
+ | `save(type?, quality?)` | 按原画布尺寸导出 DataURL;空签返回 `null` |
61
+ | `destroy()` | 解绑事件并释放资源 |
62
+
63
+ ## 行为说明
64
+
65
+ - 优先使用 Pointer Events,不支持时降级为 mouse + touch
66
+ - 高清屏按 `devicePixelRatio` 适配,避免模糊
67
+ - 画布 / 窗口尺寸变化后会**清空并重置**,需重新签字
68
+ - 插件不提供清空 / 保存按钮,由业务层调用 API
69
+
70
+ ## 本地预览
71
+
72
+ ```bash
73
+ npm run build
74
+ npm run preview
75
+ ```
76
+
77
+ 浏览器打开提示的地址,进入 `/examples/`。
78
+
79
+ ## 开发
80
+
81
+ ```bash
82
+ nvm use # 使用 .nvmrc 中的 Node 版本
83
+ npm run dev
84
+ npm test
85
+ npm run build
86
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(e,t,n){if(n||2===arguments.length)for(var i,r=0,o=t.length;r<o;r++)!i&&r in t||(i||(i=Array.prototype.slice.call(t,0,r)),i[r]=t[r]);return e.concat(i||Array.prototype.slice.call(t))}"function"==typeof SuppressedError&&SuppressedError;var n=function(){function n(e){var t;void 0===e&&(e={}),Object.defineProperty(this,"debug",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"prevTitle",{enumerable:!0,configurable:!0,writable:!0,value:"cy-plugin-signpad"}),this.debug=null!==(t=e.debug)&&void 0!==t&&t,e.title&&(this.prevTitle=e.title)}return Object.defineProperty(n.prototype,"setDebug",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.debug=e}}),Object.defineProperty(n.prototype,"log",{enumerable:!1,configurable:!0,writable:!0,value:function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.print.apply(this,t(["log"],e,!1))}}),Object.defineProperty(n.prototype,"warn",{enumerable:!1,configurable:!0,writable:!0,value:function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.print.apply(this,t(["warn"],e,!1))}}),Object.defineProperty(n.prototype,"error",{enumerable:!1,configurable:!0,writable:!0,value:function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.print.apply(this,t(["error"],e,!1))}}),Object.defineProperty(n.prototype,"print",{enumerable:!1,configurable:!0,writable:!0,value:function(e){for(var n=this,i=[],r=1;r<arguments.length;r++)i[r-1]=arguments[r];if(this.debug&&0!==i.length){var o=this.getPrefix(e),a=this.generateTime(),s=function(e){if(n.isPrimitive(e)||n.hasFunction(e))return e;try{return JSON.stringify(e,null,2)}catch(t){return e}},l=function(n,i,r){void 0===r&&(r=[]),0!==r.length||"string"!=typeof i||!i.startsWith("{")&&!i.startsWith("[")?console[e].apply(console,t([n,i],r,!1)):console[e]("".concat(n,"\n").concat(i))};if(1!==i.length){var c=i[0],u=i[1],h=i.slice(2);l("".concat(o,"-【").concat(a,"】-【").concat(c,"】"),s(u),h)}else l("".concat(o,"-【").concat(a,"】-"),s(i[0]))}}}),Object.defineProperty(n.prototype,"getPrefix",{enumerable:!1,configurable:!0,writable:!0,value:function(e){return"".concat({log:"🐛",warn:"⚠️",error:"❌"}[e],"【").concat(this.prevTitle,"】")}}),Object.defineProperty(n.prototype,"isPrimitive",{enumerable:!1,configurable:!0,writable:!0,value:function(e){return null==e||"string"==typeof e||"number"==typeof e||"boolean"==typeof e}}),Object.defineProperty(n.prototype,"hasFunction",{enumerable:!1,configurable:!0,writable:!0,value:function(t,n){if(void 0===n&&(n=new WeakSet),null===t||"object"!==e(t))return!1;if(n.has(t))return!1;for(var i in n.add(t),t)try{var r=t[i];if("function"==typeof r)return!0;if("object"===e(r)&&this.hasFunction(r,n))return!0}catch(e){}return!1}}),Object.defineProperty(n.prototype,"generateTime",{enumerable:!1,configurable:!0,writable:!0,value:function(){var e=new Date(Date.now()),t="HH:mm:ss",n={"M+":e.getMonth()+1,"D+":e.getDate(),"H+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};return t=t.replace(/(Y+)/g,function(t){return e.getFullYear().toString().slice(-t.length)}),Object.keys(n).forEach(function(e){t=t.replace(new RegExp("(".concat(e,")"),"g"),function(t){var i=n[e].toString();return 1===t.length?i:i.padStart(t.length,"0")})}),t}}),n}(),i=function(){function e(e){var t,i,r,o,a=this;if(Object.defineProperty(this,"canvas",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ctx",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"penColor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"penWidth",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"backgroundColor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"drawing",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"empty",{enumerable:!0,configurable:!0,writable:!0,value:!0}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"lastPoint",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"cssWidth",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"cssHeight",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"supportsPointer",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"resizeObserver",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"resizeRaf",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"onPointerDown",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onPointerMove",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onPointerUp",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onMouseDown",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onMouseMove",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onMouseUp",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTouchStart",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTouchMove",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTouchEnd",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onWindowResize",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.logger=new n({debug:null!==(t=null==e?void 0:e.debug)&&void 0!==t&&t}),!e||!e.canvasId)throw this.logger.error("初始化","options.canvasId is required"),new Error("[CySignPad] options.canvasId is required");var s=document.getElementById(e.canvasId);if(!s)throw this.logger.error("初始化",'canvas "#'.concat(e.canvasId,'" not found')),new Error('[CySignPad] canvas "#'.concat(e.canvasId,'" not found'));if(!(s instanceof HTMLCanvasElement))throw this.logger.error("初始化",'"#'.concat(e.canvasId,'" is not a canvas element')),new Error('[CySignPad] "#'.concat(e.canvasId,'" is not a canvas element'));var l=s.getContext("2d");if(!l)throw this.logger.error("初始化","failed to get 2d context"),new Error("[CySignPad] failed to get 2d context");this.canvas=s,this.ctx=l,this.penColor=null!==(i=e.penColor)&&void 0!==i?i:"#000000",this.penWidth=null!==(r=e.penWidth)&&void 0!==r?r:2,this.backgroundColor=null!==(o=e.backgroundColor)&&void 0!==o?o:"transparent",this.supportsPointer="undefined"!=typeof window&&"PointerEvent"in window,this.onPointerDown=function(e){a.handlePointerDown(e)},this.onPointerMove=function(e){a.handlePointerMove(e)},this.onPointerUp=function(e){a.handlePointerUp(e)},this.onMouseDown=function(e){a.handleMouseDown(e)},this.onMouseMove=function(e){a.handleMouseMove(e)},this.onMouseUp=function(e){a.handleMouseUp(e)},this.onTouchStart=function(e){a.handleTouchStart(e)},this.onTouchMove=function(e){a.handleTouchMove(e)},this.onTouchEnd=function(e){a.handleTouchEnd(e)},this.onWindowResize=function(){a.scheduleResizeReset()},this.canvas.style.touchAction="none",this.canvas.style.userSelect="none",this.setupCanvas(!0),this.bindEvents(),this.observeResize(),this.logger.log("初始化完成",{canvasId:e.canvasId,penColor:this.penColor,penWidth:this.penWidth,backgroundColor:this.backgroundColor,supportsPointer:this.supportsPointer,cssSize:{width:this.cssWidth,height:this.cssHeight},pixelSize:{width:this.canvas.width,height:this.canvas.height}})}return Object.defineProperty(e.prototype,"isEmpty",{enumerable:!1,configurable:!0,writable:!0,value:function(){return this.ensureAlive(),this.empty}}),Object.defineProperty(e.prototype,"clear",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.ensureAlive(),this.fillBackground(),this.empty=!0,this.drawing=!1,this.lastPoint=null,this.logger.log("清空","画布已清空")}}),Object.defineProperty(e.prototype,"save",{enumerable:!1,configurable:!0,writable:!0,value:function(e,t){if(void 0===e&&(e="image/png"),this.ensureAlive(),this.empty)return this.logger.warn("保存","空签,返回 null"),null;if("image/jpeg"===e&&"transparent"===this.backgroundColor){var n=document.createElement("canvas");n.width=this.canvas.width,n.height=this.canvas.height;var i=n.getContext("2d");if(!i)throw this.logger.error("保存","failed to create export canvas context"),new Error("[CySignPad] failed to create export canvas context");i.fillStyle="#ffffff",i.fillRect(0,0,n.width,n.height),i.drawImage(this.canvas,0,0);var r=n.toDataURL(e,null!=t?t:.92);return this.logger.log("保存",{type:e,quality:null!=t?t:.92,length:r.length}),r}var o="image/jpeg"===e?this.canvas.toDataURL(e,null!=t?t:.92):this.canvas.toDataURL(e);return this.logger.log("保存",{type:e,quality:"image/jpeg"===e?null!=t?t:.92:void 0,length:o.length}),o}}),Object.defineProperty(e.prototype,"destroy",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.destroyed?this.logger.warn("销毁","实例已销毁,忽略重复调用"):(this.destroyed=!0,this.drawing=!1,this.lastPoint=null,this.unbindEvents(),this.disconnectResize(),this.resizeRaf&&(cancelAnimationFrame(this.resizeRaf),this.resizeRaf=0),this.logger.log("销毁","实例已销毁"))}}),Object.defineProperty(e.prototype,"setupCanvas",{enumerable:!1,configurable:!0,writable:!0,value:function(e){var t=this.canvas.getBoundingClientRect(),n=Math.max(1,t.width||this.canvas.clientWidth||Number(this.canvas.getAttribute("width"))||300),i=Math.max(1,t.height||this.canvas.clientHeight||Number(this.canvas.getAttribute("height"))||150),r=window.devicePixelRatio||1;this.cssWidth=n,this.cssHeight=i,this.canvas.width=Math.max(1,Math.floor(n*r)),this.canvas.height=Math.max(1,Math.floor(i*r)),this.canvas.style.width="".concat(n,"px"),this.canvas.style.height="".concat(i,"px"),this.ctx.setTransform(r,0,0,r,0,0),this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.strokeStyle=this.penColor,this.ctx.lineWidth=this.penWidth,e&&this.fillBackground()}}),Object.defineProperty(e.prototype,"fillBackground",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.ctx.save(),this.ctx.setTransform(1,0,0,1,0,0),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.restore(),"transparent"!==this.backgroundColor&&(this.ctx.save(),this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.cssWidth,this.cssHeight),this.ctx.restore()),this.ctx.strokeStyle=this.penColor,this.ctx.lineWidth=this.penWidth,this.ctx.lineCap="round",this.ctx.lineJoin="round"}}),Object.defineProperty(e.prototype,"bindEvents",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.supportsPointer)return this.canvas.addEventListener("pointerdown",this.onPointerDown),this.canvas.addEventListener("pointermove",this.onPointerMove),this.canvas.addEventListener("pointerup",this.onPointerUp),this.canvas.addEventListener("pointercancel",this.onPointerUp),void this.logger.log("事件绑定","Pointer Events");this.canvas.addEventListener("mousedown",this.onMouseDown),window.addEventListener("mousemove",this.onMouseMove),window.addEventListener("mouseup",this.onMouseUp),this.canvas.addEventListener("touchstart",this.onTouchStart,{passive:!1}),this.canvas.addEventListener("touchmove",this.onTouchMove,{passive:!1}),this.canvas.addEventListener("touchend",this.onTouchEnd),this.canvas.addEventListener("touchcancel",this.onTouchEnd),this.logger.log("事件绑定","mouse + touch fallback")}}),Object.defineProperty(e.prototype,"unbindEvents",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.supportsPointer)return this.canvas.removeEventListener("pointerdown",this.onPointerDown),this.canvas.removeEventListener("pointermove",this.onPointerMove),this.canvas.removeEventListener("pointerup",this.onPointerUp),void this.canvas.removeEventListener("pointercancel",this.onPointerUp);this.canvas.removeEventListener("mousedown",this.onMouseDown),window.removeEventListener("mousemove",this.onMouseMove),window.removeEventListener("mouseup",this.onMouseUp),this.canvas.removeEventListener("touchstart",this.onTouchStart),this.canvas.removeEventListener("touchmove",this.onTouchMove),this.canvas.removeEventListener("touchend",this.onTouchEnd),this.canvas.removeEventListener("touchcancel",this.onTouchEnd)}}),Object.defineProperty(e.prototype,"observeResize",{enumerable:!1,configurable:!0,writable:!0,value:function(){var e=this;if("undefined"!=typeof ResizeObserver)return this.resizeObserver=new ResizeObserver(function(){e.scheduleResizeReset()}),void this.resizeObserver.observe(this.canvas);window.addEventListener("resize",this.onWindowResize)}}),Object.defineProperty(e.prototype,"disconnectResize",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.resizeObserver)return this.resizeObserver.disconnect(),void(this.resizeObserver=null);window.removeEventListener("resize",this.onWindowResize)}}),Object.defineProperty(e.prototype,"scheduleResizeReset",{enumerable:!1,configurable:!0,writable:!0,value:function(){var e=this;this.destroyed||(this.resizeRaf&&cancelAnimationFrame(this.resizeRaf),this.resizeRaf=requestAnimationFrame(function(){if(e.resizeRaf=0,!e.destroyed){var t=e.canvas.getBoundingClientRect(),n=Math.max(1,t.width||e.canvas.clientWidth||e.cssWidth),i=Math.max(1,t.height||e.canvas.clientHeight||e.cssHeight);Math.abs(n-e.cssWidth)<.5&&Math.abs(i-e.cssHeight)<.5||(e.logger.log("尺寸变化",{from:{width:e.cssWidth,height:e.cssHeight},to:{width:n,height:i}}),e.setupCanvas(!0),e.empty=!0,e.drawing=!1,e.lastPoint=null,e.logger.log("尺寸变化","已清空并重置,需重新签字"))}}))}}),Object.defineProperty(e.prototype,"handlePointerDown",{enumerable:!1,configurable:!0,writable:!0,value:function(e){var t,n;void 0!==e.button&&0!==e.button||(e.preventDefault(),null===(n=(t=this.canvas).setPointerCapture)||void 0===n||n.call(t,e.pointerId),this.beginStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handlePointerMove",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.continueStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handlePointerUp",{enumerable:!1,configurable:!0,writable:!0,value:function(e){var t,n;if(this.drawing){e.preventDefault();try{null===(n=(t=this.canvas).releasePointerCapture)||void 0===n||n.call(t,e.pointerId)}catch(e){}this.endStroke()}}}),Object.defineProperty(e.prototype,"handleMouseDown",{enumerable:!1,configurable:!0,writable:!0,value:function(e){0===e.button&&(e.preventDefault(),this.beginStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handleMouseMove",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.continueStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handleMouseUp",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.endStroke())}}),Object.defineProperty(e.prototype,"handleTouchStart",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(1===e.touches.length){e.preventDefault();var t=e.touches[0];this.beginStroke(this.getPointFromClient(t.clientX,t.clientY))}}}),Object.defineProperty(e.prototype,"handleTouchMove",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(this.drawing&&1===e.touches.length){e.preventDefault();var t=e.touches[0];this.continueStroke(this.getPointFromClient(t.clientX,t.clientY))}}}),Object.defineProperty(e.prototype,"handleTouchEnd",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.endStroke())}}),Object.defineProperty(e.prototype,"beginStroke",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing=!0,this.lastPoint=e,this.empty=!1,this.ctx.beginPath(),this.ctx.moveTo(e.x,e.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.logger.log("落笔",e)}}),Object.defineProperty(e.prototype,"continueStroke",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.lastPoint?(this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.lastPoint=e):this.lastPoint=e}}),Object.defineProperty(e.prototype,"endStroke",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.drawing=!1,this.lastPoint=null,this.logger.log("抬笔","stroke end")}}),Object.defineProperty(e.prototype,"getPointFromClient",{enumerable:!1,configurable:!0,writable:!0,value:function(e,t){var n=this.canvas.getBoundingClientRect(),i=this.cssWidth/(n.width||this.cssWidth),r=this.cssHeight/(n.height||this.cssHeight);return{x:(e-n.left)*i,y:(t-n.top)*r}}}),Object.defineProperty(e.prototype,"ensureAlive",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.destroyed)throw this.logger.error("调用校验","instance has been destroyed"),new Error("[CySignPad] instance has been destroyed")}}),e}();exports.CySignPad=i;
@@ -0,0 +1,185 @@
1
+ /**
2
+ * 签字板保存图片 MIME 类型
3
+ */
4
+ type TSaveMimeType = 'image/png' | 'image/jpeg';
5
+ /**
6
+ * 签字板初始化配置
7
+ *
8
+ * @property canvasId - canvas 元素 id(必填)
9
+ * @property penColor - 笔触颜色,默认 `#000000`
10
+ * @property penWidth - 笔触宽度(CSS 像素),默认 `2`
11
+ * @property backgroundColor - 画布背景色,默认 `transparent`;jpeg 导出且为透明时自动铺白底
12
+ * @property debug - 是否开启调试日志,默认 `false`
13
+ */
14
+ interface ISignPadOptions {
15
+ /** canvas 元素 id(必填) */
16
+ canvasId: string;
17
+ /** 笔触颜色,默认 `#000000` */
18
+ penColor?: string;
19
+ /** 笔触宽度(CSS 像素),默认 `2` */
20
+ penWidth?: number;
21
+ /**
22
+ * 画布背景色
23
+ * - 默认 `transparent`(png 可透明导出)
24
+ * - jpeg 导出时若仍为透明,将自动铺白底
25
+ */
26
+ backgroundColor?: string;
27
+ /** 是否开启调试日志,默认 `false` */
28
+ debug?: boolean;
29
+ }
30
+
31
+ /**
32
+ * 手写签字板
33
+ *
34
+ * @description
35
+ * 绑定宿主提供的 canvas,支持 PC / 移动端书写;对外提供清空、保存、销毁等能力。
36
+ * 画布尺寸变化时会清空并重置(需重新签字)。
37
+ *
38
+ * @param options - 初始化参数
39
+ * - `canvasId`: canvas 元素 id(必填)
40
+ * - `penColor`: 笔触颜色,默认 `#000000`
41
+ * - `penWidth`: 笔触宽度(CSS 像素),默认 `2`
42
+ * - `backgroundColor`: 画布背景色,默认 `transparent`;jpeg 导出且为透明时自动铺白底
43
+ * - `debug`: 是否开启调试日志,默认 `false`
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const pad = new CySignPad({
48
+ * canvasId: 'sign-canvas',
49
+ * penColor: '#000000',
50
+ * penWidth: 2,
51
+ * backgroundColor: 'transparent',
52
+ * debug: true
53
+ * });
54
+ * pad.clear();
55
+ * const dataUrl = pad.save(); // 空签返回 null
56
+ * pad.destroy();
57
+ * ```
58
+ */
59
+ declare class CySignPad {
60
+ private canvas;
61
+ private ctx;
62
+ private penColor;
63
+ private penWidth;
64
+ private backgroundColor;
65
+ private logger;
66
+ private drawing;
67
+ private empty;
68
+ private destroyed;
69
+ private lastPoint;
70
+ private cssWidth;
71
+ private cssHeight;
72
+ private readonly supportsPointer;
73
+ private resizeObserver;
74
+ private resizeRaf;
75
+ private readonly onPointerDown;
76
+ private readonly onPointerMove;
77
+ private readonly onPointerUp;
78
+ private readonly onMouseDown;
79
+ private readonly onMouseMove;
80
+ private readonly onMouseUp;
81
+ private readonly onTouchStart;
82
+ private readonly onTouchMove;
83
+ private readonly onTouchEnd;
84
+ private readonly onWindowResize;
85
+ /**
86
+ * @param options - 初始化参数
87
+ * - `canvasId`: canvas 元素 id(必填)
88
+ * - `penColor`: 笔触颜色,默认 `#000000`
89
+ * - `penWidth`: 笔触宽度(CSS 像素),默认 `2`
90
+ * - `backgroundColor`: 画布背景色,默认 `transparent`;jpeg 导出且为透明时自动铺白底
91
+ * - `debug`: 是否开启调试日志,默认 `false`
92
+ */
93
+ constructor(options: ISignPadOptions);
94
+ /**
95
+ * 是否尚未书写
96
+ *
97
+ * @returns 空签为 true
98
+ */
99
+ isEmpty(): boolean;
100
+ /**
101
+ * 清空画布并重置为空签状态
102
+ */
103
+ clear(): void;
104
+ /**
105
+ * 保存签字图(原画布尺寸导出)
106
+ *
107
+ * @param type - 图片类型,默认 `image/png`
108
+ * @param quality - jpeg 质量 0~1,仅 jpeg 生效
109
+ * @returns DataURL;空签返回 null
110
+ */
111
+ save(type?: TSaveMimeType, quality?: number): string | null;
112
+ /**
113
+ * 销毁实例:解绑事件并释放引用
114
+ */
115
+ destroy(): void;
116
+ /**
117
+ * 配置画布像素尺寸与绘制样式
118
+ *
119
+ * @param fillBg - 是否填充背景
120
+ */
121
+ private setupCanvas;
122
+ /**
123
+ * 按配置填充背景色
124
+ */
125
+ private fillBackground;
126
+ /**
127
+ * 绑定指针 / 鼠标 / 触摸事件
128
+ */
129
+ private bindEvents;
130
+ /**
131
+ * 解绑事件
132
+ */
133
+ private unbindEvents;
134
+ /**
135
+ * 监听尺寸变化:变化后清空重签
136
+ */
137
+ private observeResize;
138
+ /**
139
+ * 取消尺寸监听
140
+ */
141
+ private disconnectResize;
142
+ /**
143
+ * 合并同一帧内多次 resize,重置画布并清空
144
+ */
145
+ private scheduleResizeReset;
146
+ private handlePointerDown;
147
+ private handlePointerMove;
148
+ private handlePointerUp;
149
+ private handleMouseDown;
150
+ private handleMouseMove;
151
+ private handleMouseUp;
152
+ private handleTouchStart;
153
+ private handleTouchMove;
154
+ private handleTouchEnd;
155
+ /**
156
+ * 开始一笔
157
+ *
158
+ * @param point - 起点(CSS 像素)
159
+ */
160
+ private beginStroke;
161
+ /**
162
+ * 继续一笔
163
+ *
164
+ * @param point - 当前点
165
+ */
166
+ private continueStroke;
167
+ /**
168
+ * 结束一笔
169
+ */
170
+ private endStroke;
171
+ /**
172
+ * client 坐标转 canvas CSS 坐标
173
+ *
174
+ * @param clientX - 视口 X
175
+ * @param clientY - 视口 Y
176
+ */
177
+ private getPointFromClient;
178
+ /**
179
+ * 销毁后禁止继续调用
180
+ */
181
+ private ensureAlive;
182
+ }
183
+
184
+ export { CySignPad };
185
+ export type { ISignPadOptions, TSaveMimeType };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(e,t,n){if(n||2===arguments.length)for(var i,r=0,o=t.length;r<o;r++)!i&&r in t||(i||(i=Array.prototype.slice.call(t,0,r)),i[r]=t[r]);return e.concat(i||Array.prototype.slice.call(t))}"function"==typeof SuppressedError&&SuppressedError;var n=function(){function n(e){var t;void 0===e&&(e={}),Object.defineProperty(this,"debug",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"prevTitle",{enumerable:!0,configurable:!0,writable:!0,value:"cy-plugin-signpad"}),this.debug=null!==(t=e.debug)&&void 0!==t&&t,e.title&&(this.prevTitle=e.title)}return Object.defineProperty(n.prototype,"setDebug",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.debug=e}}),Object.defineProperty(n.prototype,"log",{enumerable:!1,configurable:!0,writable:!0,value:function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.print.apply(this,t(["log"],e,!1))}}),Object.defineProperty(n.prototype,"warn",{enumerable:!1,configurable:!0,writable:!0,value:function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.print.apply(this,t(["warn"],e,!1))}}),Object.defineProperty(n.prototype,"error",{enumerable:!1,configurable:!0,writable:!0,value:function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];this.print.apply(this,t(["error"],e,!1))}}),Object.defineProperty(n.prototype,"print",{enumerable:!1,configurable:!0,writable:!0,value:function(e){for(var n=this,i=[],r=1;r<arguments.length;r++)i[r-1]=arguments[r];if(this.debug&&0!==i.length){var o=this.getPrefix(e),a=this.generateTime(),s=function(e){if(n.isPrimitive(e)||n.hasFunction(e))return e;try{return JSON.stringify(e,null,2)}catch(t){return e}},l=function(n,i,r){void 0===r&&(r=[]),0!==r.length||"string"!=typeof i||!i.startsWith("{")&&!i.startsWith("[")?console[e].apply(console,t([n,i],r,!1)):console[e]("".concat(n,"\n").concat(i))};if(1!==i.length){var c=i[0],u=i[1],h=i.slice(2);l("".concat(o,"-【").concat(a,"】-【").concat(c,"】"),s(u),h)}else l("".concat(o,"-【").concat(a,"】-"),s(i[0]))}}}),Object.defineProperty(n.prototype,"getPrefix",{enumerable:!1,configurable:!0,writable:!0,value:function(e){return"".concat({log:"🐛",warn:"⚠️",error:"❌"}[e],"【").concat(this.prevTitle,"】")}}),Object.defineProperty(n.prototype,"isPrimitive",{enumerable:!1,configurable:!0,writable:!0,value:function(e){return null==e||"string"==typeof e||"number"==typeof e||"boolean"==typeof e}}),Object.defineProperty(n.prototype,"hasFunction",{enumerable:!1,configurable:!0,writable:!0,value:function(t,n){if(void 0===n&&(n=new WeakSet),null===t||"object"!==e(t))return!1;if(n.has(t))return!1;for(var i in n.add(t),t)try{var r=t[i];if("function"==typeof r)return!0;if("object"===e(r)&&this.hasFunction(r,n))return!0}catch(e){}return!1}}),Object.defineProperty(n.prototype,"generateTime",{enumerable:!1,configurable:!0,writable:!0,value:function(){var e=new Date(Date.now()),t="HH:mm:ss",n={"M+":e.getMonth()+1,"D+":e.getDate(),"H+":e.getHours(),"m+":e.getMinutes(),"s+":e.getSeconds(),"q+":Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()};return t=t.replace(/(Y+)/g,function(t){return e.getFullYear().toString().slice(-t.length)}),Object.keys(n).forEach(function(e){t=t.replace(new RegExp("(".concat(e,")"),"g"),function(t){var i=n[e].toString();return 1===t.length?i:i.padStart(t.length,"0")})}),t}}),n}(),i=function(){function e(e){var t,i,r,o,a=this;if(Object.defineProperty(this,"canvas",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"ctx",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"penColor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"penWidth",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"backgroundColor",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"logger",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"drawing",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"empty",{enumerable:!0,configurable:!0,writable:!0,value:!0}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"lastPoint",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"cssWidth",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"cssHeight",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"supportsPointer",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"resizeObserver",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"resizeRaf",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"onPointerDown",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onPointerMove",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onPointerUp",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onMouseDown",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onMouseMove",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onMouseUp",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTouchStart",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTouchMove",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onTouchEnd",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"onWindowResize",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.logger=new n({debug:null!==(t=null==e?void 0:e.debug)&&void 0!==t&&t}),!e||!e.canvasId)throw this.logger.error("初始化","options.canvasId is required"),new Error("[CySignPad] options.canvasId is required");var s=document.getElementById(e.canvasId);if(!s)throw this.logger.error("初始化",'canvas "#'.concat(e.canvasId,'" not found')),new Error('[CySignPad] canvas "#'.concat(e.canvasId,'" not found'));if(!(s instanceof HTMLCanvasElement))throw this.logger.error("初始化",'"#'.concat(e.canvasId,'" is not a canvas element')),new Error('[CySignPad] "#'.concat(e.canvasId,'" is not a canvas element'));var l=s.getContext("2d");if(!l)throw this.logger.error("初始化","failed to get 2d context"),new Error("[CySignPad] failed to get 2d context");this.canvas=s,this.ctx=l,this.penColor=null!==(i=e.penColor)&&void 0!==i?i:"#000000",this.penWidth=null!==(r=e.penWidth)&&void 0!==r?r:2,this.backgroundColor=null!==(o=e.backgroundColor)&&void 0!==o?o:"transparent",this.supportsPointer="undefined"!=typeof window&&"PointerEvent"in window,this.onPointerDown=function(e){a.handlePointerDown(e)},this.onPointerMove=function(e){a.handlePointerMove(e)},this.onPointerUp=function(e){a.handlePointerUp(e)},this.onMouseDown=function(e){a.handleMouseDown(e)},this.onMouseMove=function(e){a.handleMouseMove(e)},this.onMouseUp=function(e){a.handleMouseUp(e)},this.onTouchStart=function(e){a.handleTouchStart(e)},this.onTouchMove=function(e){a.handleTouchMove(e)},this.onTouchEnd=function(e){a.handleTouchEnd(e)},this.onWindowResize=function(){a.scheduleResizeReset()},this.canvas.style.touchAction="none",this.canvas.style.userSelect="none",this.setupCanvas(!0),this.bindEvents(),this.observeResize(),this.logger.log("初始化完成",{canvasId:e.canvasId,penColor:this.penColor,penWidth:this.penWidth,backgroundColor:this.backgroundColor,supportsPointer:this.supportsPointer,cssSize:{width:this.cssWidth,height:this.cssHeight},pixelSize:{width:this.canvas.width,height:this.canvas.height}})}return Object.defineProperty(e.prototype,"isEmpty",{enumerable:!1,configurable:!0,writable:!0,value:function(){return this.ensureAlive(),this.empty}}),Object.defineProperty(e.prototype,"clear",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.ensureAlive(),this.fillBackground(),this.empty=!0,this.drawing=!1,this.lastPoint=null,this.logger.log("清空","画布已清空")}}),Object.defineProperty(e.prototype,"save",{enumerable:!1,configurable:!0,writable:!0,value:function(e,t){if(void 0===e&&(e="image/png"),this.ensureAlive(),this.empty)return this.logger.warn("保存","空签,返回 null"),null;if("image/jpeg"===e&&"transparent"===this.backgroundColor){var n=document.createElement("canvas");n.width=this.canvas.width,n.height=this.canvas.height;var i=n.getContext("2d");if(!i)throw this.logger.error("保存","failed to create export canvas context"),new Error("[CySignPad] failed to create export canvas context");i.fillStyle="#ffffff",i.fillRect(0,0,n.width,n.height),i.drawImage(this.canvas,0,0);var r=n.toDataURL(e,null!=t?t:.92);return this.logger.log("保存",{type:e,quality:null!=t?t:.92,length:r.length}),r}var o="image/jpeg"===e?this.canvas.toDataURL(e,null!=t?t:.92):this.canvas.toDataURL(e);return this.logger.log("保存",{type:e,quality:"image/jpeg"===e?null!=t?t:.92:void 0,length:o.length}),o}}),Object.defineProperty(e.prototype,"destroy",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.destroyed?this.logger.warn("销毁","实例已销毁,忽略重复调用"):(this.destroyed=!0,this.drawing=!1,this.lastPoint=null,this.unbindEvents(),this.disconnectResize(),this.resizeRaf&&(cancelAnimationFrame(this.resizeRaf),this.resizeRaf=0),this.logger.log("销毁","实例已销毁"))}}),Object.defineProperty(e.prototype,"setupCanvas",{enumerable:!1,configurable:!0,writable:!0,value:function(e){var t=this.canvas.getBoundingClientRect(),n=Math.max(1,t.width||this.canvas.clientWidth||Number(this.canvas.getAttribute("width"))||300),i=Math.max(1,t.height||this.canvas.clientHeight||Number(this.canvas.getAttribute("height"))||150),r=window.devicePixelRatio||1;this.cssWidth=n,this.cssHeight=i,this.canvas.width=Math.max(1,Math.floor(n*r)),this.canvas.height=Math.max(1,Math.floor(i*r)),this.canvas.style.width="".concat(n,"px"),this.canvas.style.height="".concat(i,"px"),this.ctx.setTransform(r,0,0,r,0,0),this.ctx.lineCap="round",this.ctx.lineJoin="round",this.ctx.strokeStyle=this.penColor,this.ctx.lineWidth=this.penWidth,e&&this.fillBackground()}}),Object.defineProperty(e.prototype,"fillBackground",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.ctx.save(),this.ctx.setTransform(1,0,0,1,0,0),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.restore(),"transparent"!==this.backgroundColor&&(this.ctx.save(),this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.cssWidth,this.cssHeight),this.ctx.restore()),this.ctx.strokeStyle=this.penColor,this.ctx.lineWidth=this.penWidth,this.ctx.lineCap="round",this.ctx.lineJoin="round"}}),Object.defineProperty(e.prototype,"bindEvents",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.supportsPointer)return this.canvas.addEventListener("pointerdown",this.onPointerDown),this.canvas.addEventListener("pointermove",this.onPointerMove),this.canvas.addEventListener("pointerup",this.onPointerUp),this.canvas.addEventListener("pointercancel",this.onPointerUp),void this.logger.log("事件绑定","Pointer Events");this.canvas.addEventListener("mousedown",this.onMouseDown),window.addEventListener("mousemove",this.onMouseMove),window.addEventListener("mouseup",this.onMouseUp),this.canvas.addEventListener("touchstart",this.onTouchStart,{passive:!1}),this.canvas.addEventListener("touchmove",this.onTouchMove,{passive:!1}),this.canvas.addEventListener("touchend",this.onTouchEnd),this.canvas.addEventListener("touchcancel",this.onTouchEnd),this.logger.log("事件绑定","mouse + touch fallback")}}),Object.defineProperty(e.prototype,"unbindEvents",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.supportsPointer)return this.canvas.removeEventListener("pointerdown",this.onPointerDown),this.canvas.removeEventListener("pointermove",this.onPointerMove),this.canvas.removeEventListener("pointerup",this.onPointerUp),void this.canvas.removeEventListener("pointercancel",this.onPointerUp);this.canvas.removeEventListener("mousedown",this.onMouseDown),window.removeEventListener("mousemove",this.onMouseMove),window.removeEventListener("mouseup",this.onMouseUp),this.canvas.removeEventListener("touchstart",this.onTouchStart),this.canvas.removeEventListener("touchmove",this.onTouchMove),this.canvas.removeEventListener("touchend",this.onTouchEnd),this.canvas.removeEventListener("touchcancel",this.onTouchEnd)}}),Object.defineProperty(e.prototype,"observeResize",{enumerable:!1,configurable:!0,writable:!0,value:function(){var e=this;if("undefined"!=typeof ResizeObserver)return this.resizeObserver=new ResizeObserver(function(){e.scheduleResizeReset()}),void this.resizeObserver.observe(this.canvas);window.addEventListener("resize",this.onWindowResize)}}),Object.defineProperty(e.prototype,"disconnectResize",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.resizeObserver)return this.resizeObserver.disconnect(),void(this.resizeObserver=null);window.removeEventListener("resize",this.onWindowResize)}}),Object.defineProperty(e.prototype,"scheduleResizeReset",{enumerable:!1,configurable:!0,writable:!0,value:function(){var e=this;this.destroyed||(this.resizeRaf&&cancelAnimationFrame(this.resizeRaf),this.resizeRaf=requestAnimationFrame(function(){if(e.resizeRaf=0,!e.destroyed){var t=e.canvas.getBoundingClientRect(),n=Math.max(1,t.width||e.canvas.clientWidth||e.cssWidth),i=Math.max(1,t.height||e.canvas.clientHeight||e.cssHeight);Math.abs(n-e.cssWidth)<.5&&Math.abs(i-e.cssHeight)<.5||(e.logger.log("尺寸变化",{from:{width:e.cssWidth,height:e.cssHeight},to:{width:n,height:i}}),e.setupCanvas(!0),e.empty=!0,e.drawing=!1,e.lastPoint=null,e.logger.log("尺寸变化","已清空并重置,需重新签字"))}}))}}),Object.defineProperty(e.prototype,"handlePointerDown",{enumerable:!1,configurable:!0,writable:!0,value:function(e){var t,n;void 0!==e.button&&0!==e.button||(e.preventDefault(),null===(n=(t=this.canvas).setPointerCapture)||void 0===n||n.call(t,e.pointerId),this.beginStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handlePointerMove",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.continueStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handlePointerUp",{enumerable:!1,configurable:!0,writable:!0,value:function(e){var t,n;if(this.drawing){e.preventDefault();try{null===(n=(t=this.canvas).releasePointerCapture)||void 0===n||n.call(t,e.pointerId)}catch(e){}this.endStroke()}}}),Object.defineProperty(e.prototype,"handleMouseDown",{enumerable:!1,configurable:!0,writable:!0,value:function(e){0===e.button&&(e.preventDefault(),this.beginStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handleMouseMove",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.continueStroke(this.getPointFromClient(e.clientX,e.clientY)))}}),Object.defineProperty(e.prototype,"handleMouseUp",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.endStroke())}}),Object.defineProperty(e.prototype,"handleTouchStart",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(1===e.touches.length){e.preventDefault();var t=e.touches[0];this.beginStroke(this.getPointFromClient(t.clientX,t.clientY))}}}),Object.defineProperty(e.prototype,"handleTouchMove",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(this.drawing&&1===e.touches.length){e.preventDefault();var t=e.touches[0];this.continueStroke(this.getPointFromClient(t.clientX,t.clientY))}}}),Object.defineProperty(e.prototype,"handleTouchEnd",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing&&(e.preventDefault(),this.endStroke())}}),Object.defineProperty(e.prototype,"beginStroke",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.drawing=!0,this.lastPoint=e,this.empty=!1,this.ctx.beginPath(),this.ctx.moveTo(e.x,e.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.logger.log("落笔",e)}}),Object.defineProperty(e.prototype,"continueStroke",{enumerable:!1,configurable:!0,writable:!0,value:function(e){this.lastPoint?(this.ctx.beginPath(),this.ctx.moveTo(this.lastPoint.x,this.lastPoint.y),this.ctx.lineTo(e.x,e.y),this.ctx.stroke(),this.lastPoint=e):this.lastPoint=e}}),Object.defineProperty(e.prototype,"endStroke",{enumerable:!1,configurable:!0,writable:!0,value:function(){this.drawing=!1,this.lastPoint=null,this.logger.log("抬笔","stroke end")}}),Object.defineProperty(e.prototype,"getPointFromClient",{enumerable:!1,configurable:!0,writable:!0,value:function(e,t){var n=this.canvas.getBoundingClientRect(),i=this.cssWidth/(n.width||this.cssWidth),r=this.cssHeight/(n.height||this.cssHeight);return{x:(e-n.left)*i,y:(t-n.top)*r}}}),Object.defineProperty(e.prototype,"ensureAlive",{enumerable:!1,configurable:!0,writable:!0,value:function(){if(this.destroyed)throw this.logger.error("调用校验","instance has been destroyed"),new Error("[CySignPad] instance has been destroyed")}}),e}();export{i as CySignPad};
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "cy-plugin-signpad",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "手写签字板插件,支持 PC / 移动端 Canvas 签名",
6
+ "keywords": [
7
+ "canvas",
8
+ "handwriting",
9
+ "signature",
10
+ "signpad"
11
+ ],
12
+ "license": "MIT",
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "type": "module",
18
+ "main": "./dist/index.cjs",
19
+ "module": "./dist/index.mjs",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.mjs",
25
+ "require": "./dist/index.cjs"
26
+ }
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "build": "NODE_ENV=production rollup -c",
33
+ "dev": "rollup -c -w",
34
+ "preview": "npm run build && npx --yes serve . -l 5173",
35
+ "test": "vitest",
36
+ "lint": "oxlint",
37
+ "fmt": "oxfmt",
38
+ "fmt:check": "oxfmt --check"
39
+ },
40
+ "devDependencies": {
41
+ "@babel/core": "^7.29.7",
42
+ "@babel/preset-env": "^7.29.7",
43
+ "@rollup/plugin-babel": "^6.0.4",
44
+ "@rollup/plugin-commonjs": "^25.0.7",
45
+ "@rollup/plugin-node-resolve": "^15.3.0",
46
+ "@rollup/plugin-terser": "^0.4.4",
47
+ "@rollup/plugin-typescript": "^11.1.6",
48
+ "@types/node": "^20.11.21",
49
+ "jiti": "^2.5.1",
50
+ "oxfmt": "^0.58.0",
51
+ "oxlint": "^1.60.0",
52
+ "rollup": "^4.60.1",
53
+ "rollup-plugin-dts": "^6.1.0",
54
+ "tslib": "^2.8.0",
55
+ "typescript": "^5.3.3",
56
+ "vitest": "^4.1.10"
57
+ }
58
+ }