@@ -24,15 +24,6 @@ export interface DDDraggableOpt {
2424 drag ?: ( event : Event , ui : DDUIData ) => void ;
2525}
2626
27- interface DragOffset {
28- left : number ;
29- top : number ;
30- width : number ;
31- height : number ;
32- offsetLeft : number ;
33- offsetTop : number ;
34- }
35-
3627type DDDragEvent = 'drag' | 'dragstart' | 'dragstop' ;
3728
3829// make sure we are not clicking on known object that handles mouseDown
@@ -48,8 +39,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
4839 /** @internal */
4940 protected mouseDownEvent : MouseEvent ;
5041 /** @internal */
51- protected dragOffset : DragOffset ;
52- /** @internal */
5342 protected dragElementOriginStyle : Array < string > ;
5443 /** @internal */
5544 protected dragEl : HTMLElement ;
@@ -63,6 +52,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
6352 protected static originStyleProp = [ 'transition' , 'pointerEvents' , 'position' , 'left' , 'top' , 'minWidth' , 'willChange' ] ;
6453 /** @internal pause before we call the actual drag hit collision code */
6554 protected dragTimeout : number ;
55+ protected origRelativeMouse : { x : number ; y : number ; } ;
6656
6757 constructor ( el : HTMLElement , option : DDDraggableOpt = { } ) {
6858 super ( ) ;
@@ -205,9 +195,10 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
205195 } else {
206196 delete DDManager . dropElement ;
207197 }
198+ const rect = this . el . getBoundingClientRect ( ) ;
199+ this . origRelativeMouse = { x : s . clientX - rect . left , y : s . clientY - rect . top } ;
208200 this . helper = this . _createHelper ( e ) ;
209201 this . _setupHelperContainmentStyle ( ) ;
210- this . dragOffset = this . _getDragOffset ( e , this . el , this . helperContainment ) ;
211202 const ev = Utils . initEvent < DragEvent > ( e , { target : this . el , type : 'dragstart' } ) ;
212203
213204 this . _setupHelperStyle ( e ) ;
@@ -285,8 +276,9 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
285276 const style = this . helper . style ;
286277 style . pointerEvents = 'none' ; // needed for over items to get enter/leave
287278 // 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+
290282 style . willChange = 'left, top' ;
291283 style . position = 'fixed' ; // let us drag between grids by not clipping as parent .grid-stack is position: 'relative'
292284 this . _dragFollow ( e ) ; // now position it
@@ -322,15 +314,19 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
322314
323315 /** @internal updates the top/left position to follow the mouse */
324316 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- // }
330317 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` ;
334330 }
335331
336332 /** @internal */
@@ -345,51 +341,23 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
345341 return this ;
346342 }
347343
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-
384344 /** @internal TODO: set to public as called by DDDroppable! */
385345 public ui ( ) : DDUIData {
386346 const containmentEl = this . el . parentElement ;
347+ const scrollElement = Utils . getScrollElement ( this . el . parentElement ) ;
387348 const containmentRect = containmentEl . getBoundingClientRect ( ) ;
388349 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+
389357 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 ,
393361 }
394362 /* not used by GridStack for now...
395363 helper: [this.helper], //The object arr representing the helper that's being dragged.
0 commit comments