Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 07c7c67

Browse files
authored
Merge pull request gridstack#2578 from Amdoun/master
apply position scaling when acceptwidgets is enabled
2 parents 2552bc8 + 630d2a6 commit 07c7c67

File tree

4 files changed

+102
-50
lines changed

4 files changed

+102
-50
lines changed

src/dd-draggable.ts

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { DDManager } from './dd-manager';
7-
import { Utils } from './utils';
7+
import { DragTransform, Utils } from './utils';
88
import { DDBaseImplement, HTMLElementExtendOpt } from './dd-base-impl';
99
import { GridItemHTMLElement, DDUIData } from './types';
1010
import { DDElementHost } from './dd-element';
@@ -33,11 +33,6 @@ interface DragOffset {
3333
offsetTop: number;
3434
}
3535

36-
interface DragScaleReciprocal {
37-
x: number;
38-
y: number;
39-
}
40-
4136
type DDDragEvent = 'drag' | 'dragstart' | 'dragstop';
4237

4338
// make sure we are not clicking on known object that handles mouseDown
@@ -55,8 +50,6 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
5550
/** @internal */
5651
protected dragOffset: DragOffset;
5752
/** @internal */
58-
protected dragScale: DragScaleReciprocal = { x: 1, y: 1 };
59-
/** @internal */
6053
protected dragElementOriginStyle: Array<string>;
6154
/** @internal */
6255
protected dragEl: HTMLElement;
@@ -70,6 +63,13 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
7063
protected static originStyleProp = ['transition', 'pointerEvents', 'position', 'left', 'top', 'minWidth', 'willChange'];
7164
/** @internal pause before we call the actual drag hit collision code */
7265
protected dragTimeout: number;
66+
/** @internal */
67+
protected dragTransform: DragTransform = {
68+
xScale: 1,
69+
yScale: 1,
70+
xOffset: 0,
71+
yOffset: 0
72+
};
7373

7474
constructor(el: HTMLElement, option: DDDraggableOpt = {}) {
7575
super();
@@ -214,6 +214,9 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
214214
}
215215
this.helper = this._createHelper(e);
216216
this._setupHelperContainmentStyle();
217+
this.dragTransform = Utils.getValuesFromTransformedElement(
218+
this.helperContainment
219+
);
217220
this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment);
218221
const ev = Utils.initEvent<DragEvent>(e, { target: this.el, type: 'dragstart' });
219222

@@ -336,8 +339,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
336339
// }
337340
const style = this.helper.style;
338341
const offset = this.dragOffset;
339-
style.left = (e.clientX + offset.offsetLeft - containmentRect.left) * this.dragScale.x + 'px';
340-
style.top = (e.clientY + offset.offsetTop - containmentRect.top) * this.dragScale.y + 'px';
342+
style.left = (e.clientX + offset.offsetLeft - containmentRect.left) * this.dragTransform.xScale + 'px';
343+
style.top = (e.clientY + offset.offsetTop - containmentRect.top) * this.dragTransform.yScale + 'px';
341344
}
342345

343346
/** @internal */
@@ -359,25 +362,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
359362
let xformOffsetX = 0;
360363
let xformOffsetY = 0;
361364
if (parent) {
362-
const testEl = document.createElement('div');
363-
Utils.addElStyles(testEl, {
364-
opacity: '0',
365-
position: 'fixed',
366-
top: 0 + 'px',
367-
left: 0 + 'px',
368-
width: '1px',
369-
height: '1px',
370-
zIndex: '-999999',
371-
});
372-
parent.appendChild(testEl);
373-
const testElPosition = testEl.getBoundingClientRect();
374-
parent.removeChild(testEl);
375-
xformOffsetX = testElPosition.left;
376-
xformOffsetY = testElPosition.top;
377-
this.dragScale = {
378-
x: 1 / testElPosition.width,
379-
y: 1 / testElPosition.height
380-
};
365+
xformOffsetX = this.dragTransform.xOffset;
366+
xformOffsetY = this.dragTransform.yOffset;
381367
}
382368

