Draggable.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import Handler from '../Handler';
  2. import Element, { ElementEvent } from '../Element';
  3. import Displayable from '../graphic/Displayable';
  4. class Param {
  5. target: Element
  6. topTarget: Element
  7. constructor(target: Element, e?: ElementEvent) {
  8. this.target = target;
  9. this.topTarget = e && e.topTarget;
  10. }
  11. }
  12. // FIXME Draggable on element which has parent rotation or scale
  13. export default class Draggable {
  14. handler: Handler
  15. _draggingTarget: Element
  16. _dropTarget: Element
  17. _x: number
  18. _y: number
  19. constructor(handler: Handler) {
  20. this.handler = handler;
  21. handler.on('mousedown', this._dragStart, this);
  22. handler.on('mousemove', this._drag, this);
  23. handler.on('mouseup', this._dragEnd, this);
  24. // `mosuemove` and `mouseup` can be continue to fire when dragging.
  25. // See [DRAG_OUTSIDE] in `Handler.js`. So we do not need to trigger
  26. // `_dragEnd` when globalout. That would brings better user experience.
  27. // this.on('globalout', this._dragEnd, this);
  28. // this._dropTarget = null;
  29. // this._draggingTarget = null;
  30. // this._x = 0;
  31. // this._y = 0;
  32. }
  33. _dragStart(e: ElementEvent) {
  34. let draggingTarget = e.target;
  35. // Find if there is draggable in the ancestor
  36. while (draggingTarget && !draggingTarget.draggable) {
  37. draggingTarget = draggingTarget.parent || draggingTarget.__hostTarget;
  38. }
  39. if (draggingTarget) {
  40. this._draggingTarget = draggingTarget;
  41. draggingTarget.dragging = true;
  42. this._x = e.offsetX;
  43. this._y = e.offsetY;
  44. this.handler.dispatchToElement(
  45. new Param(draggingTarget, e), 'dragstart', e.event
  46. );
  47. }
  48. }
  49. _drag(e: ElementEvent) {
  50. const draggingTarget = this._draggingTarget;
  51. if (draggingTarget) {
  52. const x = e.offsetX;
  53. const y = e.offsetY;
  54. const dx = x - this._x;
  55. const dy = y - this._y;
  56. this._x = x;
  57. this._y = y;
  58. draggingTarget.drift(dx, dy, e);
  59. this.handler.dispatchToElement(
  60. new Param(draggingTarget, e), 'drag', e.event
  61. );
  62. const dropTarget = this.handler.findHover(
  63. x, y, draggingTarget as Displayable // PENDING
  64. ).target;
  65. const lastDropTarget = this._dropTarget;
  66. this._dropTarget = dropTarget;
  67. if (draggingTarget !== dropTarget) {
  68. if (lastDropTarget && dropTarget !== lastDropTarget) {
  69. this.handler.dispatchToElement(
  70. new Param(lastDropTarget, e), 'dragleave', e.event
  71. );
  72. }
  73. if (dropTarget && dropTarget !== lastDropTarget) {
  74. this.handler.dispatchToElement(
  75. new Param(dropTarget, e), 'dragenter', e.event
  76. );
  77. }
  78. }
  79. }
  80. }
  81. _dragEnd(e: ElementEvent) {
  82. const draggingTarget = this._draggingTarget;
  83. if (draggingTarget) {
  84. draggingTarget.dragging = false;
  85. }
  86. this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragend', e.event);
  87. if (this._dropTarget) {
  88. this.handler.dispatchToElement(new Param(this._dropTarget, e), 'drop', e.event);
  89. }
  90. this._draggingTarget = null;
  91. this._dropTarget = null;
  92. }
  93. }