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