Skip to content

Commit

Permalink
Merge pull request #2578 from Amdoun/master
Browse files Browse the repository at this point in the history
apply position scaling when acceptwidgets is enabled
  • Loading branch information
adumesny committed Jan 21, 2024
2 parents 2552bc8 + 630d2a6 commit 07c7c67
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 50 deletions.
52 changes: 19 additions & 33 deletions src/dd-draggable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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
Expand All @@ -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<string>;
/** @internal */
protected dragEl: HTMLElement;
Expand All @@ -70,6 +63,13 @@ 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 dragTransform: DragTransform = {
xScale: 1,
yScale: 1,
xOffset: 0,
yOffset: 0
};

constructor(el: HTMLElement, option: DDDraggableOpt = {}) {
super();
Expand Down Expand Up @@ -214,6 +214,9 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt
}
this.helper = this._createHelper(e);
this._setupHelperContainmentStyle();
this.dragTransform = Utils.getValuesFromTransformedElement(
this.helperContainment
);
this.dragOffset = this._getDragOffset(e, this.el, this.helperContainment);
const ev = Utils.initEvent<DragEvent>(e, { target: this.el, type: 'dragstart' });

Expand Down Expand Up @@ -336,8 +339,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 */
Expand All @@ -359,25 +362,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();
Expand All @@ -386,8 +372,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
};
}

Expand All @@ -398,8 +384,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.
Expand Down
18 changes: 3 additions & 15 deletions src/dd-resizable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,22 +226,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 dragTransform = Utils.getValuesFromTransformedElement(parent);
this.rectScale = {
x: 1 / testElPosition.width,
y: 1 / testElPosition.height
x: dragTransform.xScale,
y: dragTransform.yScale
};

if (getComputedStyle(this.el.parentElement).position.match(/static/)) {
Expand Down
48 changes: 46 additions & 2 deletions src/gridstack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, GridStackDroppedHandler, GridStackElementHandler } from './types';
Expand Down Expand Up @@ -261,6 +261,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;

/**
Expand Down Expand Up @@ -2046,11 +2048,29 @@ export class GridStack {
if (!node) return;

helper = helper || el;

// 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 + (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`
}

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 * this.dragTransform.xScale,
left: left * this.dragTransform.yScale
}
};

if (node._temporaryRemoved) {
node.x = Math.max(0, Math.round(left / cellWidth));
Expand Down Expand Up @@ -2406,6 +2426,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;
Expand Down Expand Up @@ -2526,6 +2567,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
Expand Down
34 changes: 34 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -554,6 +561,33 @@ export class Utils {
(target || e.target).dispatchEvent(simulatedEvent);
}

/**
* defines an element that is used to get the offset and scale from grid transforms
* returns the scale and offsets from said element
*/
public static getValuesFromTransformedElement(parent: HTMLElement): DragTransform {
const transformReference = document.createElement('div');
Utils.addElStyles(transformReference, {
opacity: '0',
position: 'fixed',
top: 0 + 'px',
left: 0 + 'px',
width: '1px',
height: '1px',
zIndex: '-999999',
});
parent.appendChild(transformReference);
const transformValues = transformReference.getBoundingClientRect();
parent.removeChild(transformReference);
transformReference.remove();
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)
Expand Down

0 comments on commit 07c7c67

Please sign in to comment.