GestureHandler.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * GestureHandler.js
  3. *
  4. * @author realor
  5. */
  6. import * as THREE from '../lib/three.module.js'
  7. class GestureHandler {
  8. constructor(tool) {
  9. this.tool = tool
  10. this._onPointerDown = this.onPointerDown.bind(this)
  11. this._onPointerMove = this.onPointerMove.bind(this)
  12. this._onPointerUp = this.onPointerUp.bind(this)
  13. this._onContextMenu = this.onContextMenu.bind(this)
  14. this.pointers = new Map()
  15. }
  16. enable() {
  17. const container = this.tool.application.container
  18. container.addEventListener('pointerdown', this._onPointerDown)
  19. container.addEventListener('pointerup', this._onPointerUp)
  20. container.addEventListener('contextmenu', this._onContextMenu, false)
  21. }
  22. disable() {
  23. const container = this.tool.application.container
  24. container.removeEventListener('pointerdown', this._onPointerDown)
  25. container.removeEventListener('pointermove', this._onPointerMove)
  26. container.removeEventListener('pointerup', this._onPointerUp)
  27. container.removeEventListener('contextmenu', this._onContextMenu, false)
  28. this.pointers.clear()
  29. }
  30. onStartGesture() {
  31. if (this.tool.onStartGesture) {
  32. this.tool.onStartGesture()
  33. }
  34. }
  35. onEndGesture() {
  36. if (this.tool.onEndGesture) {
  37. this.tool.onEndGesture()
  38. }
  39. }
  40. onTap(position, button) {
  41. if (this.tool.onTap) {
  42. this.tool.onTap(position, button)
  43. }
  44. }
  45. onDrag(position, direction, pointerCount, button) {
  46. if (this.tool.onDrag) {
  47. this.tool.onDrag(position, direction, pointerCount, button)
  48. }
  49. }
  50. onZoom(position, delta) {
  51. if (this.tool.onZoom) {
  52. this.tool.onZoom(position, delta)
  53. }
  54. }
  55. onRotate(position, angle) {
  56. if (this.tool.onRotate) {
  57. this.tool.onRotate(position, angle)
  58. }
  59. }
  60. onPointerDown(event) {
  61. if (!this.tool.isCanvasEvent(event)) return
  62. const container = this.tool.application.container
  63. let pointers = this.pointers
  64. if (pointers.size === 0) {
  65. container.addEventListener('pointermove', this._onPointerMove)
  66. this.onStartGesture()
  67. }
  68. let pointerId = event.pointerId
  69. let pointerData = pointers.get(pointerId)
  70. if (pointerData === undefined) {
  71. pointerData = {
  72. id: pointerId,
  73. position: new THREE.Vector2(),
  74. previous: new THREE.Vector2(),
  75. delta: new THREE.Vector2(),
  76. button: event.button,
  77. dragLength: 0
  78. }
  79. pointers.set(pointerId, pointerData)
  80. container.setPointerCapture(pointerId)
  81. }
  82. const x = event.offsetX || event.layerX
  83. const y = event.offsetY || event.layerY
  84. pointerData.position.set(x, y)
  85. pointerData.previous.copy(pointerData.position)
  86. pointerData.delta.set(0, 0)
  87. }
  88. onPointerMove(event) {
  89. let pointers = this.pointers
  90. let pointerId = event.pointerId
  91. let pointerData = pointers.get(pointerId)
  92. if (pointerData) {
  93. const x = event.offsetX || event.layerX
  94. const y = event.offsetY || event.layerY
  95. pointerData.previous.copy(pointerData.position)
  96. pointerData.position.set(x, y)
  97. pointerData.delta.subVectors(pointerData.position, pointerData.previous)
  98. }
  99. if (pointers.size === 1) {
  100. const [pointerData] = pointers.values()
  101. pointerData.dragLength += pointerData.delta.length()
  102. this.onDrag(pointerData.previous, pointerData.delta, 1, pointerData.button)
  103. } else if (pointers.size === 2) {
  104. const [pointer1Data, pointer2Data] = pointers.values()
  105. const center = new THREE.Vector2()
  106. center.addVectors(pointer1Data.previous, pointer2Data.previous)
  107. center.x *= 0.5
  108. center.y *= 0.5
  109. let dot = pointer1Data.delta.dot(pointer2Data.delta)
  110. if (dot > 0) {
  111. let direction = new THREE.Vector2()
  112. direction.addVectors(pointer1Data.delta, pointer2Data.delta)
  113. direction.x *= 0.25
  114. direction.y *= 0.25
  115. this.onDrag(center, direction, 2, pointer1Data.button)
  116. } else {
  117. let distance1 = pointer1Data.previous.distanceTo(pointer2Data.previous)
  118. let distance2 = pointer1Data.position.distanceTo(pointer2Data.position)
  119. let delta = distance1 - distance2
  120. this.onZoom(center, delta)
  121. // TODO: detect rotation
  122. }
  123. }
  124. }
  125. onPointerUp(event) {
  126. const container = this.tool.application.container
  127. let pointers = this.pointers
  128. let pointerId = event.pointerId
  129. let pointerData = pointers.get(pointerId)
  130. if (pointerData) {
  131. if (pointerData.dragLength < 3) {
  132. this.onTap(pointerData.position, pointerData.button)
  133. }
  134. pointers.delete(pointerId)
  135. container.releasePointerCapture(pointerId)
  136. }
  137. if (pointers.size === 0) {
  138. container.removeEventListener('pointermove', this._onPointerMove)
  139. this.onEndGesture()
  140. }
  141. }
  142. onContextMenu(event) {
  143. event.preventDefault()
  144. }
  145. }
  146. export { GestureHandler }