@@ -14,7 +14,12 @@ import {coerceBooleanProperty, coerceElement} from '@angular/cdk/coercion';
14
14
import { Subscription , Subject , Observable } from 'rxjs' ;
15
15
import { DropListRefInternal as DropListRef } from './drop-list-ref' ;
16
16
import { DragDropRegistry } from './drag-drop-registry' ;
17
- import { extendStyles , toggleNativeDragInteractions , toggleVisibility } from './drag-styling' ;
17
+ import {
18
+ combineTransforms ,
19
+ extendStyles ,
20
+ toggleNativeDragInteractions ,
21
+ toggleVisibility ,
22
+ } from './drag-styling' ;
18
23
import { getTransformTransitionDurationInMs } from './transition-duration' ;
19
24
import { getMutableClientRect , adjustClientRect } from './client-rect' ;
20
25
import { ParentPositionTracker } from './parent-position-tracker' ;
@@ -792,7 +797,6 @@ export class DragRef<T = any> {
792
797
if ( dropContainer ) {
793
798
const element = this . _rootElement ;
794
799
const parent = element . parentNode as HTMLElement ;
795
- const preview = this . _preview = this . _createPreviewElement ( ) ;
796
800
const placeholder = this . _placeholder = this . _createPlaceholderElement ( ) ;
797
801
const anchor = this . _anchor = this . _anchor || this . _document . createComment ( '' ) ;
798
802
@@ -802,12 +806,20 @@ export class DragRef<T = any> {
802
806
// Insert an anchor node so that we can restore the element's position in the DOM.
803
807
parent . insertBefore ( anchor , element ) ;
804
808
809
+ // There's no risk of transforms stacking when inside a drop container so
810
+ // we can keep the initial transform up to date any time dragging starts.
811
+ this . _initialTransform = element . style . transform || '' ;
812
+
813
+ // Create the preview after the initial transform has
814
+ // been cached, because it can be affected by the transform.
815
+ this . _preview = this . _createPreviewElement ( ) ;
816
+
805
817
// We move the element out at the end of the body and we make it hidden, because keeping it in
806
818
// place will throw off the consumer's `:last-child` selectors. We can't remove the element
807
819
// from the DOM completely, because iOS will stop firing all subsequent events in the chain.
808
820
toggleVisibility ( element , false ) ;
809
821
this . _document . body . appendChild ( parent . replaceChild ( placeholder , element ) ) ;
810
- this . _getPreviewInsertionPoint ( parent , shadowRoot ) . appendChild ( preview ) ;
822
+ this . _getPreviewInsertionPoint ( parent , shadowRoot ) . appendChild ( this . _preview ) ;
811
823
this . started . next ( { source : this } ) ; // Emit before notifying the container.
812
824
dropContainer . start ( ) ;
813
825
this . _initialContainer = dropContainer ;
@@ -906,7 +918,7 @@ export class DragRef<T = any> {
906
918
907
919
this . _destroyPreview ( ) ;
908
920
this . _destroyPlaceholder ( ) ;
909
- this . _boundaryRect = this . _previewRect = undefined ;
921
+ this . _boundaryRect = this . _previewRect = this . _initialTransform = undefined ;
910
922
911
923
// Re-enter the NgZone since we bound `document` events on the outside.
912
924
this . _ngZone . run ( ( ) => {
@@ -972,8 +984,8 @@ export class DragRef<T = any> {
972
984
973
985
this . _dropContainer ! . _startScrollingIfNecessary ( rawX , rawY ) ;
974
986
this . _dropContainer ! . _sortItem ( this , x , y , this . _pointerDirectionDelta ) ;
975
- this . _preview . style . transform =
976
- getTransform ( x - this . _pickupPositionInElement . x , y - this . _pickupPositionInElement . y ) ;
987
+ this . _applyPreviewTransform (
988
+ x - this . _pickupPositionInElement . x , y - this . _pickupPositionInElement . y ) ;
977
989
}
978
990
979
991
/**
@@ -1005,6 +1017,10 @@ export class DragRef<T = any> {
1005
1017
const element = this . _rootElement ;
1006
1018
preview = deepCloneNode ( element ) ;
1007
1019
matchElementSize ( preview , element . getBoundingClientRect ( ) ) ;
1020
+
1021
+ if ( this . _initialTransform ) {
1022
+ preview . style . transform = this . _initialTransform ;
1023
+ }
1008
1024
}
1009
1025
1010
1026
extendStyles ( preview . style , {
@@ -1050,7 +1066,7 @@ export class DragRef<T = any> {
1050
1066
this . _preview . classList . add ( 'cdk-drag-animating' ) ;
1051
1067
1052
1068
// Move the preview to the placeholder position.
1053
- this . _preview . style . transform = getTransform ( placeholderRect . left , placeholderRect . top ) ;
1069
+ this . _applyPreviewTransform ( placeholderRect . left , placeholderRect . top ) ;
1054
1070
1055
1071
// If the element doesn't have a `transition`, the `transitionend` event won't fire. Since
1056
1072
// we need to trigger a style recalculation in order for the `cdk-drag-animating` class to
@@ -1247,8 +1263,20 @@ export class DragRef<T = any> {
1247
1263
// Preserve the previous `transform` value, if there was one. Note that we apply our own
1248
1264
// transform before the user's, because things like rotation can affect which direction
1249
1265
// the element will be translated towards.
1250
- this . _rootElement . style . transform = this . _initialTransform ?
1251
- transform + ' ' + this . _initialTransform : transform ;
1266
+ this . _rootElement . style . transform = combineTransforms ( transform , this . _initialTransform ) ;
1267
+ }
1268
+
1269
+ /**
1270
+ * Applies a `transform` to the preview, taking into account any existing transforms on it.
1271
+ * @param x New transform value along the X axis.
1272
+ * @param y New transform value along the Y axis.
1273
+ */
1274
+ private _applyPreviewTransform ( x : number , y : number ) {
1275
+ // Only apply the initial transform if the preview is a clone of the original element, otherwise
1276
+ // it could be completely different and the transform might not make sense anymore.
1277
+ const initialTransform = this . _previewTemplate ?. template ? undefined : this . _initialTransform ;
1278
+ const transform = getTransform ( x , y ) ;
1279
+ this . _preview . style . transform = combineTransforms ( transform , initialTransform ) ;
1252
1280
}
1253
1281
1254
1282
/**
0 commit comments