@@ -240,6 +240,9 @@ export class DragRef<T = any> {
240
240
/** Whether the native dragging interactions have been enabled on the root element. */
241
241
private _nativeInteractionsEnabled = true ;
242
242
243
+ /** Client rect of the root element when the dragging sequence has started. */
244
+ private _initialClientRect ?: ClientRect ;
245
+
243
246
/** Cached dimensions of the preview element. Should be read via `_getPreviewRect`. */
244
247
private _previewRect ?: ClientRect ;
245
248
@@ -355,10 +358,14 @@ export class DragRef<T = any> {
355
358
/**
356
359
* Function that can be used to customize the logic of how the position of the drag item
357
360
* is limited while it's being dragged. Gets called with a point containing the current position
358
- * of the user's pointer on the page and should return a point describing where the item should
359
- * be rendered.
361
+ * of the user's pointer on the page, a reference to the item being dragged and its dimenstions.
362
+ * Should return a point describing where the item should be rendered.
360
363
*/
361
- constrainPosition ?: ( point : Point , dragRef : DragRef ) => Point ;
364
+ constrainPosition ?: (
365
+ userPointerPosition : Point ,
366
+ dragRef : DragRef ,
367
+ dimensions : ClientRect ,
368
+ ) => Point ;
362
369
363
370
constructor (
364
371
element : ElementRef < HTMLElement > | HTMLElement ,
@@ -695,12 +702,12 @@ export class DragRef<T = any> {
695
702
if ( this . _dropContainer ) {
696
703
this . _updateActiveDropContainer ( constrainedPointerPosition , pointerPosition ) ;
697
704
} else {
705
+ // If there's a position constraint function, we want the element's top/left to be at the
706
+ // specific position on the page. Use the initial position as a reference if that's the case.
707
+ const offset = this . constrainPosition ? this . _initialClientRect ! : this . _pickupPositionOnPage ;
698
708
const activeTransform = this . _activeTransform ;
699
- activeTransform . x =
700
- constrainedPointerPosition . x - this . _pickupPositionOnPage . x + this . _passiveTransform . x ;
701
- activeTransform . y =
702
- constrainedPointerPosition . y - this . _pickupPositionOnPage . y + this . _passiveTransform . y ;
703
-
709
+ activeTransform . x = constrainedPointerPosition . x - offset . x + this . _passiveTransform . x ;
710
+ activeTransform . y = constrainedPointerPosition . y - offset . y + this . _passiveTransform . y ;
704
711
this . _applyRootElementTransform ( activeTransform . x , activeTransform . y ) ;
705
712
}
706
713
@@ -886,6 +893,7 @@ export class DragRef<T = any> {
886
893
// Avoid multiple subscriptions and memory leaks when multi touch
887
894
// (isDragging check above isn't enough because of possible temporal and/or dimensional delays)
888
895
this . _removeSubscriptions ( ) ;
896
+ this . _initialClientRect = this . _rootElement . getBoundingClientRect ( ) ;
889
897
this . _pointerMoveSubscription = this . _dragDropRegistry . pointerMove . subscribe ( this . _pointerMove ) ;
890
898
this . _pointerUpSubscription = this . _dragDropRegistry . pointerUp . subscribe ( this . _pointerUp ) ;
891
899
this . _scrollSubscription = this . _dragDropRegistry
@@ -903,7 +911,7 @@ export class DragRef<T = any> {
903
911
this . _pickupPositionInElement =
904
912
previewTemplate && previewTemplate . template && ! previewTemplate . matchSize
905
913
? { x : 0 , y : 0 }
906
- : this . _getPointerPositionInElement ( referenceElement , event ) ;
914
+ : this . _getPointerPositionInElement ( this . _initialClientRect , referenceElement , event ) ;
907
915
const pointerPosition =
908
916
( this . _pickupPositionOnPage =
909
917
this . _lastKnownPointerPosition =
@@ -925,7 +933,11 @@ export class DragRef<T = any> {
925
933
926
934
this . _destroyPreview ( ) ;
927
935
this . _destroyPlaceholder ( ) ;
928
- this . _boundaryRect = this . _previewRect = this . _initialTransform = undefined ;
936
+ this . _initialClientRect =
937
+ this . _boundaryRect =
938
+ this . _previewRect =
939
+ this . _initialTransform =
940
+ undefined ;
929
941
930
942
// Re-enter the NgZone since we bound `document` events on the outside.
931
943
this . _ngZone . run ( ( ) => {
@@ -1013,10 +1025,15 @@ export class DragRef<T = any> {
1013
1025
if ( this . isDragging ( ) ) {
1014
1026
this . _dropContainer ! . _startScrollingIfNecessary ( rawX , rawY ) ;
1015
1027
this . _dropContainer ! . _sortItem ( this , x , y , this . _pointerDirectionDelta ) ;
1016
- this . _applyPreviewTransform (
1017
- x - this . _pickupPositionInElement . x ,
1018
- y - this . _pickupPositionInElement . y ,
1019
- ) ;
1028
+
1029
+ if ( this . constrainPosition ) {
1030
+ this . _applyPreviewTransform ( x , y ) ;
1031
+ } else {
1032
+ this . _applyPreviewTransform (
1033
+ x - this . _pickupPositionInElement . x ,
1034
+ y - this . _pickupPositionInElement . y ,
1035
+ ) ;
1036
+ }
1020
1037
}
1021
1038
}
1022
1039
@@ -1033,7 +1050,7 @@ export class DragRef<T = any> {
1033
1050
if ( previewTemplate && previewConfig ) {
1034
1051
// Measure the element before we've inserted the preview
1035
1052
// since the insertion could throw off the measurement.
1036
- const rootRect = previewConfig . matchSize ? this . _rootElement . getBoundingClientRect ( ) : null ;
1053
+ const rootRect = previewConfig . matchSize ? this . _initialClientRect : null ;
1037
1054
const viewRef = previewConfig . viewContainer . createEmbeddedView (
1038
1055
previewTemplate ,
1039
1056
previewConfig . context ,
@@ -1050,9 +1067,8 @@ export class DragRef<T = any> {
1050
1067
) ;
1051
1068
}
1052
1069
} else {
1053
- const element = this . _rootElement ;
1054
- preview = deepCloneNode ( element ) ;
1055
- matchElementSize ( preview , element . getBoundingClientRect ( ) ) ;
1070
+ preview = deepCloneNode ( this . _rootElement ) ;
1071
+ matchElementSize ( preview , this . _initialClientRect ! ) ;
1056
1072
1057
1073
if ( this . _initialTransform ) {
1058
1074
preview . style . transform = this . _initialTransform ;
@@ -1170,10 +1186,10 @@ export class DragRef<T = any> {
1170
1186
* @param event Event that initiated the dragging.
1171
1187
*/
1172
1188
private _getPointerPositionInElement (
1189
+ elementRect : ClientRect ,
1173
1190
referenceElement : HTMLElement ,
1174
1191
event : MouseEvent | TouchEvent ,
1175
1192
) : Point {
1176
- const elementRect = this . _rootElement . getBoundingClientRect ( ) ;
1177
1193
const handleElement = referenceElement === this . _rootElement ? null : referenceElement ;
1178
1194
const referenceRect = handleElement ? handleElement . getBoundingClientRect ( ) : elementRect ;
1179
1195
const point = isTouchEvent ( event ) ? event . targetTouches [ 0 ] : event ;
@@ -1222,7 +1238,9 @@ export class DragRef<T = any> {
1222
1238
/** Gets the pointer position on the page, accounting for any position constraints. */
1223
1239
private _getConstrainedPointerPosition ( point : Point ) : Point {
1224
1240
const dropContainerLock = this . _dropContainer ? this . _dropContainer . lockAxis : null ;
1225
- let { x, y} = this . constrainPosition ? this . constrainPosition ( point , this ) : point ;
1241
+ let { x, y} = this . constrainPosition
1242
+ ? this . constrainPosition ( point , this , this . _initialClientRect ! )
1243
+ : point ;
1226
1244
1227
1245
if ( this . lockAxis === 'x' || dropContainerLock === 'x' ) {
1228
1246
y = this . _pickupPositionOnPage . y ;
@@ -1361,8 +1379,9 @@ export class DragRef<T = any> {
1361
1379
return ;
1362
1380
}
1363
1381
1364
- const boundaryRect = this . _boundaryElement . getBoundingClientRect ( ) ;
1382
+ // Note: don't use `_clientRectAtStart` here, because we want the latest position.
1365
1383
const elementRect = this . _rootElement . getBoundingClientRect ( ) ;
1384
+ const boundaryRect = this . _boundaryElement . getBoundingClientRect ( ) ;
1366
1385
1367
1386
// It's possible that the element got hidden away after dragging (e.g. by switching to a
1368
1387
// different tab). Don't do anything in this case so we don't clear the user's position.
@@ -1511,7 +1530,9 @@ export class DragRef<T = any> {
1511
1530
// Cache the preview element rect if we haven't cached it already or if
1512
1531
// we cached it too early before the element dimensions were computed.
1513
1532
if ( ! this . _previewRect || ( ! this . _previewRect . width && ! this . _previewRect . height ) ) {
1514
- this . _previewRect = ( this . _preview || this . _rootElement ) . getBoundingClientRect ( ) ;
1533
+ this . _previewRect = this . _preview
1534
+ ? this . _preview . getBoundingClientRect ( )
1535
+ : this . _initialClientRect ! ;
1515
1536
}
1516
1537
1517
1538
return this . _previewRect ;
0 commit comments