Skip to content

Commit 35a045c

Browse files
crisbetojelbourn
authored andcommitted
feat(drag-drop): include dragged distance in events (#15947)
Adds the distance that the user has dragged in the `ended`, `moved` and `drop` events. This makes cases like resize handles to be implemented more conveniently.
1 parent a833dfb commit 35a045c

File tree

7 files changed

+171
-34
lines changed

7 files changed

+171
-34
lines changed

src/cdk/drag-drop/directives/drag.spec.ts

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,31 @@ describe('CdkDrag', () => {
356356

357357
// Assert the event like this, rather than `toHaveBeenCalledWith`, because Jasmine will
358358
// go into an infinite loop trying to stringify the event, if the test fails.
359-
expect(event).toEqual({source: fixture.componentInstance.dragInstance});
359+
expect(event).toEqual({
360+
source: fixture.componentInstance.dragInstance,
361+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
362+
});
363+
}));
364+
365+
it('should include the drag distance in the ended event', fakeAsync(() => {
366+
const fixture = createComponent(StandaloneDraggable);
367+
fixture.detectChanges();
368+
369+
dragElementViaMouse(fixture, fixture.componentInstance.dragElement.nativeElement, 25, 30);
370+
let event = fixture.componentInstance.endedSpy.calls.mostRecent().args[0];
371+
372+
expect(event).toEqual({
373+
source: jasmine.anything(),
374+
distance: {x: 25, y: 30}
375+
});
376+
377+
dragElementViaMouse(fixture, fixture.componentInstance.dragElement.nativeElement, 40, 50);
378+
event = fixture.componentInstance.endedSpy.calls.mostRecent().args[0];
379+
380+
expect(event).toEqual({
381+
source: jasmine.anything(),
382+
distance: {x: 40, y: 50}
383+
});
360384
}));
361385

362386
it('should emit when the user is moving the drag element', () => {
@@ -855,6 +879,30 @@ describe('CdkDrag', () => {
855879
expect(dragElement.style.transform).toBe('translate3d(150px, 300px, 0px)');
856880
}));
857881

882+
it('should include the dragged distance as the user is dragging', fakeAsync(() => {
883+
const fixture = createComponent(StandaloneDraggable);
884+
fixture.detectChanges();
885+
const dragElement = fixture.componentInstance.dragElement.nativeElement;
886+
const spy = jasmine.createSpy('moved spy');
887+
const subscription = fixture.componentInstance.dragInstance.moved.subscribe(spy);
888+
889+
startDraggingViaMouse(fixture, dragElement);
890+
891+
dispatchMouseEvent(document, 'mousemove', 50, 100);
892+
fixture.detectChanges();
893+
894+
let event = spy.calls.mostRecent().args[0];
895+
expect(event.distance).toEqual({x: 50, y: 100});
896+
897+
dispatchMouseEvent(document, 'mousemove', 75, 50);
898+
fixture.detectChanges();
899+
900+
event = spy.calls.mostRecent().args[0];
901+
expect(event.distance).toEqual({x: 75, y: 50});
902+
903+
subscription.unsubscribe();
904+
}));
905+
858906
});
859907

