From c0abba22ac1ef8cb5a5326d395596ffddfcb5c5d Mon Sep 17 00:00:00 2001 From: Mohamed Amdoun Date: Fri, 15 Dec 2023 13:17:49 +0100 Subject: [PATCH 1/4] adjust drag position with scaling when acceptwidgets is true --- src/gridstack.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/gridstack.ts b/src/gridstack.ts index abab38119..80a2e4dcc 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -2030,16 +2030,35 @@ export class GridStack { // vars shared across all methods let cellHeight: number, cellWidth: number; + // creates a reference element for tracking the right position after scaling + const testEl = document.createElement('div'); + Utils.addElStyles(testEl, { + opacity: '0', + position: 'fixed', + top: 0 + 'px', + left: 0 + 'px', + width: '1px', + height: '1px', + zIndex: '-999999', + }); + let onDrag = (event: DragEvent, el: GridItemHTMLElement, helper: GridItemHTMLElement) => { let node = el.gridstackNode; if (!node) return; helper = helper || el; + helper.appendChild(testEl); + const testElPosition = testEl.getBoundingClientRect(); + helper.removeChild(testEl); + const dragScale = { + x: 1 / testElPosition.width, + y: 1 / testElPosition.height, + } let parent = this.el.getBoundingClientRect(); let {top, left} = helper.getBoundingClientRect(); left -= parent.left; top -= parent.top; - let ui: DDUIData = {position: {top, left}}; + let ui: DDUIData = {position: {top: top * dragScale.y, left: left * dragScale.x}}; if (node._temporaryRemoved) { node.x = Math.max(0, Math.round(left / cellWidth)); From bd4e9933b2422722c0ea3903d9bd63f15dd638f3 Mon Sep 17 00:00:00 2001 From: Mohamed Amdoun Date: Sat, 16 Dec 2023 21:49:20 +0100 Subject: [PATCH 2/4] moved scale from ref element functions to utils adjusted position and scale of helper that is dragged from outside --- src/dd-draggable.ts | 56 +++++++++++++++++++-------------------------- src/dd-resizable.ts | 21 +++++------------ src/gridstack.ts | 55 +++++++++++++++++++++++++++++--------------- src/utils.ts | 41 +++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 66 deletions(-) diff --git a/src/dd-draggable.ts b/src/dd-draggable.ts index cef086888..875926254 100644 --- a/src/dd-draggable.ts +++ b/src/dd-draggable.ts @@ -4,7 +4,7 @@ */ import { DDManager } from './dd-manager'; -import { Utils } from './utils'; +import { DragTransform, Utils } from './utils'; import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl'; import { GridItemHTMLElement, DDUIData } from './types'; import { DDElementHost } from './dd-element'; @@ -33,11 +33,6 @@ interface DragOffset { offsetTop: number; } -interface DragScaleReciprocal { - x: number; - y: number; -} - type DDDragEvent = 'drag' | 'dragstart' | 'dragstop'; // make sure we are not clicking on known object that handles mouseDown @@ -55,8 +50,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt /** @internal */ protected dragOffset: DragOffset; /** @internal */ - protected dragScale: DragScaleReciprocal = { x: 1, y: 1 }; - /** @internal */ protected dragElementOriginStyle: Array; /** @internal */ protected dragEl: HTMLElement; @@ -70,6 +63,15 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt protected static originStyleProp = ['transition', 'pointerEvents', 'position', 'left', 'top', 'minWidth', 'willChange']; /** @internal pause before we call the actual drag hit collision code */ protected dragTimeout: number; + /** @internal */ + protected transformReference: HTMLElement; + /** @internal */ + protected dragTransform: DragTransform = { + xScale: 1, + yScale: 1, + xOffset: 0, + yOffset: 0 + }; constructor(el: HTMLElement, option: DDDraggableOpt = {}) { super(); @@ -79,6 +81,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt // get the element that is actually supposed to be dragged by let handleName = option.handle.substring(1); this.dragEl = el.classList.contains(handleName) ? el : el.querySelector(option.handle) || el; + this.transformReference = Utils.createTransformReferenceElement(); // create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions) this._mouseDown = this._mouseDown.bind(this); this._mouseMove = this._mouseMove.bind(this); @@ -214,6 +217,10 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } this.helper = this._createHelper(e); this._setupHelperContainmentStyle(); + this.dragTransform = Utils.getValuesFromTransformedElement( + this.transformReference, + this.helperContainment + ); this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment); const ev = Utils.initEvent(e, { target: this.el, type: 'dragstart' }); @@ -336,8 +343,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt // } const style = this.helper.style; const offset = this.dragOffset; - style.left = (e.clientX + offset.offsetLeft - containmentRect.left) * this.dragScale.x + 'px'; - style.top = (e.clientY + offset.offsetTop - containmentRect.top) * this.dragScale.y + 'px'; + style.left = (e.clientX + offset.offsetLeft - containmentRect.left) * this.dragTransform.xScale + 'px'; + style.top = (e.clientY + offset.offsetTop - containmentRect.top) * this.dragTransform.yScale + 'px'; } /** @internal */ @@ -359,25 +366,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt let xformOffsetX = 0; let xformOffsetY = 0; if (parent) { - const testEl = document.createElement('div'); - Utils.addElStyles(testEl, { - opacity: '0', - position: 'fixed', - top: 0 + 'px', - left: 0 + 'px', - width: '1px', - height: '1px', - zIndex: '-999999', - }); - parent.appendChild(testEl); - const testElPosition = testEl.getBoundingClientRect(); - parent.removeChild(testEl); - xformOffsetX = testElPosition.left; - xformOffsetY = testElPosition.top; - this.dragScale = { - x: 1 / testElPosition.width, - y: 1 / testElPosition.height - }; + xformOffsetX = this.dragTransform.xOffset; + xformOffsetY = this.dragTransform.yOffset; } const targetOffset = el.getBoundingClientRect(); @@ -386,8 +376,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt top: targetOffset.top, offsetLeft: - event.clientX + targetOffset.left - xformOffsetX, offsetTop: - event.clientY + targetOffset.top - xformOffsetY, - width: targetOffset.width * this.dragScale.x, - height: targetOffset.height * this.dragScale.y + width: targetOffset.width * this.dragTransform.xScale, + height: targetOffset.height * this.dragTransform.yScale }; } @@ -398,8 +388,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt const offset = this.helper.getBoundingClientRect(); return { position: { //Current CSS position of the helper as { top, left } object - top: (offset.top - containmentRect.top) * this.dragScale.y, - left: (offset.left - containmentRect.left) * this.dragScale.x + top: (offset.top - containmentRect.top) * this.dragTransform.yScale, + left: (offset.left - containmentRect.left) * this.dragTransform.xScale } /* not used by GridStack for now... helper: [this.helper], //The object arr representing the helper that's being dragged. diff --git a/src/dd-resizable.ts b/src/dd-resizable.ts index 478f28aa6..e82c85f81 100644 --- a/src/dd-resizable.ts +++ b/src/dd-resizable.ts @@ -57,11 +57,14 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt protected parentOriginStylePosition: string; /** @internal */ protected static _originStyleProp = ['width', 'height', 'position', 'left', 'top', 'opacity', 'zIndex']; + /** @internal */ + protected transformReference: HTMLElement; constructor(el: HTMLElement, opts: DDResizableOpt = {}) { super(); this.el = el; this.option = opts; + this.transformReference = Utils.createTransformReferenceElement(); // create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions) this._mouseOver = this._mouseOver.bind(this); this._mouseOut = this._mouseOut.bind(this); @@ -226,22 +229,10 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt this.parentOriginStylePosition = this.el.parentElement.style.position; const parent = this.el.parentElement; - const testEl = document.createElement('div'); - Utils.addElStyles(testEl, { - opacity: '0', - position: 'fixed', - top: 0 + 'px', - left: 0 + 'px', - width: '1px', - height: '1px', - zIndex: '-999999', - }); - parent.appendChild(testEl); - const testElPosition = testEl.getBoundingClientRect(); - parent.removeChild(testEl); + const transformValues = Utils.getValuesFromTransformedElement(this.transformReference, parent); this.rectScale = { - x: 1 / testElPosition.width, - y: 1 / testElPosition.height + x: transformValues.xScale, + y: transformValues.yScale }; if (getComputedStyle(this.el.parentElement).position.match(/static/)) { diff --git a/src/gridstack.ts b/src/gridstack.ts index 80a2e4dcc..9ea9968fe 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -6,7 +6,7 @@ * see root license https://github.com/gridstack/gridstack.js/tree/master/LICENSE */ import { GridStackEngine } from './gridstack-engine'; -import { Utils, HeightData, obsolete } from './utils'; +import { Utils, HeightData, obsolete, DragTransform } from './utils'; import { gridDefaults, ColumnOptions, GridItemHTMLElement, GridStackElement, GridStackEventHandlerCallback, GridStackNode, GridStackWidget, numberOrString, DDUIData, DDDragInOpt, GridStackPosition, GridStackOptions, dragInDefaultOptions, GridStackEventHandler, GridStackNodesHandler, AddRemoveFcn, SaveFcn, CompactOptions, GridStackMoveOpts, ResizeToContentFcn } from './types'; @@ -2031,34 +2031,50 @@ export class GridStack { let cellHeight: number, cellWidth: number; // creates a reference element for tracking the right position after scaling - const testEl = document.createElement('div'); - Utils.addElStyles(testEl, { - opacity: '0', - position: 'fixed', - top: 0 + 'px', - left: 0 + 'px', - width: '1px', - height: '1px', - zIndex: '-999999', - }); + const transformReference = Utils.createTransformReferenceElement(); let onDrag = (event: DragEvent, el: GridItemHTMLElement, helper: GridItemHTMLElement) => { let node = el.gridstackNode; if (!node) return; helper = helper || el; - helper.appendChild(testEl); - const testElPosition = testEl.getBoundingClientRect(); - helper.removeChild(testEl); - const dragScale = { - x: 1 / testElPosition.width, - y: 1 / testElPosition.height, + let transformValues: DragTransform; + // if we are dragging an element in and out that is coming from a grid + // we get the transform values by using the helper attached to the grid + if (node.grid?.el) { + transformValues = Utils.getValuesFromTransformedElement(transformReference, helper) + } + // if the element is being dragged from outside (not from any grid) + // we use the grid as the transformation reference, since the helper is not subject to transformation + else if (this._placeholder && this._placeholder.closest('.grid-stack')) { + const gridEl = this._placeholder.closest('.grid-stack') as HTMLElement; + transformValues = Utils.getValuesFromTransformedElement(transformReference, gridEl); + // if the element is being dragged from outside, scale it down to match the grid's scale + helper.style.transform = `scale(${1 / transformValues.xScale},${1 / transformValues.yScale})`; + // this makes it so that the helper is well positioned relative to the mouse after scaling + const helperRect = helper.getBoundingClientRect(); + helper.style.left = helperRect.x + (transformValues.xScale - 1) * (event.clientX - helperRect.x) / transformValues.xScale + 'px'; + helper.style.top = helperRect.y + (transformValues.yScale - 1) * (event.clientY - helperRect.y) / transformValues.yScale + 'px'; + helper.style.transformOrigin = `0px 0px` + } // if all else fails, we might want to use the default transform value + else { + transformValues = { + xScale: 1, + xOffset: 0, + yScale: 1, + yOffset: 0, + } } let parent = this.el.getBoundingClientRect(); let {top, left} = helper.getBoundingClientRect(); left -= parent.left; top -= parent.top; - let ui: DDUIData = {position: {top: top * dragScale.y, left: left * dragScale.x}}; + let ui: DDUIData = { + position: { + top: top * transformValues.xScale, + left: left * transformValues.yScale + } + }; if (node._temporaryRemoved) { node.x = Math.max(0, Math.round(left / cellWidth)); @@ -2534,6 +2550,9 @@ export class GridStack { let node = el.gridstackNode; if (!node) return; + helper = helper || el; + // restore the scale of the helper on leave + helper.style.transform = 'scale(1)'; dd.off(el, 'drag'); // no need to track while being outside // this gets called when cursor leaves and shape is outside, so only do this once diff --git a/src/utils.ts b/src/utils.ts index 46358d5ef..8a7ca76b7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -10,6 +10,13 @@ export interface HeightData { unit: string; } +export interface DragTransform { + xScale: number; + yScale: number; + xOffset: number; + yOffset: number; +} + /** checks for obsolete method names */ // eslint-disable-next-line export function obsolete(self, f, oldName: string, newName: string, rev: string): (...args: any[]) => any { @@ -554,6 +561,40 @@ export class Utils { (target || e.target).dispatchEvent(simulatedEvent); } + /** + * defines an element that is used to get the offset and scale from grid transforms + * has to be hooked to a helper + * should be called once + */ + public static createTransformReferenceElement(): HTMLElement { + const transformReference = document.createElement('div'); + Utils.addElStyles(transformReference, { + opacity: '0', + position: 'fixed', + top: 0 + 'px', + left: 0 + 'px', + width: '1px', + height: '1px', + zIndex: '-999999', + }); + return transformReference; + } + + /** + * can be used after setting the reference element from createTransformReferenceElement + */ + public static getValuesFromTransformedElement(transformReference: HTMLElement, helper: HTMLElement): DragTransform { + helper.appendChild(transformReference); + const transformValues = transformReference.getBoundingClientRect(); + helper.removeChild(transformReference); + return { + xScale: 1 / transformValues.width, + yScale: 1 / transformValues.height, + xOffset: transformValues.left, + yOffset: transformValues.top, + } + } + /** returns true if event is inside the given element rectangle */ // Note: Safari Mac has null event.relatedTarget which causes #1684 so check if DragEvent is inside the coordinates instead // this.el.contains(event.relatedTarget as HTMLElement) From baf8cd06cb5f7b24206c47abd71870dccaa77f01 Mon Sep 17 00:00:00 2001 From: Mohamed Amdoun Date: Sun, 17 Dec 2023 20:25:37 +0100 Subject: [PATCH 3/4] changed getValuesFromTransformedElement signature removed createTransformReferenceElement --- src/dd-draggable.ts | 4 ---- src/dd-resizable.ts | 5 +---- src/gridstack.ts | 7 ++----- src/utils.ts | 17 +++++------------ 4 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/dd-draggable.ts b/src/dd-draggable.ts index 875926254..6592ec00e 100644 --- a/src/dd-draggable.ts +++ b/src/dd-draggable.ts @@ -64,8 +64,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt /** @internal pause before we call the actual drag hit collision code */ protected dragTimeout: number; /** @internal */ - protected transformReference: HTMLElement; - /** @internal */ protected dragTransform: DragTransform = { xScale: 1, yScale: 1, @@ -81,7 +79,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt // get the element that is actually supposed to be dragged by let handleName = option.handle.substring(1); this.dragEl = el.classList.contains(handleName) ? el : el.querySelector(option.handle) || el; - this.transformReference = Utils.createTransformReferenceElement(); // create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions) this._mouseDown = this._mouseDown.bind(this); this._mouseMove = this._mouseMove.bind(this); @@ -218,7 +215,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt this.helper = this._createHelper(e); this._setupHelperContainmentStyle(); this.dragTransform = Utils.getValuesFromTransformedElement( - this.transformReference, this.helperContainment ); this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment); diff --git a/src/dd-resizable.ts b/src/dd-resizable.ts index e82c85f81..fbcbfa902 100644 --- a/src/dd-resizable.ts +++ b/src/dd-resizable.ts @@ -57,14 +57,11 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt protected parentOriginStylePosition: string; /** @internal */ protected static _originStyleProp = ['width', 'height', 'position', 'left', 'top', 'opacity', 'zIndex']; - /** @internal */ - protected transformReference: HTMLElement; constructor(el: HTMLElement, opts: DDResizableOpt = {}) { super(); this.el = el; this.option = opts; - this.transformReference = Utils.createTransformReferenceElement(); // create var event binding so we can easily remove and still look like TS methods (unlike anonymous functions) this._mouseOver = this._mouseOver.bind(this); this._mouseOut = this._mouseOut.bind(this); @@ -229,7 +226,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt this.parentOriginStylePosition = this.el.parentElement.style.position; const parent = this.el.parentElement; - const transformValues = Utils.getValuesFromTransformedElement(this.transformReference, parent); + const transformValues = Utils.getValuesFromTransformedElement(parent); this.rectScale = { x: transformValues.xScale, y: transformValues.yScale diff --git a/src/gridstack.ts b/src/gridstack.ts index 9ea9968fe..ff3676808 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -2030,9 +2030,6 @@ export class GridStack { // vars shared across all methods let cellHeight: number, cellWidth: number; - // creates a reference element for tracking the right position after scaling - const transformReference = Utils.createTransformReferenceElement(); - let onDrag = (event: DragEvent, el: GridItemHTMLElement, helper: GridItemHTMLElement) => { let node = el.gridstackNode; if (!node) return; @@ -2042,13 +2039,13 @@ export class GridStack { // if we are dragging an element in and out that is coming from a grid // we get the transform values by using the helper attached to the grid if (node.grid?.el) { - transformValues = Utils.getValuesFromTransformedElement(transformReference, helper) + transformValues = Utils.getValuesFromTransformedElement(helper) } // if the element is being dragged from outside (not from any grid) // we use the grid as the transformation reference, since the helper is not subject to transformation else if (this._placeholder && this._placeholder.closest('.grid-stack')) { const gridEl = this._placeholder.closest('.grid-stack') as HTMLElement; - transformValues = Utils.getValuesFromTransformedElement(transformReference, gridEl); + transformValues = Utils.getValuesFromTransformedElement(gridEl); // if the element is being dragged from outside, scale it down to match the grid's scale helper.style.transform = `scale(${1 / transformValues.xScale},${1 / transformValues.yScale})`; // this makes it so that the helper is well positioned relative to the mouse after scaling diff --git a/src/utils.ts b/src/utils.ts index 8a7ca76b7..15849a5ec 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -563,10 +563,9 @@ export class Utils { /** * defines an element that is used to get the offset and scale from grid transforms - * has to be hooked to a helper - * should be called once + * returns the scale and offsets from said element */ - public static createTransformReferenceElement(): HTMLElement { + public static getValuesFromTransformedElement(parent: HTMLElement): DragTransform { const transformReference = document.createElement('div'); Utils.addElStyles(transformReference, { opacity: '0', @@ -577,16 +576,10 @@ export class Utils { height: '1px', zIndex: '-999999', }); - return transformReference; - } - - /** - * can be used after setting the reference element from createTransformReferenceElement - */ - public static getValuesFromTransformedElement(transformReference: HTMLElement, helper: HTMLElement): DragTransform { - helper.appendChild(transformReference); + parent.appendChild(transformReference); const transformValues = transformReference.getBoundingClientRect(); - helper.removeChild(transformReference); + parent.removeChild(transformReference); + transformReference.remove(); return { xScale: 1 / transformValues.width, yScale: 1 / transformValues.height, From 630d2a6239f3d4382e59f16453423ec2446de5e4 Mon Sep 17 00:00:00 2001 From: Mohamed Amdoun Date: Sat, 6 Jan 2024 20:58:01 +0100 Subject: [PATCH 4/4] dragtransform only calculated on start in gridstack.ts --- src/dd-resizable.ts | 6 ++--- src/gridstack.ts | 59 ++++++++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/dd-resizable.ts b/src/dd-resizable.ts index fbcbfa902..8afafb16a 100644 --- a/src/dd-resizable.ts +++ b/src/dd-resizable.ts @@ -226,10 +226,10 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt this.parentOriginStylePosition = this.el.parentElement.style.position; const parent = this.el.parentElement; - const transformValues = Utils.getValuesFromTransformedElement(parent); + const dragTransform = Utils.getValuesFromTransformedElement(parent); this.rectScale = { - x: transformValues.xScale, - y: transformValues.yScale + x: dragTransform.xScale, + y: dragTransform.yScale }; if (getComputedStyle(this.el.parentElement).position.match(/static/)) { diff --git a/src/gridstack.ts b/src/gridstack.ts index ff3676808..7306af879 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -259,6 +259,8 @@ export class GridStack { protected _extraDragRow = 0; /** @internal true if nested grid should get column count from our width */ protected _autoColumn?: boolean; + /** @internal meant to store the scale of the active grid */ + protected dragTransform: DragTransform = { xScale: 1, yScale: 1, xOffset: 0, yOffset: 0 }; private _skipInitialResize: boolean; /** @@ -2035,41 +2037,27 @@ export class GridStack { if (!node) return; helper = helper || el; - let transformValues: DragTransform; - // if we are dragging an element in and out that is coming from a grid - // we get the transform values by using the helper attached to the grid - if (node.grid?.el) { - transformValues = Utils.getValuesFromTransformedElement(helper) - } - // if the element is being dragged from outside (not from any grid) - // we use the grid as the transformation reference, since the helper is not subject to transformation - else if (this._placeholder && this._placeholder.closest('.grid-stack')) { - const gridEl = this._placeholder.closest('.grid-stack') as HTMLElement; - transformValues = Utils.getValuesFromTransformedElement(gridEl); - // if the element is being dragged from outside, scale it down to match the grid's scale - helper.style.transform = `scale(${1 / transformValues.xScale},${1 / transformValues.yScale})`; + + // if the element is being dragged from outside, scale it down to match the grid's scale + // and slightly adjust its position relative to the mouse + if (!node.grid?.el) { + // this scales the helper down + helper.style.transform = `scale(${1 / this.dragTransform.xScale},${1 / this.dragTransform.yScale})`; // this makes it so that the helper is well positioned relative to the mouse after scaling const helperRect = helper.getBoundingClientRect(); - helper.style.left = helperRect.x + (transformValues.xScale - 1) * (event.clientX - helperRect.x) / transformValues.xScale + 'px'; - helper.style.top = helperRect.y + (transformValues.yScale - 1) * (event.clientY - helperRect.y) / transformValues.yScale + 'px'; + helper.style.left = helperRect.x + (this.dragTransform.xScale - 1) * (event.clientX - helperRect.x) / this.dragTransform.xScale + 'px'; + helper.style.top = helperRect.y + (this.dragTransform.yScale - 1) * (event.clientY - helperRect.y) / this.dragTransform.yScale + 'px'; helper.style.transformOrigin = `0px 0px` - } // if all else fails, we might want to use the default transform value - else { - transformValues = { - xScale: 1, - xOffset: 0, - yScale: 1, - yOffset: 0, - } } + let parent = this.el.getBoundingClientRect(); let {top, left} = helper.getBoundingClientRect(); left -= parent.left; top -= parent.top; let ui: DDUIData = { position: { - top: top * transformValues.xScale, - left: left * transformValues.yScale + top: top * this.dragTransform.xScale, + left: left * this.dragTransform.yScale } }; @@ -2427,6 +2415,27 @@ export class GridStack { this.el.appendChild(this.placeholder); // console.log('_onStartMoving placeholder') // TEST + // if the element is inside a grid, it has already been scaled + // we can use that as a scale reference + if (node.grid?.el) { + this.dragTransform = Utils.getValuesFromTransformedElement(el); + } + // if the element is being dragged from outside (not from any grid) + // we use the grid as the transformation reference, since the helper is not subject to transformation + else if (this.placeholder && this.placeholder.closest('.grid-stack')) { + const gridEl = this.placeholder.closest('.grid-stack') as HTMLElement; + this.dragTransform = Utils.getValuesFromTransformedElement(gridEl); + } + // Fallback + else { + this.dragTransform = { + xScale: 1, + xOffset: 0, + yScale: 1, + yOffset: 0, + } + } + node.el = this.placeholder; node._lastUiPosition = ui.position; node._prevYPix = ui.position.top;