@@ -24,15 +24,6 @@ export interface DDDraggableOpt {
24
24
drag ?: ( event : Event , ui : DDUIData ) => void ;
25
25
}
26
26
27
- interface DragOffset {
28
- left : number ;
29
- top : number ;
30
- width : number ;
31
- height : number ;
32
- offsetLeft : number ;
33
- offsetTop : number ;
34
- }
35
-
36
27
type DDDragEvent = 'drag' | 'dragstart' | 'dragstop' ;
37
28
38
29
// make sure we are not clicking on known object that handles mouseDown
@@ -48,8 +39,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
48
39
/** @internal */
49
40
protected mouseDownEvent : MouseEvent ;
50
41
/** @internal */
51
- protected dragOffset : DragOffset ;
52
- /** @internal */
53
42
protected dragElementOriginStyle : Array < string > ;
54
43
/** @internal */
55
44
protected dragEl : HTMLElement ;
@@ -63,6 +52,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
63
52
protected static originStyleProp = [ 'transition' , 'pointerEvents' , 'position' , 'left' , 'top' , 'minWidth' , 'willChange' ] ;
64
53
/** @internal pause before we call the actual drag hit collision code */
65
54
protected dragTimeout : number ;
55
+ protected origRelativeMouse : { x : number ; y : number ; } ;
66
56
67
57
constructor ( el : HTMLElement , option : DDDraggableOpt = { } ) {
68
58
super ( ) ;
@@ -205,9 +195,10 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
205
195
} else {
206
196
delete DDManager . dropElement ;
207
197
}
198
+ const rect = this . el . getBoundingClientRect ( ) ;
199
+ this . origRelativeMouse = { x : s . clientX - rect . left , y : s . clientY - rect . top } ;
208
200
this . helper = this . _createHelper ( e ) ;
209
201
this . _setupHelperContainmentStyle ( ) ;
210
- this . dragOffset = this . _getDragOffset ( e , this . el , this . helperContainment ) ;
211
202
const ev = Utils . initEvent < DragEvent > ( e , { target : this . el , type : 'dragstart' } ) ;
212
203
213
204
this . _setupHelperStyle ( e ) ;
@@ -285,8 +276,9 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
285
276
const style = this . helper . style ;
286
277
style . pointerEvents = 'none' ; // needed for over items to get enter/leave
287
278
// style.cursor = 'move'; // TODO: can't set with pointerEvents=none ! (done in CSS as well)
288
- style . width = this . dragOffset . width + 'px' ;
289
- style . height = this . dragOffset . height + 'px' ;
279
+ style . width = this . el . offsetWidth + 'px' ;
280
+ style . height = this . el . offsetHeight + 'px' ;
281
+
290
282
style . willChange = 'left, top' ;
291
283
style . position = 'fixed' ; // let us drag between grids by not clipping as parent .grid-stack is position: 'relative'
292
284
this . _dragFollow ( e ) ; // now position it
@@ -322,15 +314,19 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
322
314
323
315
/** @internal updates the top/left position to follow the mouse */
324
316
protected _dragFollow ( e : DragEvent ) : void {
325
- let containmentRect = { left : 0 , top : 0 } ;
326
- // if (this.helper.style.position === 'absolute') { // we use 'fixed'
327
- // const { left, top } = this.helperContainment.getBoundingClientRect();
328
- // containmentRect = { left, top };
329
- // }
330
317
const style = this . helper . style ;
331
- const offset = this . dragOffset ;
332
- style . left = e . clientX + offset . offsetLeft - containmentRect . left + 'px' ;
333
- style . top = e . clientY + offset . offsetTop - containmentRect . top + 'px' ;
318
+ const { scaleX, scaleY } = Utils . getScaleForElement ( this . helper ) ;
319
+ const transformParent = Utils . getContainerForPositionFixedElement ( this . helper ) ;
320
+ const transformParentRect = transformParent . getBoundingClientRect ( ) ;
321
+ // when an element is scaled, the helper is positioned relative to the first transformed parent, so we need to remove the extra offset
322
+ const offsetX = transformParentRect . left ;
323
+ const offsetY = transformParentRect . top ;
324
+
325
+ // Position the element under the mouse
326
+ const x = ( e . clientX - offsetX - ( this . origRelativeMouse ?. x || 0 ) ) / scaleX ;
327
+ const y = ( e . clientY - offsetY - ( this . origRelativeMouse ?. y || 0 ) ) / scaleY ;
328
+ style . left = `${ x } px` ;
329
+ style . top = `${ y } px` ;
334
330
}
335
331
336
332
/** @internal */
@@ -345,51 +341,23 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
345
341
return this ;
346
342
}
347
343
348
- /** @internal */
349
- protected _getDragOffset ( event : DragEvent , el : HTMLElement , parent : HTMLElement ) : DragOffset {
350
-
351
- // in case ancestor has transform/perspective css properties that change the viewpoint
352
- let xformOffsetX = 0 ;
353
- let xformOffsetY = 0 ;
354
- if ( parent ) {
355
- const testEl = document . createElement ( 'div' ) ;
356
- Utils . addElStyles ( testEl , {
357
- opacity : '0' ,
358
- position : 'fixed' ,
359
- top : 0 + 'px' ,
360
- left : 0 + 'px' ,
361
- width : '1px' ,
362
- height : '1px' ,
363
- zIndex : '-999999' ,
364
- } ) ;
365
- parent . appendChild ( testEl ) ;
366
- const testElPosition = testEl . getBoundingClientRect ( ) ;
367
- parent . removeChild ( testEl ) ;
368
- xformOffsetX = testElPosition . left ;
369
- xformOffsetY = testElPosition . top ;
370
- // TODO: scale ?
371
- }
372
-
373
- const targetOffset = el . getBoundingClientRect ( ) ;
374
- return {
375
- left : targetOffset . left ,
376
- top : targetOffset . top ,
377
- offsetLeft : - event . clientX + targetOffset . left - xformOffsetX ,
378
- offsetTop : - event . clientY + targetOffset . top - xformOffsetY ,
379
- width : targetOffset . width ,
380
- height : targetOffset . height
381
- } ;
382
- }
383
-
384
344
/** @internal TODO: set to public as called by DDDroppable! */
385
345
public ui ( ) : DDUIData {
386
346
const containmentEl = this . el . parentElement ;
347
+ const scrollElement = Utils . getScrollElement ( this . el . parentElement ) ;
387
348
const containmentRect = containmentEl . getBoundingClientRect ( ) ;
388
349
const offset = this . helper . getBoundingClientRect ( ) ;
350
+ const { scaleX, scaleY } = Utils . getScaleForElement ( this . helper ) ;
351
+
352
+ // When an element is inside a scrolled element, the boundingClientRect will return the position of the element minus the scroll.
353
+ const parentPositionIncludingScroll = containmentEl === scrollElement
354
+ ? { top : containmentRect . top + scrollElement . scrollTop , left : containmentRect . left + scrollElement . scrollLeft }
355
+ : { top : containmentRect . top , left : containmentRect . left } ;
356
+
389
357
return {
390
- position : { //Current CSS position of the helper as { top, left } object
391
- top : offset . top - containmentRect . top ,
392
- left : offset . left - containmentRect . left
358
+ position : { // Current CSS position of the helper as { top, left } object
359
+ top : ( offset . top - parentPositionIncludingScroll . top ) / scaleY ,
360
+ left : ( offset . left - parentPositionIncludingScroll . left ) / scaleX ,
393
361
}
394
362
/* not used by GridStack for now...
395
363
helper: [this.helper], //The object arr representing the helper that's being dragged.
0 commit comments