860908
describe('draggable with a handle', () => {
@@ -1160,7 +1208,8 @@ describe('CdkDrag', () => {
11601208
item: firstItem,
11611209
container: fixture.componentInstance.dropInstance,
11621210
previousContainer: fixture.componentInstance.dropInstance,
1163-
isPointerOverContainer: true
1211+
isPointerOverContainer: true,
1212+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
11641213
});
11651214

11661215
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
@@ -1187,6 +1236,24 @@ describe('CdkDrag', () => {
11871236
expect(event.isPointerOverContainer).toBe(true);
11881237
}));
11891238

1239+
it('should expose the drag distance when an item is dropped', fakeAsync(() => {
1240+
const fixture = createComponent(DraggableInDropZone);
1241+
fixture.detectChanges();
1242+
const dragItems = fixture.componentInstance.dragItems;
1243+
const firstItem = dragItems.first;
1244+
1245+
dragElementViaMouse(fixture, firstItem.element.nativeElement, 50, 60);
1246+
flush();
1247+
fixture.detectChanges();
1248+
1249+
expect(fixture.componentInstance.droppedSpy).toHaveBeenCalledTimes(1);
1250+
1251+
const event: CdkDragDrop<any> =
1252+
fixture.componentInstance.droppedSpy.calls.mostRecent().args[0];
1253+
1254+
expect(event.distance).toEqual({x: 50, y: 60});
1255+
}));
1256+
11901257
it('should expose whether an item was dropped outside of a container', fakeAsync(() => {
11911258
const fixture = createComponent(DraggableInDropZone);
11921259
fixture.detectChanges();
@@ -1267,7 +1334,8 @@ describe('CdkDrag', () => {
12671334
item: firstItem,
12681335
container: fixture.componentInstance.dropInstance,
12691336
previousContainer: fixture.componentInstance.dropInstance,
1270-
isPointerOverContainer: false
1337+
isPointerOverContainer: false,
1338+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
12711339
});
12721340

12731341
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
@@ -1325,7 +1393,8 @@ describe('CdkDrag', () => {
13251393
item: firstItem,
13261394
container: fixture.componentInstance.dropInstance,
13271395
previousContainer: fixture.componentInstance.dropInstance,
1328-
isPointerOverContainer: true
1396+
isPointerOverContainer: true,
1397+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
13291398
});
13301399

13311400
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
@@ -1365,7 +1434,8 @@ describe('CdkDrag', () => {
13651434
item: firstItem,
13661435
container: fixture.componentInstance.dropInstance,
13671436
previousContainer: fixture.componentInstance.dropInstance,
1368-
isPointerOverContainer: true
1437+
isPointerOverContainer: true,
1438+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
13691439
});
13701440

13711441
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
@@ -1401,7 +1471,8 @@ describe('CdkDrag', () => {
14011471
item: firstItem,
14021472
container: fixture.componentInstance.dropInstance,
14031473
previousContainer: fixture.componentInstance.dropInstance,
1404-
isPointerOverContainer: false
1474+
isPointerOverContainer: false,
1475+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
14051476
});
14061477

14071478
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
@@ -2539,7 +2610,8 @@ describe('CdkDrag', () => {
25392610
item: firstItem,
25402611
container: dropInstance,
25412612
previousContainer: dropInstance,
2542-
isPointerOverContainer: true
2613+
isPointerOverContainer: true,
2614+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
25432615
});
25442616

25452617
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
@@ -2595,7 +2667,8 @@ describe('CdkDrag', () => {
25952667
item,
25962668
container: fixture.componentInstance.dropInstances.toArray()[1],
25972669
previousContainer: fixture.componentInstance.dropInstances.first,
2598-
isPointerOverContainer: true
2670+
isPointerOverContainer: true,
2671+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
25992672
});
26002673
}));
26012674

@@ -2697,7 +2770,8 @@ describe('CdkDrag', () => {
26972770
item: groups[0][1],
26982771
container: dropInstances[1],
26992772
previousContainer: dropInstances[0],
2700-
isPointerOverContainer: true
2773+
isPointerOverContainer: true,
2774+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
27012775
});
27022776
}));
27032777

@@ -2727,7 +2801,8 @@ describe('CdkDrag', () => {
27272801
item: groups[0][1],
27282802
container: dropInstances[0],
27292803
previousContainer: dropInstances[0],
2730-
isPointerOverContainer: false
2804+
isPointerOverContainer: false,
2805+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
27312806
});
27322807
}));
27332808

@@ -2757,7 +2832,8 @@ describe('CdkDrag', () => {
27572832
item: groups[0][1],
27582833
container: dropInstances[0],
27592834
previousContainer: dropInstances[0],
2760-
isPointerOverContainer: false
2835+
isPointerOverContainer: false,
2836+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
27612837
});
27622838
}));
27632839

@@ -2880,7 +2956,8 @@ describe('CdkDrag', () => {
28802956
item: groups[0][1],
28812957
container: dropInstances[1],
28822958
previousContainer: dropInstances[0],
2883-
isPointerOverContainer: true
2959+
isPointerOverContainer: true,
2960+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
28842961
});
28852962
}));
28862963

@@ -2906,7 +2983,8 @@ describe('CdkDrag', () => {
29062983
item: groups[0][1],
29072984
container: dropInstances[1],
29082985
previousContainer: dropInstances[0],
2909-
isPointerOverContainer: true
2986+
isPointerOverContainer: true,
2987+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
29102988
});
29112989
}));
29122990

