Event.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import { getTowPointDistance } from './utils'
  2. import EventEmitter from 'eventemitter3'
  3. // 事件类
  4. export default class Event extends EventEmitter {
  5. constructor(app) {
  6. super()
  7. this.app = app
  8. this.coordinate = app.coordinate
  9. // 鼠标是否按下
  10. this.isMousedown = false
  11. // 按下时的鼠标位置
  12. this.mousedownPos = {
  13. x: 0,
  14. y: 0,
  15. unGridClientX: 0,
  16. unGridClientY: 0,
  17. originClientX: 0,
  18. originClientY: 0
  19. }
  20. // 鼠标当前位置和按下时位置的差值
  21. this.mouseOffset = {
  22. x: 0,
  23. y: 0,
  24. originX: 0,
  25. originY: 0
  26. }
  27. // 记录上一时刻的鼠标位置
  28. this.lastMousePos = {
  29. x: 0,
  30. y: 0
  31. }
  32. // 前一瞬间的鼠标移动距离
  33. this.mouseDistance = 0
  34. // 记录上一时刻的时间
  35. this.lastMouseTime = Date.now()
  36. // 前一瞬间的时间
  37. this.mouseDuration = 0
  38. // 前一瞬间的鼠标移动速度
  39. this.mouseSpeed = 0
  40. // 绑定事件
  41. this.onMousedown = this.onMousedown.bind(this)
  42. this.onMousemove = this.onMousemove.bind(this)
  43. this.onMouseup = this.onMouseup.bind(this)
  44. this.onDblclick = this.onDblclick.bind(this)
  45. this.onMousewheel = this.onMousewheel.bind(this)
  46. this.onKeydown = this.onKeydown.bind(this)
  47. this.onKeyup = this.onKeyup.bind(this)
  48. this.onContextmenu = this.onContextmenu.bind(this)
  49. this.bindEvent()
  50. }
  51. // 绑定canvas事件
  52. bindEvent() {
  53. this.app.container.addEventListener('mousedown', this.onMousedown)
  54. this.app.container.addEventListener('mousemove', this.onMousemove)
  55. this.app.container.addEventListener('mouseup', this.onMouseup)
  56. this.app.container.addEventListener('dblclick', this.onDblclick)
  57. this.app.container.addEventListener('mousewheel', this.onMousewheel)
  58. this.app.container.addEventListener('contextmenu', this.onContextmenu)
  59. window.addEventListener('keydown', this.onKeydown)
  60. window.addEventListener('keyup', this.onKeyup)
  61. }
  62. // 解绑事件
  63. unbindEvent() {
  64. this.app.container.removeEventListener('mousedown', this.onMousedown)
  65. this.app.container.removeEventListener('mousemove', this.onMousemove)
  66. this.app.container.removeEventListener('mouseup', this.onMouseup)
  67. this.app.container.removeEventListener('dblclick', this.onDblclick)
  68. this.app.container.removeEventListener('mousewheel', this.onMousewheel)
  69. this.app.container.removeEventListener('contextmenu', this.onContextmenu)
  70. window.removeEventListener('keydown', this.onKeydown)
  71. window.removeEventListener('keyup', this.onKeyup)
  72. }
  73. // 转换事件对象e
  74. // 1.将相当于浏览器窗口左上角的坐标转换成相对容器左上角
  75. // 2.如果画布进行了缩放,那么鼠标坐标要反向进行缩放
  76. // 3.x、y坐标加上了画布水平和垂直的滚动距离scrollX和scrollY
  77. // 4.如果开启了网格,那么坐标要吸附到网格上
  78. transformEvent(e) {
  79. let { coordinate } = this.app
  80. // 容器和窗口左上角存在距离时转换
  81. let wp = coordinate.windowToContainer(e.clientX, e.clientY)
  82. // 元素缩放是*scale,所以视觉上我们点击到了元素,但是实际上元素的位置还是原来的x,y,所以鼠标的坐标需要/scale
  83. let { x, y } = coordinate.reverseScale(wp.x, wp.y)
  84. // 加上滚动偏移
  85. x = coordinate.addScrollX(x)
  86. y = coordinate.addScrollY(y)
  87. // 保存未吸附到网格的坐标,用于位置检测等不需要吸附的场景
  88. let unGridClientX = x
  89. let unGridClientY = y
  90. // 如果开启了网格,那么要坐标要吸附到网格
  91. let gp = coordinate.gridAdsorbent(x, y)
  92. let newEvent = {
  93. originEvent: e,
  94. unGridClientX,
  95. unGridClientY,
  96. clientX: gp.x,
  97. clientY: gp.y // 向下滚动scroll值为正,而canvas坐标系向下为正,所以要造成元素向上滚动的效果显示的时候元素的y坐标需要减去scroll值,但是元素真实的y值并未改变,所以对于鼠标坐标来说需要加上scroll值,这样才能匹配元素真实的y坐标,水平方向也是一样的。
  98. }
  99. return newEvent
  100. }
  101. // 鼠标按下事件
  102. onMousedown(e) {
  103. e = this.transformEvent(e)
  104. this.isMousedown = true
  105. this.mousedownPos.x = e.clientX
  106. this.mousedownPos.y = e.clientY
  107. this.mousedownPos.unGridClientX = e.unGridClientX
  108. this.mousedownPos.unGridClientY = e.unGridClientY
  109. this.mousedownPos.originClientX = e.originEvent.clientX
  110. this.mousedownPos.originClientY = e.originEvent.clientY
  111. this.emit('mousedown', e, this)
  112. }
  113. // 鼠标移动事件
  114. onMousemove(e) {
  115. e = this.transformEvent(e)
  116. let x = e.clientX
  117. let y = e.clientY
  118. // 鼠标按下状态
  119. if (this.isMousedown) {
  120. this.mouseOffset.x = x - this.mousedownPos.x
  121. this.mouseOffset.y = y - this.mousedownPos.y
  122. this.mouseOffset.originX =
  123. e.originEvent.clientX - this.mousedownPos.originClientX
  124. this.mouseOffset.originY =
  125. e.originEvent.clientY - this.mousedownPos.originClientY
  126. }
  127. let curTime = Date.now()
  128. // 距离上一次的时间
  129. this.mouseDuration = curTime - this.lastMouseTime
  130. // 距离上一次的距离
  131. this.mouseDistance = getTowPointDistance(
  132. x,
  133. y,
  134. this.lastMousePos.x,
  135. this.lastMousePos.y
  136. )
  137. // 鼠标移动速度
  138. this.mouseSpeed = this.mouseDistance / this.mouseDuration
  139. this.emit('mousemove', e, this)
  140. // 更新变量
  141. this.lastMouseTime = curTime
  142. this.lastMousePos.x = x
  143. this.lastMousePos.y = y
  144. }
  145. // 鼠标松开事件
  146. onMouseup(e) {
  147. e = this.transformEvent(e)
  148. // 复位
  149. this.isMousedown = false
  150. this.mousedownPos.x = 0
  151. this.mousedownPos.y = 0
  152. this.emit('mouseup', e, this)
  153. }
  154. // 双击事件
  155. onDblclick(e) {
  156. e = this.transformEvent(e)
  157. this.emit('dblclick', e, this)
  158. }
  159. // 鼠标滚动事件
  160. onMousewheel(e) {
  161. e = this.transformEvent(e)
  162. this.emit('mousewheel', e.originEvent.wheelDelta < 0 ? 'down' : 'up')
  163. }
  164. // 右键菜单事件
  165. onContextmenu(e) {
  166. e.stopPropagation()
  167. e.preventDefault()
  168. e = this.transformEvent(e)
  169. this.emit('contextmenu', e, this)
  170. }
  171. // 按键按下事件
  172. onKeydown(e) {
  173. this.emit('keydown', e, this)
  174. }
  175. // 按键松开事件
  176. onKeyup(e) {
  177. this.emit('keyup', e, this)
  178. }
  179. }