@@ -24,6 +24,15 @@ 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+
2736type DDDragEvent = 'drag' | 'dragstart' | 'dragstop' ;
2837
2938// make sure we are not clicking on known object that handles mouseDown
@@ -39,6 +48,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
3948 /** @internal */
4049 protected mouseDownEvent : MouseEvent ;
4150 /** @internal */
51+ protected dragOffset : DragOffset ;
52+ /** @internal */
4253 protected dragElementOriginStyle : Array < string > ;
4354 /** @internal */
4455 protected dragEl : HTMLElement ;
@@ -52,7 +63,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
5263 protected static originStyleProp = [ 'transition' , 'pointerEvents' , 'position' , 'left' , 'top' , 'minWidth' , 'willChange' ] ;
5364 /** @internal pause before we call the actual drag hit collision code */
5465 protected dragTimeout : number ;
55- protected origRelativeMouse : { x : number ; y : number ; } ;
5666
5767 constructor ( el : HTMLElement , option : DDDraggableOpt = { } ) {
5868 super ( ) ;
@@ -195,10 +205,9 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
195205 } else {
196206 delete DDManager . dropElement ;
197207 }
198- const rect = this . el . getBoundingClientRect ( ) ;
199- this . origRelativeMouse = { x : s . clientX - rect . left , y : s . clientY - rect . top } ;
200208 this . helper = this . _createHelper ( e ) ;
201209 this . _setupHelperContainmentStyle ( ) ;
210+ this . dragOffset = this . _getDragOffset ( e , this . el , this . helperContainment ) ;
202211 const ev = Utils . initEvent < DragEvent > ( e , { target : this . el , type : 'dragstart' } ) ;
203212
204213 this . _setupHelperStyle ( e ) ;
@@ -276,9 +285,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
276285 const style = this . helper . style ;
277286 style . pointerEvents = 'none' ; // needed for over items to get enter/leave
278287 // style.cursor = 'move'; // TODO: can't set with pointerEvents=none ! (done in CSS as well)
279- style . width = this . el . offsetWidth + 'px' ;
280- style . height = this . el . offsetHeight + 'px' ;
281-
288+ style . width = this . dragOffset . width + 'px' ;
289+ style . height = this . dragOffset . height + 'px' ;
282290 style . willChange = 'left, top' ;
283291 style . position = 'fixed' ; // let us drag between grids by not clipping as parent .grid-stack is position: 'relative'
284292 this . _dragFollow ( e ) ; // now position it
@@ -314,19 +322,15 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
314322
315323 /** @internal updates the top/left position to follow the mouse */
316324 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+ // }
317330 const style = this . helper . style ;
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` ;
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' ;
330334 }
331335
332336 /** @internal */
@@ -341,23 +345,51 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
341345 return this ;
342346 }
343347
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+
344384 /** @internal TODO: set to public as called by DDDroppable! */
345385 public ui ( ) : DDUIData {
346386 const containmentEl = this . el . parentElement ;
347- const scrollElement = Utils . getScrollElement ( this . el . parentElement ) ;
348387 const containmentRect = containmentEl . getBoundingClientRect ( ) ;
349388 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-
357389 return {
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 ,
390+ position : { //Current CSS position of the helper as { top, left } object
391+ top : offset . top - containmentRect . top ,
392+ left : offset . left - containmentRect . left
361393 }
362394 /* not used by GridStack for now...
363395 helper: [this.helper], //The object arr representing the helper that's being dragged.
0 commit comments