@@ -2937,7 +3015,8 @@ describe('CdkDrag', () => {
29373015
item: groups[0][1],
29383016
container: dropInstances[1],
29393017
previousContainer: dropInstances[0],
2940-
isPointerOverContainer: true
3018+
isPointerOverContainer: true,
3019+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
29413020
});
29423021
}));
29433022

@@ -2972,7 +3051,8 @@ describe('CdkDrag', () => {
29723051
item,
29733052
container: fixture.componentInstance.dropInstances.toArray()[1],
29743053
previousContainer: fixture.componentInstance.dropInstances.first,
2975-
isPointerOverContainer: true
3054+
isPointerOverContainer: true,
3055+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
29763056
});
29773057

29783058
expect(dropContainers[0].contains(item.element.nativeElement)).toBe(true,
@@ -3068,7 +3148,8 @@ describe('CdkDrag', () => {
30683148
item: groups[0][1],
30693149
container: dropInstances[0],
30703150
previousContainer: dropInstances[0],
3071-
isPointerOverContainer: false
3151+
isPointerOverContainer: false,
3152+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
30723153
});
30733154
}));
30743155

@@ -3188,7 +3269,8 @@ describe('CdkDrag', () => {
31883269
item: groups[0][1],
31893270
container: dropInstances[2],
31903271
previousContainer: dropInstances[0],
3191-
isPointerOverContainer: false
3272+
isPointerOverContainer: false,
3273+
distance: {x: jasmine.any(Number), y: jasmine.any(Number)}
31923274
}));
31933275

31943276
}));

src/cdk/drag-drop/directives/drag.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
186186
source: this,
187187
pointerPosition: movedEvent.pointerPosition,
188188
event: movedEvent.event,
189-
delta: movedEvent.delta
189+
delta: movedEvent.delta,
190+
distance: movedEvent.distance
190191
}))).subscribe(observer);
191192

192193
return () => {
@@ -375,8 +376,8 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
375376
this.released.emit({source: this});
376377
});
377378

378-
ref.ended.subscribe(() => {
379-
this.ended.emit({source: this});
379+
ref.ended.subscribe(event => {
380+
this.ended.emit({source: this, distance: event.distance});
380381

381382
// Since all of these events run outside of change detection,
382383
// we need to ensure that everything is marked correctly.
@@ -405,7 +406,8 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
405406
previousContainer: event.previousContainer.data,
406407
container: event.container.data,
407408
isPointerOverContainer: event.isPointerOverContainer,
408-
item: this
409+
item: this,
410+
distance: event.distance
409411
});
410412
});
411413
}

src/cdk/drag-drop/directives/drop-list.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ export class CdkDropList<T = any> implements CdkDropListContainer, AfterContentI
342342
previousContainer: event.previousContainer.data,
343343
container: event.container.data,
344344
item: event.item.data,
345-
isPointerOverContainer: event.isPointerOverContainer
345+
isPointerOverContainer: event.isPointerOverContainer,
346+
distance: event.distance
346347
});
347348

348349
// Mark for check since all of these events run outside of change

src/cdk/drag-drop/drag-events.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export interface CdkDragRelease<T = any> {
2525
export interface CdkDragEnd<T = any> {
2626
/** Draggable that emitted the event. */
2727
source: CdkDrag<T>;
28+
/** Distance in pixels that the user has dragged since the drag sequence started. */
29+
distance: {x: number, y: number};
2830
}
2931

3032
/** Event emitted when the user moves an item into a new drop container. */
@@ -63,6 +65,8 @@ export interface CdkDragDrop<T, O = T> {
6365
previousContainer: CdkDropList<O>;
6466
/** Whether the user's pointer was over the container when the item was dropped. */
6567
isPointerOverContainer: boolean;
68+
/** Distance in pixels that the user has dragged since the drag sequence started. */
69+
distance: {x: number, y: number};
6670
}
6771

6872
/** Event emitted as the user is dragging a draggable item. */
@@ -73,6 +77,8 @@ export interface CdkDragMove<T = any> {
7377
pointerPosition: {x: number, y: number};
7478
/** Native event that is causing the dragging. */
7579
event: MouseEvent | TouchEvent;
80+
/** Distance in pixels that the user has dragged since the drag sequence started. */
81+
distance: {x: number, y: number};
7682
/**
7783
* Indicates the direction in which the user is dragging the element along each axis.
7884
* `1` means that the position is increasing (e.g. the user is moving to the right or downwards),

0 commit comments

Comments
 (0)