eventEmitterMixin.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import H from '../parts/Globals.js';
  2. import U from '../parts/Utilities.js';
  3. var objectEach = U.objectEach,
  4. pick = U.pick;
  5. var fireEvent = H.fireEvent;
  6. /**
  7. * It provides methods for:
  8. * - adding and handling DOM events and a drag event,
  9. * - mapping a mouse move event to the distance between two following events.
  10. * The units of the distance are specific to a transformation,
  11. * e.g. for rotation they are radians, for scaling they are scale factors.
  12. *
  13. * @private
  14. * @mixin
  15. * @memberOf Annotation
  16. */
  17. var eventEmitterMixin = {
  18. /**
  19. * Add emitter events.
  20. */
  21. addEvents: function () {
  22. var emitter = this;
  23. H.addEvent(
  24. emitter.graphic.element,
  25. 'mousedown',
  26. function (e) {
  27. emitter.onMouseDown(e);
  28. }
  29. );
  30. objectEach(emitter.options.events, function (event, type) {
  31. var eventHandler = function (e) {
  32. if (type !== 'click' || !emitter.cancelClick) {
  33. event.call(
  34. emitter,
  35. emitter.chart.pointer.normalize(e),
  36. emitter.target
  37. );
  38. }
  39. };
  40. if (H.inArray(type, emitter.nonDOMEvents || []) === -1) {
  41. emitter.graphic.on(type, eventHandler);
  42. } else {
  43. H.addEvent(emitter, type, eventHandler);
  44. }
  45. });
  46. if (emitter.options.draggable) {
  47. H.addEvent(emitter, 'drag', emitter.onDrag);
  48. if (!emitter.graphic.renderer.styledMode) {
  49. emitter.graphic.css({
  50. cursor: {
  51. x: 'ew-resize',
  52. y: 'ns-resize',
  53. xy: 'move'
  54. }[emitter.options.draggable]
  55. });
  56. }
  57. }
  58. if (!emitter.isUpdating) {
  59. fireEvent(emitter, 'add');
  60. }
  61. },
  62. /**
  63. * Remove emitter document events.
  64. */
  65. removeDocEvents: function () {
  66. if (this.removeDrag) {
  67. this.removeDrag = this.removeDrag();
  68. }
  69. if (this.removeMouseUp) {
  70. this.removeMouseUp = this.removeMouseUp();
  71. }
  72. },
  73. /**
  74. * Mouse down handler.
  75. *
  76. * @param {Object} e event
  77. */
  78. onMouseDown: function (e) {
  79. var emitter = this,
  80. pointer = emitter.chart.pointer,
  81. prevChartX,
  82. prevChartY;
  83. if (e.preventDefault) {
  84. e.preventDefault();
  85. }
  86. // On right click, do nothing:
  87. if (e.button === 2) {
  88. return;
  89. }
  90. e = pointer.normalize(e);
  91. prevChartX = e.chartX;
  92. prevChartY = e.chartY;
  93. emitter.cancelClick = false;
  94. emitter.chart.hasDraggedAnnotation = true;
  95. emitter.removeDrag = H.addEvent(
  96. H.doc,
  97. 'mousemove',
  98. function (e) {
  99. emitter.hasDragged = true;
  100. e = pointer.normalize(e);
  101. e.prevChartX = prevChartX;
  102. e.prevChartY = prevChartY;
  103. fireEvent(emitter, 'drag', e);
  104. prevChartX = e.chartX;
  105. prevChartY = e.chartY;
  106. }
  107. );
  108. emitter.removeMouseUp = H.addEvent(
  109. H.doc,
  110. 'mouseup',
  111. function (e) {
  112. emitter.cancelClick = emitter.hasDragged;
  113. emitter.hasDragged = false;
  114. emitter.chart.hasDraggedAnnotation = false;
  115. // ControlPoints vs Annotation:
  116. fireEvent(pick(emitter.target, emitter), 'afterUpdate');
  117. emitter.onMouseUp(e);
  118. }
  119. );
  120. },
  121. /**
  122. * Mouse up handler.
  123. *
  124. * @param {Object} e event
  125. */
  126. onMouseUp: function () {
  127. var chart = this.chart,
  128. annotation = this.target || this,
  129. annotationsOptions = chart.options.annotations,
  130. index = chart.annotations.indexOf(annotation);
  131. this.removeDocEvents();
  132. annotationsOptions[index] = annotation.options;
  133. },
  134. /**
  135. * Drag and drop event. All basic annotations should share this
  136. * capability as well as the extended ones.
  137. *
  138. * @param {Object} e event
  139. */
  140. onDrag: function (e) {
  141. if (
  142. this.chart.isInsidePlot(
  143. e.chartX - this.chart.plotLeft,
  144. e.chartY - this.chart.plotTop
  145. )
  146. ) {
  147. var translation = this.mouseMoveToTranslation(e);
  148. if (this.options.draggable === 'x') {
  149. translation.y = 0;
  150. }
  151. if (this.options.draggable === 'y') {
  152. translation.x = 0;
  153. }
  154. if (this.points.length) {
  155. this.translate(translation.x, translation.y);
  156. } else {
  157. this.shapes.forEach(function (shape) {
  158. shape.translate(translation.x, translation.y);
  159. });
  160. this.labels.forEach(function (label) {
  161. label.translate(translation.x, translation.y);
  162. });
  163. }
  164. this.redraw(false);
  165. }
  166. },
  167. /**
  168. * Map mouse move event to the radians.
  169. *
  170. * @param {Object} e event
  171. * @param {number} cx center x
  172. * @param {number} cy center y
  173. */
  174. mouseMoveToRadians: function (e, cx, cy) {
  175. var prevDy = e.prevChartY - cy,
  176. prevDx = e.prevChartX - cx,
  177. dy = e.chartY - cy,
  178. dx = e.chartX - cx,
  179. temp;
  180. if (this.chart.inverted) {
  181. temp = prevDx;
  182. prevDx = prevDy;
  183. prevDy = temp;
  184. temp = dx;
  185. dx = dy;
  186. dy = temp;
  187. }
  188. return Math.atan2(dy, dx) - Math.atan2(prevDy, prevDx);
  189. },
  190. /**
  191. * Map mouse move event to the distance between two following events.
  192. *
  193. * @param {Object} e event
  194. */
  195. mouseMoveToTranslation: function (e) {
  196. var dx = e.chartX - e.prevChartX,
  197. dy = e.chartY - e.prevChartY,
  198. temp;
  199. if (this.chart.inverted) {
  200. temp = dy;
  201. dy = dx;
  202. dx = temp;
  203. }
  204. return {
  205. x: dx,
  206. y: dy
  207. };
  208. },
  209. /**
  210. * Map mouse move to the scale factors.
  211. *
  212. * @param {Object} e event
  213. * @param {number} cx center x
  214. * @param {number} cy center y
  215. **/
  216. mouseMoveToScale: function (e, cx, cy) {
  217. var prevDx = e.prevChartX - cx,
  218. prevDy = e.prevChartY - cy,
  219. dx = e.chartX - cx,
  220. dy = e.chartY - cy,
  221. sx = (dx || 1) / (prevDx || 1),
  222. sy = (dy || 1) / (prevDy || 1),
  223. temp;
  224. if (this.chart.inverted) {
  225. temp = sy;
  226. sy = sx;
  227. sx = temp;
  228. }
  229. return {
  230. x: sx,
  231. y: sy
  232. };
  233. },
  234. /**
  235. * Destroy the event emitter.
  236. */
  237. destroy: function () {
  238. this.removeDocEvents();
  239. H.removeEvent(this);
  240. this.hcEvents = null;
  241. }
  242. };
  243. export default eventEmitterMixin;