signature.uts 4.2 KB

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