Gesture.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. type DragCallback = (dx: number, dy: number) => void
  2. type ZoomCallback = (scale: number, focusX: number, focusY: number) => void
  3. type TapCallback = (dx: number, dy: number) => void
  4. export interface Callbacks {
  5. drag?: DragCallback,
  6. zoom?: ZoomCallback,
  7. tap?: TapCallback,
  8. }
  9. interface MyTouch {
  10. identifier: number,
  11. lastX: number,
  12. lastY: number,
  13. dx: number,
  14. dy: number,
  15. }
  16. interface ScaleTracker {
  17. focusX: number,
  18. focusY: number,
  19. distance: number,
  20. }
  21. export class TouchTracker {
  22. touches: Array<MyTouch> = []
  23. callbacks: Callbacks;
  24. el: HTMLElement;
  25. scaleTracker?: ScaleTracker
  26. distance = 0
  27. constructor(el: HTMLElement, callbacks: Callbacks) {
  28. this.callbacks = callbacks;
  29. this.el = el;
  30. }
  31. private removeTouch(identifier: number) {
  32. let index = this.touches.findIndex(t => t.identifier == identifier)
  33. if (index >= 0) {
  34. this.touches.splice(index, 1)
  35. }
  36. }
  37. private getTouch(identifier: number): MyTouch | null {
  38. let index = this.touches.findIndex(t => t.identifier == identifier)
  39. if (index >= 0) return this.touches[index]
  40. else return null
  41. }
  42. private getX(touch: Touch) {
  43. //return touch.pageX - this.el.offsetLeft
  44. return touch.pageX
  45. }
  46. private getY(touch: Touch) {
  47. //return touch.pageY - this.el.offsetTop
  48. return touch.pageY
  49. }
  50. start(list: TouchList) {
  51. for (var i = 0; i < list.length; i++) {
  52. let touch = list[i];
  53. this.removeTouch(touch.identifier);
  54. this.touches.push({
  55. lastX: this.getX(touch),
  56. lastY: this.getY(touch),
  57. dx: 0,
  58. dy: 0,
  59. identifier: touch.identifier
  60. })
  61. }
  62. if (this.touches.length == 1) {
  63. this.distance = 0;
  64. }
  65. this.updateFocus();
  66. }
  67. updateFocus() {
  68. if (this.touches.length < 2) {
  69. this.scaleTracker = undefined;
  70. return
  71. }
  72. let t1 = this.touches[0];
  73. let t2 = this.touches[1];
  74. let focusX = (t1.lastX + t2.lastX) / 2;
  75. let focusY = (t1.lastY + t2.lastY) / 2;
  76. let distance = Math.sqrt(Math.pow(t2.lastX - t1.lastX, 2) + Math.pow(t2.lastY - t1.lastY, 2));
  77. this.scaleTracker = { focusX, focusY, distance }
  78. }
  79. end(list: TouchList) {
  80. console.log('end')
  81. for (var i = 0; i < list.length; i++) {
  82. this.removeTouch(list[i].identifier);
  83. }
  84. this.updateFocus();
  85. if (this.touches.length <= 0 && this.distance == 0) {
  86. let touch = list[0];
  87. let el = touch.target as HTMLElement
  88. //console.log('kkkkkk', el.offsetLeft, el.offsetTop)
  89. //this.callbacks?.tap?.(touch.clientX - el.offsetLeft, touch.clientY - el.offsetTop)
  90. this.callbacks?.tap?.(touch.clientX , touch.clientY)
  91. }
  92. }
  93. move(list: TouchList) {
  94. for (var i = 0; i < list.length; i++) {
  95. let touch = list[i];
  96. let mytouch = this.getTouch(touch.identifier);
  97. if (mytouch == null) continue;
  98. mytouch.dx = this.getX(touch) - mytouch.lastX
  99. mytouch.dy = this.getY(touch) - mytouch.lastY
  100. mytouch.lastX = this.getX(touch)
  101. mytouch.lastY = this.getY(touch)
  102. if (this.scaleTracker) {
  103. let t1 = this.touches[0];
  104. let t2 = this.touches[1];
  105. let focusX = (t1.lastX + t2.lastX) / 2;
  106. let focusY = (t1.lastY + t2.lastY) / 2;
  107. let distance = Math.sqrt(Math.pow(t2.lastX - t1.lastX, 2) + Math.pow(t2.lastY - t1.lastY, 2));
  108. let dx = focusX - this.scaleTracker.focusX;
  109. let dy = focusY - this.scaleTracker.focusY;
  110. let scale = distance / this.scaleTracker.distance;
  111. console.log(`dx=${dx}, dy=${dy}, scale=${scale}, distance=${distance}`);
  112. this.callbacks.drag?.(dx, dy);
  113. this.callbacks.zoom?.(scale, focusX, focusY);
  114. this.scaleTracker.focusX = focusX;
  115. this.scaleTracker.focusY = focusY;
  116. this.scaleTracker.distance = distance;
  117. this.distance += Math.abs(dx) + Math.abs(dy)
  118. } else {
  119. //if(mytouch.dx > 0 || mytouch.dy >0) {
  120. this.callbacks.drag?.(mytouch.dx, mytouch.dy)
  121. // }
  122. this.distance += Math.abs(mytouch.dx) + Math.abs(mytouch.dy)
  123. }
  124. }
  125. }
  126. }
  127. export class Gesture {
  128. constructor(el: HTMLElement, callbacks: Callbacks) {
  129. var dx, dy;
  130. var isDown = false;
  131. var lastX: number = 0;
  132. var lastY: number = 0;
  133. var distance = 0;
  134. el.addEventListener('mousedown', e => {
  135. isDown = true;
  136. lastX = e.clientX;
  137. lastY = e.clientY;
  138. distance = 0;
  139. })
  140. document.addEventListener('mouseup', e => {
  141. isDown = false;
  142. if (distance == 0 && e.target == el) {
  143. callbacks.tap?.(e.offsetX, e.offsetY)
  144. }
  145. })
  146. document.addEventListener('mousemove', e => {
  147. if (isDown) {
  148. e.preventDefault()
  149. dx = e.clientX - lastX;
  150. dy = e.clientY - lastY;
  151. lastX = e.clientX;
  152. lastY = e.clientY;
  153. distance += Math.abs(dx) + Math.abs(dy)
  154. callbacks?.drag?.(dx, dy);
  155. }
  156. })
  157. el.addEventListener('wheel', e => {
  158. e.preventDefault()
  159. let scale = e.deltaY * -0.01 + 1;
  160. callbacks.zoom?.(scale, e.offsetX, e.offsetY)
  161. })
  162. el.addEventListener('click', e => {
  163. e.preventDefault()
  164. //callbacks.tap?.(e.offsetX, e.offsetY)
  165. })
  166. const tracker = new TouchTracker(el, callbacks);
  167. el.addEventListener('touchstart', e => {
  168. e.preventDefault();
  169. tracker.start(e.changedTouches);
  170. })
  171. el.addEventListener('touchmove', e => {
  172. tracker.move(e.changedTouches)
  173. })
  174. el.addEventListener('touchend', e => {
  175. tracker.end(e.changedTouches)
  176. })
  177. el.addEventListener('touchcancel', e => {
  178. tracker.end(e.changedTouches)
  179. })
  180. }
  181. }