@@ -24,6 +24,15 @@ 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
+
27
36
type DDDragEvent = 'drag' | 'dragstart' | 'dragstop' ;
28
37
29
38
// make sure we are not clicking on known object that handles mouseDown
@@ -39,6 +48,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
39
48
/** @internal */
40
49
protected mouseDownEvent : MouseEvent ;
41
50
/** @internal */
51
+ protected dragOffset : DragOffset ;
52
+ /** @internal */
42
53
protected dragElementOriginStyle : Array < string > ;
43
54
/** @internal */
44
55
protected dragEl : HTMLElement ;
@@ -52,7 +63,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
52
63
protected static originStyleProp = [ 'transition' , 'pointerEvents' , 'position' , 'left' , 'top' , 'minWidth' , 'willChange' ] ;
53
64
/** @internal pause before we call the actual drag hit collision code */
54
65
protected dragTimeout : number ;
55
- protected origRelativeMouse : { x : number ; y : number ; } ;
56
66
57
67
constructor ( el : HTMLElement , option : DDDraggableOpt = { } ) {
58
68
super ( ) ;
@@ -195,10 +205,9 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
195
205
} else {
196
206
delete DDManager . dropElement ;
197
207
}
198
- const rect = this . el . getBoundingClientRect ( ) ;
199
- this . origRelativeMouse = { x : s . clientX - rect . left , y : s . clientY - rect . top } ;
200
208
this . helper = this . _createHelper ( e ) ;
201
209
this . _setupHelperContainmentStyle ( ) ;
210
+ this . dragOffset = this . _getDragOffset ( e , this . el , this . helperContainment ) ;
202
211
const ev = Utils . initEvent < DragEvent > ( e , { target : this . el , type : 'dragstart' } ) ;
203
212
204
213
this . _setupHelperStyle ( e ) ;
@@ -276,9 +285,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
276
285
const style = this . helper . style ;
277
286
style . pointerEvents = 'none' ; // needed for over items to get enter/leave
278
287
// 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' ;
282
290
style . willChange = 'left, top' ;
283
291
style . position = 'fixed' ; // let us drag between grids by not clipping as parent .grid-stack is position: 'relative'
284
292
this . _dragFollow ( e ) ; // now position it
@@ -314,19 +322,15 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
314
322
315
323
/** @internal updates the top/left position to follow the mouse */
316
324
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
+ // }
317
330
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' ;
330
334
}
331
335
332
336
/** @internal */
@@ -341,23 +345,51 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
341
345
return this ;
342
346
}
343
347
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
+
344
384
/** @internal TODO: set to public as called by DDDroppable! */
345
385
public ui ( ) : DDUIData {
346
386
const containmentEl = this . el . parentElement ;
347
- const scrollElement = Utils . getScrollElement ( this . el . parentElement ) ;
348
387
const containmentRect = containmentEl . getBoundingClientRect ( ) ;
349
388
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
-
357
389
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
361
393
}
362
394
/* not used by GridStack for now...
363
395
helper: [this.helper], //The object arr representing the helper that's being dragged.
0 commit comments