Skip to content

Commit 84a2366

Browse files
authored
fix(cdk/drag-drop): use consistent touch coordinates for bounded dragging (#33928)
1 parent f6c2a19 commit 84a2366

2 files changed

Lines changed: 28 additions & 3 deletions

File tree

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,30 @@ describe('Standalone CdkDrag', () => {
10521052
expect(dragElement.style.transform).toBe('translate3d(100px, 100px, 0px)');
10531053
});
10541054

1055+
it('should keep a touch drag within its boundary when another target is already touched', () => {
1056+
const fixture = createComponent(StandaloneDraggable);
1057+
fixture.componentInstance.boundary = '.wrapper';
1058+
fixture.detectChanges();
1059+
const dragElement = fixture.componentInstance.dragElement.nativeElement;
1060+
const rect = dragElement.getBoundingClientRect();
1061+
const outsideTouch = {pageX: rect.left + 400, pageY: rect.top + 400, identifier: 0};
1062+
1063+
const dispatchDragTouch = (type: string, x: number, y: number) => {
1064+
const event = createTouchEvent(type, x, y);
1065+
const touch = (event as TouchEvent).targetTouches[0];
1066+
Object.defineProperty(event, 'touches', {get: () => [outsideTouch, touch]});
1067+
dispatchEvent(dragElement, event);
1068+
fixture.detectChanges();
1069+
};
1070+
1071+
dispatchDragTouch('touchstart', rect.left + 10, rect.top + 10);
1072+
dispatchDragTouch('touchmove', rect.left + 310, rect.top + 310);
1073+
dispatchDragTouch('touchmove', rect.left + 310, rect.top + 310);
1074+
dispatchDragTouch('touchend', rect.left + 310, rect.top + 310);
1075+
1076+
expect(dragElement.style.transform).toBe('translate3d(100px, 100px, 0px)');
1077+
});
1078+
10551079
it('should allow for dragging to be constrained to an element while using constrainPosition', () => {
10561080
const fixture = createComponent(StandaloneDraggable);
10571081
fixture.componentInstance.boundary = '.wrapper';

‎src/cdk/drag-drop/drag-ref.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,14 +1269,15 @@ export class DragRef<T = any> {
12691269
private _getPointerPositionOnPage(event: MouseEvent | TouchEvent): Point {
12701270
const scrollPosition = this._getViewportScrollPosition();
12711271
const point = isTouchEvent(event)
1272-
? // `touches` will be empty for start/end events so we have to fall back to `changedTouches`.
1273-
// Also note that on real devices we're guaranteed for either `touches` or `changedTouches`
1272+
? // Use the same target touch as the pickup offset when multiple elements are touched.
1273+
// `targetTouches` can be empty for end events, so fall back to `changedTouches`.
1274+
// Also note that on real devices either `targetTouches` or `changedTouches` is guaranteed
12741275
// to have a value, but Firefox in device emulation mode has a bug where both can be empty
12751276
// for `touchstart` and `touchend` so we fall back to a dummy object in order to avoid
12761277
// throwing an error. The value returned here will be incorrect, but since this only
12771278
// breaks inside a developer tool and the value is only used for secondary information,
12781279
// we can get away with it. See https://bugzilla.mozilla.org/show_bug.cgi?id=1615824.
1279-
event.touches[0] || event.changedTouches[0] || {pageX: 0, pageY: 0}
1280+
event.targetTouches[0] || event.changedTouches[0] || {pageX: 0, pageY: 0}
12801281
: event;
12811282

12821283
const x = point.pageX - scrollPosition.left;

0 commit comments

Comments
 (0)