feat: implement DeesDashboardgrid component with drag-and-drop functionality
- Added DeesDashboardgrid class for managing a grid of dashboard widgets. - Implemented widget dragging and resizing capabilities. - Introduced layout management with collision detection and margin resolution. - Created styles for grid layout, widget appearance, and animations. - Added support for customizable margins, cell height, and grid lines. - Included methods for adding, removing, and updating widgets dynamically. - Implemented context menu for widget actions and keyboard navigation support. - Established a responsive design with breakpoint handling for different layouts.
This commit is contained in:
105
ts_web/elements/dees-dashboardgrid/interaction.ts
Normal file
105
ts_web/elements/dees-dashboardgrid/interaction.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import type { DashboardWidget, GridCellMetrics } from './types.js';
|
||||
|
||||
export interface PointerPosition {
|
||||
clientX: number;
|
||||
clientY: number;
|
||||
}
|
||||
|
||||
export interface DragComputationArgs {
|
||||
pointer: PointerPosition;
|
||||
containerRect: DOMRect;
|
||||
metrics: GridCellMetrics;
|
||||
columns: number;
|
||||
widget: DashboardWidget;
|
||||
rtl: boolean;
|
||||
dragOffsetX?: number;
|
||||
dragOffsetY?: number;
|
||||
}
|
||||
|
||||
export const computeGridCoordinates = ({
|
||||
pointer,
|
||||
containerRect,
|
||||
metrics,
|
||||
columns,
|
||||
widget,
|
||||
rtl,
|
||||
dragOffsetX = 0,
|
||||
dragOffsetY = 0,
|
||||
}: DragComputationArgs): { x: number; y: number } => {
|
||||
const relativeX = pointer.clientX - containerRect.left - dragOffsetX;
|
||||
const relativeY = pointer.clientY - containerRect.top - dragOffsetY;
|
||||
|
||||
const marginX = metrics.marginHorizontalPx;
|
||||
const marginY = metrics.marginVerticalPx;
|
||||
const cellWidth = metrics.cellWidthPx;
|
||||
const cellHeight = metrics.cellHeightPx;
|
||||
|
||||
const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value));
|
||||
|
||||
const adjustedX = clamp(relativeX - marginX, 0, containerRect.width - marginX);
|
||||
const adjustedY = clamp(relativeY - marginY, 0, Number.POSITIVE_INFINITY);
|
||||
|
||||
const cellPlusMarginX = cellWidth + marginX;
|
||||
const cellPlusMarginY = cellHeight + marginY;
|
||||
|
||||
let gridX = Math.round(adjustedX / cellPlusMarginX);
|
||||
if (rtl) {
|
||||
gridX = columns - widget.w - gridX;
|
||||
}
|
||||
gridX = clamp(gridX, 0, columns - widget.w);
|
||||
|
||||
const gridY = clamp(Math.round(adjustedY / cellPlusMarginY), 0, Number.MAX_SAFE_INTEGER);
|
||||
|
||||
return { x: gridX, y: gridY };
|
||||
};
|
||||
|
||||
export interface ResizeComputationArgs {
|
||||
pointer: PointerPosition;
|
||||
containerRect: DOMRect;
|
||||
metrics: GridCellMetrics;
|
||||
startWidth: number;
|
||||
startHeight: number;
|
||||
startPointer: PointerPosition;
|
||||
handler: 'e' | 's' | 'se';
|
||||
widget: DashboardWidget;
|
||||
columns: number;
|
||||
}
|
||||
|
||||
export const computeResizeDimensions = ({
|
||||
pointer,
|
||||
containerRect,
|
||||
metrics,
|
||||
startWidth,
|
||||
startHeight,
|
||||
startPointer,
|
||||
handler,
|
||||
widget,
|
||||
columns,
|
||||
}: ResizeComputationArgs): { width: number; height: number } => {
|
||||
const deltaX = pointer.clientX - startPointer.clientX;
|
||||
const deltaY = pointer.clientY - startPointer.clientY;
|
||||
|
||||
let width = startWidth;
|
||||
let height = startHeight;
|
||||
|
||||
const cellPlusMarginX = metrics.cellWidthPx + metrics.marginHorizontalPx;
|
||||
const cellPlusMarginY = metrics.cellHeightPx + metrics.marginVerticalPx;
|
||||
|
||||
if (handler.includes('e')) {
|
||||
const deltaCols = Math.round(deltaX / cellPlusMarginX);
|
||||
width = startWidth + deltaCols;
|
||||
}
|
||||
|
||||
if (handler.includes('s')) {
|
||||
const deltaRows = Math.round(deltaY / cellPlusMarginY);
|
||||
height = startHeight + deltaRows;
|
||||
}
|
||||
|
||||
const clampedWidth = Math.max(widget.minW || 1, Math.min(width, widget.maxW || columns - widget.x));
|
||||
const clampedHeight = Math.max(widget.minH || 1, Math.min(height, widget.maxH || Number.MAX_SAFE_INTEGER));
|
||||
|
||||
return {
|
||||
width: clampedWidth,
|
||||
height: clampedHeight,
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user