383369
const targetOffset = el.getBoundingClientRect();
@@ -386,8 +372,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
386372
top: targetOffset.top,
387373
offsetLeft: - event.clientX + targetOffset.left - xformOffsetX,
388374
offsetTop: - event.clientY + targetOffset.top - xformOffsetY,
389-
width: targetOffset.width * this.dragScale.x,
390-
height: targetOffset.height * this.dragScale.y
375+
width: targetOffset.width * this.dragTransform.xScale,
376+
height: targetOffset.height * this.dragTransform.yScale
391377
};
392378
}
393379

@@ -398,8 +384,8 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
398384
const offset = this.helper.getBoundingClientRect();
399385
return {
400386
position: { //Current CSS position of the helper as { top, left } object
401-
top: (offset.top - containmentRect.top) * this.dragScale.y,
402-
left: (offset.left - containmentRect.left) * this.dragScale.x
387+
top: (offset.top - containmentRect.top) * this.dragTransform.yScale,
388+
left: (offset.left - containmentRect.left) * this.dragTransform.xScale
403389
}
404390
/* not used by GridStack for now...
405391
helper: [this.helper], //The object arr representing the helper that's being dragged.

src/dd-resizable.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -226,22 +226,10 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt
226226
this.parentOriginStylePosition = this.el.parentElement.style.position;
227227

228228
const parent = this.el.parentElement;
229-
const testEl = document.createElement('div');
230-
Utils.addElStyles(testEl, {
231-
opacity: '0',
232-
position: 'fixed',
233-
top: 0 + 'px',
234-
left: 0 + 'px',
235-
width: '1px',
236-
height: '1px',
237-
zIndex: '-999999',
238-
});
239-
parent.appendChild(testEl);
240-
const testElPosition = testEl.getBoundingClientRect();
241-
parent.removeChild(testEl);
229+
const dragTransform = Utils.getValuesFromTransformedElement(parent);
242230
this.rectScale = {
243-
x: 1 / testElPosition.width,
244-
y: 1 / testElPosition.height
231+
x: dragTransform.xScale,
232+
y: dragTransform.yScale
245233
};
246234

247235
if (getComputedStyle(this.el.parentElement).position.match(/static/)) {

src/gridstack.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* see root license https://github.com/gridstack/gridstack.js/tree/master/LICENSE
77
*/
88
import { GridStackEngine } from './gridstack-engine';
9-
import { Utils, HeightData, obsolete } from './utils';
9+
import { Utils, HeightData, obsolete, DragTransform } from './utils';
1010
import { gridDefaults, ColumnOptions, GridItemHTMLElement, GridStackElement, GridStackEventHandlerCallback,
1111
GridStackNode, GridStackWidget, numberOrString, DDUIData, DDDragInOpt, GridStackPosition, GridStackOptions,
1212
dragInDefaultOptions, GridStackEventHandler, GridStackNodesHandler, AddRemoveFcn, SaveFcn, CompactOptions, GridStackMoveOpts, ResizeToContentFcn, GridStackDroppedHandler, GridStackElementHandler } from './types';
@@ -261,6 +261,8 @@ export class GridStack {
261261
protected _extraDragRow = 0;
262262
/** @internal true if nested grid should get column count from our width */
263263
protected _autoColumn?: boolean;
264+
/** @internal meant to store the scale of the active grid */
265+
protected dragTransform: DragTransform = { xScale: 1, yScale: 1, xOffset: 0, yOffset: 0 };
264266
private _skipInitialResize: boolean;
265267

266268
/**
@@ -2046,11 +2048,29 @@ export class GridStack {
20462048
if (!node) return;
20472049

20482050
helper = helper || el;
2051+
2052+
// if the element is being dragged from outside, scale it down to match the grid's scale
2053+
// and slightly adjust its position relative to the mouse
2054+
if (!node.grid?.el) {
2055+
// this scales the helper down
2056+
helper.style.transform = `scale(${1 / this.dragTransform.xScale},${1 / this.dragTransform.yScale})`;
2057+
// this makes it so that the helper is well positioned relative to the mouse after scaling
2058+
const helperRect = helper.getBoundingClientRect();
2059+
helper.style.left = helperRect.x + (this.dragTransform.xScale - 1) * (event.clientX - helperRect.x) / this.dragTransform.xScale + 'px';
2060+
helper.style.top = helperRect.y + (this.dragTransform.yScale - 1) * (event.clientY - helperRect.y) / this.dragTransform.yScale + 'px';
2061+
helper.style.transformOrigin = `0px 0px`
2062+
}
2063+
20492064
let parent = this.el.getBoundingClientRect();
20502065
let {top, left} = helper.getBoundingClientRect();
20512066
left -= parent.left;
20522067
top -= parent.top;
2053-
let ui: DDUIData = {position: {top, left}};
2068+
let ui: DDUIData = {
2069+
position: {
2070+
top: top * this.dragTransform.xScale,
2071+
left: left * this.dragTransform.yScale
2072+
}
2073+
};
20542074

20552075
if (node._temporaryRemoved) {
20562076
node.x = Math.max(0, Math.round(left / cellWidth));
@@ -2406,6 +2426,27 @@ export class GridStack {
24062426
this.el.appendChild(this.placeholder);
24072427
// console.log('_onStartMoving placeholder') // TEST
24082428

2429+
// if the element is inside a grid, it has already been scaled
2430+
// we can use that as a scale reference
2431+
if (node.grid?.el) {
2432+
this.dragTransform = Utils.getValuesFromTransformedElement(el);
2433+
}
2434+
// if the element is being dragged from outside (not from any grid)
2435+
// we use the grid as the transformation reference, since the helper is not subject to transformation
2436+
else if (this.placeholder && this.placeholder.closest('.grid-stack')) {
2437+
const gridEl = this.placeholder.closest('.grid-stack') as HTMLElement;
2438+
this.dragTransform = Utils.getValuesFromTransformedElement(gridEl);
2439+
}
2440+
// Fallback
2441+
else {
2442+
this.dragTransform = {
2443+
xScale: 1,
2444+
xOffset: 0,
2445+
yScale: 1,
2446+
yOffset: 0,
2447+
}
2448+
}
2449+
24092450
node.el = this.placeholder;
24102451
node._lastUiPosition = ui.position;
24112452
node._prevYPix = ui.position.top;
@@ -2526,6 +2567,9 @@ export class GridStack {
25262567
let node = el.gridstackNode;
25272568
if (!node) return;
25282569

2570+
helper = helper || el;
2571+
// restore the scale of the helper on leave
2572+
helper.style.transform = 'scale(1)';
25292573
dd.off(el, 'drag'); // no need to track while being outside
25302574

25312575
// this gets called when cursor leaves and shape is outside, so only do this once

src/utils.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ export interface HeightData {
1010
unit: string;
1111
}
1212

13+
export interface DragTransform {
14+
xScale: number;
15+
yScale: number;
16+
xOffset: number;
17+
yOffset: number;
18+
}
19+
1320
/** checks for obsolete method names */
1421
// eslint-disable-next-line
1522
export function obsolete(self, f, oldName: string, newName: string, rev: string): (...args: any[]) => any {
@@ -554,6 +561,33 @@ export class Utils {
554561
(target || e.target).dispatchEvent(simulatedEvent);
555562
}
556563

564+
/**
565+
* defines an element that is used to get the offset and scale from grid transforms
566+
* returns the scale and offsets from said element
567+
*/
568+
public static getValuesFromTransformedElement(parent: HTMLElement): DragTransform {
569+
const transformReference = document.createElement('div');
570+
Utils.addElStyles(transformReference, {
571+
opacity: '0',
572+
position: 'fixed',
573+
top: 0 + 'px',
574+
left: 0 + 'px',
575+
width: '1px',
576+
height: '1px',
577+
zIndex: '-999999',
578+
});
579+
parent.appendChild(transformReference);
580+
const transformValues = transformReference.getBoundingClientRect();
581+
parent.removeChild(transformReference);
582+
transformReference.remove();
583+
return {
584+
xScale: 1 / transformValues.width,
585+
yScale: 1 / transformValues.height,
586+
xOffset: transformValues.left,
587+
yOffset: transformValues.top,
588+
}
589+
}
590+
557591
/** returns true if event is inside the given element rectangle */
558592
// Note: Safari Mac has null event.relatedTarget which causes #1684 so check if DragEvent is inside the coordinates instead
559593
// this.el.contains(event.relatedTarget as HTMLElement)

0 commit comments

Comments
 (0)