signature.uts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { LSignatureOptions, Point, Line } from '../../index.uts'
  2. let points : Line = []
  3. let undoStack : Line[] = [];
  4. let redoStack : Line[] = [];
  5. let lastX = 0;
  6. let lastY = 0;
  7. export class Signature {
  8. el : UniElement
  9. options : LSignatureOptions = {
  10. penColor: 'black',
  11. openSmooth: true,
  12. disableScroll: true,
  13. disabled: false,
  14. penSize: 2,
  15. minLineWidth: 2,
  16. maxLineWidth: 6,
  17. minSpeed: 1.5,
  18. maxWidthDiffRate: 20,
  19. maxHistoryLength: 20
  20. } as LSignatureOptions
  21. ctx : DrawableContext
  22. isEmpty : boolean = true
  23. isDrawing : boolean = false
  24. // historyList : Point[][] = []
  25. // id : string
  26. // instance : ComponentPublicInstance
  27. touchstartCallbackWrapper: UniCallbackWrapper|null = null
  28. touchmoveCallbackWrapper: UniCallbackWrapper|null= null
  29. touchendCallbackWrapper: UniCallbackWrapper|null= null
  30. constructor(el : UniElement) {
  31. this.el = el
  32. this.ctx = el.getDrawableContext() as DrawableContext
  33. this.init()
  34. }
  35. init() {
  36. this.touchstartCallbackWrapper = this.el.addEventListener('touchstart', this.onTouchStart)
  37. this.touchmoveCallbackWrapper = this.el.addEventListener('touchmove', this.onTouchMove)
  38. this.touchendCallbackWrapper = this.el.addEventListener('touchend', this.onTouchEnd)
  39. }
  40. remove() {
  41. if(this.touchstartCallbackWrapper == null) return
  42. this.el.removeEventListener('touchstart', this.touchstartCallbackWrapper!)
  43. this.el.removeEventListener('touchmove', this.touchmoveCallbackWrapper!)
  44. this.el.removeEventListener('touchend', this.touchendCallbackWrapper!)
  45. }
  46. setOption(options : LSignatureOptions) {
  47. this.options = options
  48. }
  49. disableScroll(event : UniTouchEvent) {
  50. event.stopPropagation()
  51. if (this.options.disableScroll) {
  52. {
  53. event.preventDefault()
  54. }
  55. }
  56. }
  57. getTouchPoint(event : UniTouchEvent) : Point {
  58. const rect = this.el.getBoundingClientRect()
  59. const touche = event.touches[0];
  60. const x = touche.clientX
  61. const y = touche.clientY
  62. // const force = touche.force
  63. return {
  64. x: x - rect.left,
  65. y: y - rect.top
  66. } as Point
  67. }
  68. onTouchStart: (event : UniTouchEvent) => void = (event : UniTouchEvent) =>{
  69. if (this.options.disabled) {
  70. return
  71. }
  72. this.disableScroll(event)
  73. const { x, y } = this.getTouchPoint(event)
  74. this.isDrawing = true;
  75. this.isEmpty = false
  76. lastX = x
  77. lastY = y
  78. points.push({ x, y } as Point);
  79. }
  80. onTouchMove: (event : UniTouchEvent) => void = (event : UniTouchEvent) =>{
  81. if (this.options.disabled || !this.isDrawing) {
  82. return
  83. }
  84. this.disableScroll(event)
  85. const { x, y } = this.getTouchPoint(event)
  86. const lineWidth = this.options.penSize
  87. const strokeStyle = this.options.penColor
  88. const point = { x, y } as Point
  89. const last = { x: lastX, y: lastY } as Point
  90. this.drawLine(point, last, lineWidth, strokeStyle)
  91. lastX = x
  92. lastY = y
  93. points.push({ x, y, c: strokeStyle, w: lineWidth } as Point);
  94. }
  95. onTouchEnd: (event : UniTouchEvent) => void = (event : UniTouchEvent) =>{
  96. this.disableScroll(event)
  97. this.isDrawing = false;
  98. undoStack.push(points);
  99. redoStack = [] as Line[];
  100. points = [] as Point[];
  101. }
  102. drawLine(point : Point, last : Point, lineWidth : number, strokeStyle : string) {
  103. const ctx = this.ctx
  104. ctx.lineWidth = lineWidth
  105. ctx.strokeStyle = strokeStyle
  106. ctx.lineCap = 'round'
  107. ctx.lineJoin = 'round'
  108. ctx.beginPath()
  109. ctx.moveTo(last.x, last.y)
  110. ctx.lineTo(point.x, point.y)
  111. ctx.stroke()
  112. ctx.update()
  113. }
  114. // addHistory() { }
  115. clear() {
  116. this.ctx.reset()
  117. this.ctx.update()
  118. this.isEmpty = true
  119. undoStack = [] as Line[];
  120. redoStack = [] as Line[];
  121. points = [] as Point[];
  122. }
  123. undo() {
  124. if(redoStack.length == this.options.maxHistoryLength && this.options.maxHistoryLength != 0){
  125. return
  126. }
  127. this.ctx.reset()
  128. if(undoStack.length > 0){
  129. const lastPath : Line = undoStack.pop()!;
  130. redoStack.push(lastPath);
  131. if(undoStack.length == 0){
  132. this.isEmpty = true
  133. this.ctx.update()
  134. return
  135. }
  136. for (let l = 0; l < undoStack.length; l++) {
  137. for (let i = 1; i < undoStack[l].length; i++) {
  138. const last = undoStack[l][i - 1]
  139. const point = undoStack[l][i]
  140. this.drawLine(point, last, point.w!, point.c!)
  141. }
  142. }
  143. } else {
  144. this.ctx.update()
  145. }
  146. }
  147. redo() {
  148. if(redoStack.length < 1) return
  149. const lastPath : Line = redoStack.pop()!;
  150. undoStack.push(lastPath);
  151. this.isEmpty = false
  152. for (let l = 0; l < undoStack.length; l++) {
  153. for (let i = 1; i < undoStack[l].length; i++) {
  154. const last = undoStack[l][i - 1]
  155. const point = undoStack[l][i]
  156. this.drawLine(point, last, point.w!, point.c!)
  157. }
  158. }
  159. }
  160. // restore() { }
  161. }