@@ -27,12 +27,19 @@ import {DOCUMENT} from '@angular/common';
27
27
import { Directionality } from '@angular/cdk/bidi' ;
28
28
import { CdkDragHandle } from './drag-handle' ;
29
29
import { CdkDropContainer , CDK_DROP_CONTAINER } from './drop-container' ;
30
- import { CdkDragStart , CdkDragEnd , CdkDragExit , CdkDragEnter , CdkDragDrop } from './drag-events' ;
30
+ import {
31
+ CdkDragStart ,
32
+ CdkDragEnd ,
33
+ CdkDragExit ,
34
+ CdkDragEnter ,
35
+ CdkDragDrop ,
36
+ CdkDragMove ,
37
+ } from './drag-events' ;
31
38
import { CdkDragPreview } from './drag-preview' ;
32
39
import { CdkDragPlaceholder } from './drag-placeholder' ;
33
40
import { ViewportRuler } from '@angular/cdk/overlay' ;
34
41
import { DragDropRegistry } from './drag-drop-registry' ;
35
- import { Subject , merge } from 'rxjs' ;
42
+ import { Subject , merge , Observable } from 'rxjs' ;
36
43
import { takeUntil } from 'rxjs/operators' ;
37
44
38
45
// TODO(crisbeto): add auto-scrolling functionality.
@@ -97,6 +104,15 @@ export class CdkDrag<T = any> implements OnDestroy {
97
104
/** Cached scroll position on the page when the element was picked up. */
98
105
private _scrollPosition : { top : number , left : number } ;
99
106
107
+ /** Emits when the item is being moved. */
108
+ private _moveEvents = new Subject < CdkDragMove < T > > ( ) ;
109
+
110
+ /**
111
+ * Amount of subscriptions to the move event. Used to avoid
112
+ * hitting the zone if the consumer didn't subscribe to it.
113
+ */
114
+ private _moveEventSubscriptions = 0 ;
115
+
100
116
/** Elements that can be used to drag the draggable item. */
101
117
@ContentChildren ( CdkDragHandle ) _handles : QueryList < CdkDragHandle > ;
102
118
@@ -129,6 +145,20 @@ export class CdkDrag<T = any> implements OnDestroy {
129
145
@Output ( 'cdkDragDropped' ) dropped : EventEmitter < CdkDragDrop < any > > =
130
146
new EventEmitter < CdkDragDrop < any > > ( ) ;
131
147
148
+ /**
149
+ * Emits as the user is dragging the the item. Use with caution,
150
+ * because this event will fire for every pixel that the user has dragged.
151
+ */
152
+ @Output ( 'cdkDragMoved' ) moved : Observable < CdkDragMove < T > > = Observable . create ( observer => {
153
+ const subscription = this . _moveEvents . subscribe ( observer ) ;
154
+ this . _moveEventSubscriptions ++ ;
155
+
156
+ return ( ) => {
157
+ subscription . unsubscribe ( ) ;
158
+ this . _moveEventSubscriptions -- ;
159
+ } ;
160
+ } ) ;
161
+
132
162
constructor (
133
163
/** Element that the draggable is attached to. */
134
164
public element : ElementRef < HTMLElement > ,
@@ -166,6 +196,7 @@ export class CdkDrag<T = any> implements OnDestroy {
166
196
167
197
this . _nextSibling = null ;
168
198
this . _dragDropRegistry . removeDragItem ( this ) ;
199
+ this . _moveEvents . complete ( ) ;
169
200
this . _destroyed . next ( ) ;
170
201
this . _destroyed . complete ( ) ;
171
202
}
@@ -245,15 +276,31 @@ export class CdkDrag<T = any> implements OnDestroy {
245
276
this . _hasMoved = true ;
246
277
event . preventDefault ( ) ;
247
278
279
+ const pointerPosition = this . _getPointerPositionOnPage ( event ) ;
280
+
248
281
if ( this . dropContainer ) {
249
- this . _updateActiveDropContainer ( event ) ;
282
+ this . _updateActiveDropContainer ( pointerPosition ) ;
250
283
} else {
251
284
const activeTransform = this . _activeTransform ;
252
- const { x : pageX , y : pageY } = this . _getPointerPositionOnPage ( event ) ;
253
- activeTransform . x = pageX - this . _pickupPositionOnPage . x + this . _passiveTransform . x ;
254
- activeTransform . y = pageY - this . _pickupPositionOnPage . y + this . _passiveTransform . y ;
285
+ activeTransform . x =
286
+ pointerPosition . x - this . _pickupPositionOnPage . x + this . _passiveTransform . x ;
287
+ activeTransform . y =
288
+ pointerPosition . y - this . _pickupPositionOnPage . y + this . _passiveTransform . y ;
255
289
this . _setTransform ( this . element . nativeElement , activeTransform . x , activeTransform . y ) ;
256
290
}
291
+
292
+ // Since this event gets fired for every pixel while dragging, we only
293
+ // want to fire it if the consumer opted into it. Also we have to
294
+ // re-enter the zone becaus we run all of the events on the outside.
295
+ if ( this . _moveEventSubscriptions > 0 ) {
296
+ this . _ngZone . run ( ( ) => {
297
+ this . _moveEvents . next ( {
298
+ source : this ,
299
+ pointerPosition,
300
+ event
301
+ } ) ;
302
+ } ) ;
303
+ }
257
304
}
258
305
259
306
/** Handler that is invoked when the user lifts their pointer up, after initiating a drag. */
@@ -314,19 +361,17 @@ export class CdkDrag<T = any> implements OnDestroy {
314
361
* Updates the item's position in its drop container, or moves it
315
362
* into a new one, depending on its current drag position.
316
363
*/
317
- private _updateActiveDropContainer ( event : MouseEvent | TouchEvent ) {
318
- const { x, y} = this . _getPointerPositionOnPage ( event ) ;
319
-
364
+ private _updateActiveDropContainer ( { x, y} : Point ) {
320
365
// Drop container that draggable has been moved into.
321
366
const newContainer = this . dropContainer . _getSiblingContainerFromPosition ( x , y ) ;
322
367
323
368
if ( newContainer ) {
324
369
this . _ngZone . run ( ( ) => {
325
370
// Notify the old container that the item has left.
326
- this . exited . emit ( { item : this , container : this . dropContainer } ) ;
371
+ this . exited . emit ( { item : this , container : this . dropContainer } ) ;
327
372
this . dropContainer . exit ( this ) ;
328
373
// Notify the new container that the item has entered.
329
- this . entered . emit ( { item : this , container : newContainer } ) ;
374
+ this . entered . emit ( { item : this , container : newContainer } ) ;
330
375
this . dropContainer = newContainer ;
331
376
this . dropContainer . enter ( this , x , y ) ;
332
377
} ) ;
0 commit comments