mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(drag-drop): preserve previous inline transform (#13529)
This commit is contained in:
committed by
Joey Perrott
parent
280b0d6878
commit
cae16b0f85
@@ -144,6 +144,30 @@ describe('CdkDrag', () => {
|
||||
expect(dragElement.style.transform).toBeFalsy();
|
||||
}));
|
||||
|
||||
it('should preserve the previous `transform` value', fakeAsync(() => {
|
||||
const fixture = createComponent(StandaloneDraggable);
|
||||
fixture.detectChanges();
|
||||
const dragElement = fixture.componentInstance.dragElement.nativeElement;
|
||||
|
||||
dragElement.style.transform = 'translateX(-50%)';
|
||||
dragElementViaMouse(fixture, dragElement, 50, 100);
|
||||
expect(dragElement.style.transform).toBe('translateX(-50%) translate3d(50px, 100px, 0px)');
|
||||
}));
|
||||
|
||||
it('should not generate multiple own `translate3d` values', fakeAsync(() => {
|
||||
const fixture = createComponent(StandaloneDraggable);
|
||||
fixture.detectChanges();
|
||||
const dragElement = fixture.componentInstance.dragElement.nativeElement;
|
||||
|
||||
dragElement.style.transform = 'translateY(-50%)';
|
||||
|
||||
dragElementViaMouse(fixture, dragElement, 50, 100);
|
||||
expect(dragElement.style.transform).toBe('translateY(-50%) translate3d(50px, 100px, 0px)');
|
||||
|
||||
dragElementViaMouse(fixture, dragElement, 100, 200);
|
||||
expect(dragElement.style.transform).toBe('translateY(-50%) translate3d(150px, 300px, 0px)');
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
describe('touch dragging', () => {
|
||||
|
||||
+30
-19
@@ -129,6 +129,9 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
/** CSS `transform` that is applied to the element while it's being dragged. */
|
||||
private _activeTransform: Point = {x: 0, y: 0};
|
||||
|
||||
/** Inline `transform` value that the element had before the first dragging sequence. */
|
||||
private _initialTransform?: string;
|
||||
|
||||
/**
|
||||
* Whether the dragging sequence has been started. Doesn't
|
||||
* necessarily mean that the element has been moved.
|
||||
@@ -325,6 +328,12 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the previous transform amount only after the first drag sequence, because
|
||||
// we don't want our own transforms to stack on top of each other.
|
||||
if (this._initialTransform == null) {
|
||||
this._initialTransform = this._rootElement.style.transform || '';
|
||||
}
|
||||
|
||||
this._hasStartedDragging = this._hasMoved = false;
|
||||
this._initialContainer = this.dropContainer;
|
||||
this._pointerMoveSubscription = this._dragDropRegistry.pointerMove.subscribe(this._pointerMove);
|
||||
@@ -373,13 +382,12 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
if (!this._hasStartedDragging) {
|
||||
const distanceX = Math.abs(pointerPosition.x - this._pickupPositionOnPage.x);
|
||||
const distanceY = Math.abs(pointerPosition.y - this._pickupPositionOnPage.y);
|
||||
const minimumDistance = this._config.dragStartThreshold;
|
||||
|
||||
// Only start dragging after the user has moved more than the minimum distance in either
|
||||
// direction. Note that this is preferrable over doing something like `skip(minimumDistance)`
|
||||
// in the `pointerMove` subscription, because we're not guaranteed to have one move event
|
||||
// per pixel of movement (e.g. if the user moves their pointer quickly).
|
||||
if (distanceX + distanceY >= minimumDistance) {
|
||||
if (distanceX + distanceY >= this._config.dragStartThreshold) {
|
||||
this._hasStartedDragging = true;
|
||||
this._ngZone.run(() => this._startDragSequence());
|
||||
}
|
||||
@@ -399,7 +407,11 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
pointerPosition.x - this._pickupPositionOnPage.x + this._passiveTransform.x;
|
||||
activeTransform.y =
|
||||
pointerPosition.y - this._pickupPositionOnPage.y + this._passiveTransform.y;
|
||||
this._setTransform(this._rootElement, activeTransform.x, activeTransform.y);
|
||||
const transform = getTransform(activeTransform.x, activeTransform.y);
|
||||
|
||||
// Preserve the previous `transform` value, if there was one.
|
||||
this._rootElement.style.transform = this._initialTransform ?
|
||||
this._initialTransform + ' ' + transform : transform;
|
||||
}
|
||||
|
||||
// Since this event gets fired for every pixel while dragging, we only
|
||||
@@ -507,9 +519,8 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
this.dropContainer._sortItem(this, x, y, this._pointerDirectionDelta);
|
||||
this._setTransform(this._preview,
|
||||
x - this._pickupPositionInElement.x,
|
||||
y - this._pickupPositionInElement.y);
|
||||
this._preview.style.transform =
|
||||
getTransform(x - this._pickupPositionInElement.x, y - this._pickupPositionInElement.y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,7 +536,8 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
|
||||
preview = viewRef.rootNodes[0];
|
||||
this._previewRef = viewRef;
|
||||
this._setTransform(preview, this._pickupPositionOnPage.x, this._pickupPositionOnPage.y);
|
||||
preview.style.transform =
|
||||
getTransform(this._pickupPositionOnPage.x, this._pickupPositionOnPage.y);
|
||||
} else {
|
||||
const element = this._rootElement;
|
||||
const elementRect = element.getBoundingClientRect();
|
||||
@@ -533,7 +545,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
preview = element.cloneNode(true) as HTMLElement;
|
||||
preview.style.width = `${elementRect.width}px`;
|
||||
preview.style.height = `${elementRect.height}px`;
|
||||
this._setTransform(preview, elementRect.left, elementRect.top);
|
||||
preview.style.transform = getTransform(elementRect.left, elementRect.top);
|
||||
}
|
||||
|
||||
extendStyles(preview.style, {
|
||||
@@ -603,7 +615,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
this._preview.classList.add('cdk-drag-animating');
|
||||
|
||||
// Move the preview to the placeholder position.
|
||||
this._setTransform(this._preview, placeholderRect.left, placeholderRect.top);
|
||||
this._preview.style.transform = getTransform(placeholderRect.left, placeholderRect.top);
|
||||
|
||||
// If the element doesn't have a `transition`, the `transitionend` event won't fire. Since
|
||||
// we need to trigger a style recalculation in order for the `cdk-drag-animating` class to
|
||||
@@ -634,16 +646,6 @@ export class CdkDrag<T = any> implements AfterViewInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the `transform` style on an element.
|
||||
* @param element Element on which to set the transform.
|
||||
* @param x Desired position of the element along the X axis.
|
||||
* @param y Desired position of the element along the Y axis.
|
||||
*/
|
||||
private _setTransform(element: HTMLElement, x: number, y: number) {
|
||||
element.style.transform = `translate3d(${x}px, ${y}px, 0)`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to remove an element from the DOM and to do all the necessary null checks.
|
||||
* @param element Element to be removed.
|
||||
@@ -768,3 +770,12 @@ interface Point {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a 3d `transform` that can be applied to an element.
|
||||
* @param x Desired position of the element along the X axis.
|
||||
* @param y Desired position of the element along the Y axis.
|
||||
*/
|
||||
function getTransform(x: number, y: number): string {
|
||||
return `translate3d(${x}px, ${y}px, 0)`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user