SGraphyView.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * ********************************************************************************************************************
  3. *
  4. * iFHS7.
  5. * ;BBMBMBMc rZMBMBR BMB
  6. * MBEr:;PBM, 7MBMMEOBB: BBB RBW
  7. * XK: BO SB. :SZ MBM. c;; ir BBM :FFr :SSF: ;xBMB:r iuGXv. i:. iF2;
  8. * DBBM0r. :D S7 ;XMBMB GMBMu. MBM: BMB MBMBBBMBMS WMBMBMBBK MBMBMBM BMBRBMBW .MBMBMBMBB
  9. * :JMRMMD .. , 1MMRM1; ;MBMBBR: MBM ;MB: BMB: MBM. RMBr sBMH BM0 UMB, BMB. KMBv
  10. * ;. XOW B1; :uM: 1RE, i .2BMBs rMB. MBO MBO JMB; MBB MBM BBS 7MBMBOBM: MBW :BMc
  11. * OBRJ.SEE MRDOWOR, 3DE:7OBM . ;BMB RMR7BM BMB MBB. BMB ,BMR .BBZ MMB rMB, BMM rMB7
  12. * :FBRO0D0 RKXSXPR. JOKOOMPi BMBSSWBMB; BMBB: MBMB0ZMBMS .BMBOXRBMB MBMDE RBM2;SMBM; MBB xBM2
  13. * iZGE O0SHSPO. uGZ7. sBMBMBDL :BMO OZu:BMBK, rRBMB0; ,EBMB xBMBr:ER. RDU :OO;
  14. * ,BZ, 1D0 RPSFHXR. xWZ .SMr . .BBB
  15. * :0BMRDG RESSSKR. 2WOMBW; BMBMR
  16. * i0BM: SWKHKGO MBDv
  17. * .UB OOGDM. MK, Copyright (c) 2015-2018. 斯伯坦机器人世界
  18. * , XMW ..
  19. * r All rights reserved.
  20. *
  21. * ********************************************************************************************************************
  22. */
  23. import './SCanvas'
  24. import SPoint from './types/SPoint'
  25. import SMouseEvent from './SMouseEvent'
  26. const bindEvent = Symbol('bindEvent')
  27. const toSceneMotionEvent = Symbol('toSceneMotionEvent')
  28. /**
  29. * Graphy图形引擎视图类
  30. *
  31. * @author Andy
  32. */
  33. export default class SGraphyView {
  34. /**
  35. * 构造函数
  36. *
  37. * @param id Canvas对象ID
  38. */
  39. constructor(id, scene) {
  40. this.canvasView = document.getElementById(id)
  41. this.canvas = this.canvasView.getContext('2d')
  42. this[bindEvent](this.canvasView)
  43. this.scene = scene
  44. this.pos = new SPoint(10, 0)
  45. this.scale = 1
  46. this.minScale = 0.004
  47. this.maxScale = 0.5
  48. this._midKeyX = 0
  49. this._midKeyY = 0
  50. this.wheelZoom = 1.05
  51. window.requestAnimationFrame(this.onDraw.bind(this))
  52. } // Function constructor()
  53. /**
  54. * 绑定canvas事件
  55. *
  56. * @param canvas canvas对象
  57. * @private
  58. */
  59. [bindEvent](canvasView) {
  60. canvasView.onclick = this.onClick.bind(this)
  61. canvasView.ondblclick = this.onDbClick.bind(this)
  62. canvasView.onmousedown = this.onMouseDown.bind(this)
  63. canvasView.onmousemove = this.onMouseMove.bind(this)
  64. canvasView.onmouseup = this.onMouseUp.bind(this)
  65. canvasView.onmousewheel = this.onMouseWheel.bind(this)
  66. canvasView.onresize = this.onResize.bind(this)
  67. } // Function [bindEvent]()
  68. /**
  69. * 获取canvas的宽度
  70. */
  71. get width() {
  72. return this.canvasView.width
  73. }
  74. get height() {
  75. return this.canvasView.height
  76. }
  77. /**
  78. * 将场景中的xy坐标转换成视图坐标。
  79. *
  80. * @param x 场景中的横坐标
  81. * @param y 场景中的纵坐标
  82. *
  83. * @return SPoint
  84. */
  85. mapFromScene(x, y = null) {
  86. if (typeof(x) === 'object') { // 如果传入的是SPoint对象
  87. return new SPoint(x.x * this.scale + this.pos.x, x.y * this.scale + this.pos.y)
  88. }
  89. return new SPoint(x * this.scale + this.pos.x, y * this.scale + this.pos.y)
  90. } // Function mapFromScene()
  91. /**
  92. * 将item中的xy坐标转换成场景坐标。
  93. *
  94. * @param x item中的横坐标
  95. * @param y item中的纵坐标
  96. * @return SPoint
  97. */
  98. mapToScene(x, y = null) {
  99. if (typeof(x) === 'object') { // 如果传入的是SPoint对象
  100. return new SPoint((x.x - this.pos.x) / this.scale, (x.y - this.pos.y) / this.scale)
  101. }
  102. return new SPoint((x - this.pos.x) / this.scale, (y - this.pos.y) / this.scale)
  103. } // Function mapToScene()
  104. /**
  105. * 缩放视图时计算视图的位置与缩放比例
  106. *
  107. * @param zoom 缩放比例
  108. * @param x0 缩放计算的中心点X坐标
  109. * @param y0 缩放计算的中心点Y坐标
  110. */
  111. scaleByPoint(zoom, x0, y0) {
  112. let z = zoom
  113. /**
  114. * 缩放比例在最小比例和最大比例范围内
  115. */
  116. if (this.scale * zoom >= this.maxScale) { // 大于最大缩放比例
  117. z = this.maxScale / this.scale
  118. this.scale = this.maxScale
  119. } else if (this.scale * zoom <= this.minScale) { // 小于最小绽放比例
  120. z = this.minScale / this.scale
  121. this.scale = this.minScale
  122. } else {
  123. this.scale *= zoom
  124. }
  125. this.pos.x = x0 - (x0 - this.pos.x) * z
  126. this.pos.y = y0 - (y0 - this.pos.y) * z
  127. // EventBus.getDefault().post(SGraphyViewZoomEvent(this, scale))
  128. // EventBus.getDefault().post(SGraphyViewMoveEvent(this, pos.x, pos.y))
  129. // return
  130. } // Function scaleByPoint()
  131. // ===================================================================================================================
  132. // 事件
  133. onDraw() {
  134. this.canvas.save()
  135. this.canvas.clearRect(0, 0, this.canvasView.width, this.canvasView.height)
  136. this.canvas.restore()
  137. if (this.scene != null) {
  138. // 绘制背景
  139. this.canvas.save()
  140. this.scene.drawBackground(this.canvas)
  141. this.canvas.restore()
  142. // 绘制场景
  143. this.canvas.save()
  144. this.canvas.translate(this.pos.x, this.pos.y)
  145. this.canvas.scale(this.scale, this.scale)
  146. this.scene.drawScene(this.canvas)
  147. this.canvas.restore()
  148. // 绘制前景
  149. this.canvas.save()
  150. this.scene.drawForeground(this.canvas)
  151. this.canvas.restore()
  152. }
  153. window.requestAnimationFrame(this.onDraw.bind(this))
  154. } // Function onDraw()
  155. /**
  156. * 鼠标单击事件
  157. *
  158. * @param e 保存事件参数
  159. */
  160. onClick(e) {
  161. if (this.scene != null) {
  162. let se = this[toSceneMotionEvent](e)
  163. this.scene.onClick(se)
  164. }
  165. } // Function onClick()
  166. /**
  167. * 鼠标双击事件
  168. *
  169. * @param e 保存事件参数
  170. */
  171. onDbClick(e) {
  172. if (this.scene != null) {
  173. let ce = this[toSceneMotionEvent](e)
  174. this.scene.onDbClick(ce)
  175. }
  176. } // Function onDbClick()
  177. /**
  178. * 鼠标按下事件
  179. *
  180. * @param e 保存事件参数
  181. */
  182. onMouseDown(e) {
  183. let se = new SMouseEvent(e)
  184. if (se.buttons & SMouseEvent.MIDDLE_BUTTON) { // 如果按下中键
  185. this._midKeyX = e.x
  186. this._midKeyY = e.y
  187. }
  188. if (this.scene != null) {
  189. let ce = this[toSceneMotionEvent](e)
  190. this.scene.onMouseDown(ce)
  191. }
  192. } // Function onMouseDown()
  193. /**
  194. * 鼠标移动事件
  195. *
  196. * @param e 保存事件参数
  197. */
  198. onMouseMove(e) {
  199. let se = new SMouseEvent(e)
  200. if (se.buttons & SMouseEvent.MIDDLE_BUTTON) { // 如果按下中键,则移动视图
  201. this.pos.x += e.x - this._midKeyX
  202. this.pos.y += e.y - this._midKeyY
  203. this._midKeyX = e.x
  204. this._midKeyY = e.y
  205. return
  206. }
  207. if (this.scene != null) {
  208. let ce = this[toSceneMotionEvent](e)
  209. this.scene.onMouseMove(ce)
  210. }
  211. } // Function onMouseMove()
  212. /**
  213. * 释放鼠标事件
  214. *
  215. * @param e 保存事件参数
  216. */
  217. onMouseUp(e) {
  218. if (this.scene != null) {
  219. let ce = this[toSceneMotionEvent](e)
  220. this.scene.onMouseUp(ce)
  221. }
  222. } // Function onMouseUp()
  223. /**
  224. * 鼠标滚轮事件
  225. *
  226. * @param e 保存事件参数
  227. */
  228. onMouseWheel(e) {
  229. let se = new SMouseEvent(e)
  230. if (e.wheelDelta < 0) {
  231. this.scaleByPoint(1 / this.wheelZoom, se.x, se.y)
  232. } else {
  233. this.scaleByPoint(this.wheelZoom, se.x, se.y)
  234. }
  235. } // Function onMouseWheel()
  236. /**
  237. * View大小发生变化事件
  238. *
  239. * @param e 保存事件参数
  240. */
  241. onResize(e) {} // Function onResize()
  242. /**
  243. * MotionEvent转场景对象MotionEvent
  244. *
  245. * @param e MotionEvent
  246. * @return 子对象MotionEvent
  247. */
  248. [toSceneMotionEvent](e) {
  249. let se = new SMouseEvent(e)
  250. se.x = (se.x - this.pos.x) / this.scale
  251. se.y = (se.y - this.pos.y) / this.scale
  252. return se
  253. } // Function toSceneMotionEvent()
  254. } // Class SGraphyView