Initial commit: dashboard-elements-ui library
Angular library providing dashboard components including grid layout, drag-and-drop widgets, resize handles, toolbar, config panel, layout presets, and persistence services.
This commit is contained in:
154
src/services/dashboard-drag.service.ts
Normal file
154
src/services/dashboard-drag.service.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { Injectable, signal, computed } from '@angular/core';
|
||||
import type { DbResizeDirection, DbDragPreview, DbResizePreview } from '../types/dashboard.types';
|
||||
import { pixelToGridPosition, clamp } from '../utils/grid.utils';
|
||||
|
||||
@Injectable()
|
||||
export class DashboardDragService {
|
||||
// Move state
|
||||
readonly isDragging = signal(false);
|
||||
readonly draggedWidgetId = signal<string | null>(null);
|
||||
readonly dragStartCol = signal(0);
|
||||
readonly dragStartRow = signal(0);
|
||||
readonly dragPreviewCol = signal(0);
|
||||
readonly dragPreviewRow = signal(0);
|
||||
readonly dragPreviewColSpan = signal(0);
|
||||
readonly dragPreviewRowSpan = signal(0);
|
||||
|
||||
// Resize state
|
||||
readonly isResizing = signal(false);
|
||||
readonly resizeWidgetId = signal<string | null>(null);
|
||||
readonly resizeDirection = signal<DbResizeDirection | null>(null);
|
||||
readonly resizeStartColSpan = signal(0);
|
||||
readonly resizeStartRowSpan = signal(0);
|
||||
readonly resizePreviewColSpan = signal(0);
|
||||
readonly resizePreviewRowSpan = signal(0);
|
||||
|
||||
// Computed
|
||||
readonly isActive = computed(() => this.isDragging() || this.isResizing());
|
||||
|
||||
readonly dragPreview = computed<DbDragPreview | null>(() => {
|
||||
if (!this.isDragging()) return null;
|
||||
return {
|
||||
col: this.dragPreviewCol(),
|
||||
row: this.dragPreviewRow(),
|
||||
colSpan: this.dragPreviewColSpan(),
|
||||
rowSpan: this.dragPreviewRowSpan(),
|
||||
};
|
||||
});
|
||||
|
||||
readonly resizePreview = computed<DbResizePreview | null>(() => {
|
||||
if (!this.isResizing()) return null;
|
||||
return {
|
||||
colSpan: this.resizePreviewColSpan(),
|
||||
rowSpan: this.resizePreviewRowSpan(),
|
||||
};
|
||||
});
|
||||
|
||||
startDrag(widgetId: string, col: number, row: number, colSpan: number, rowSpan: number): void {
|
||||
this.isDragging.set(true);
|
||||
this.draggedWidgetId.set(widgetId);
|
||||
this.dragStartCol.set(col);
|
||||
this.dragStartRow.set(row);
|
||||
this.dragPreviewCol.set(col);
|
||||
this.dragPreviewRow.set(row);
|
||||
this.dragPreviewColSpan.set(colSpan);
|
||||
this.dragPreviewRowSpan.set(rowSpan);
|
||||
}
|
||||
|
||||
updateDragPreview(col: number, row: number): void {
|
||||
this.dragPreviewCol.set(col);
|
||||
this.dragPreviewRow.set(row);
|
||||
}
|
||||
|
||||
endDrag(): { widgetId: string; col: number; row: number } | null {
|
||||
const widgetId = this.draggedWidgetId();
|
||||
const col = this.dragPreviewCol();
|
||||
const row = this.dragPreviewRow();
|
||||
|
||||
if (!widgetId) {
|
||||
this.cancelAll();
|
||||
return null;
|
||||
}
|
||||
|
||||
this.isDragging.set(false);
|
||||
this.draggedWidgetId.set(null);
|
||||
this.dragStartCol.set(0);
|
||||
this.dragStartRow.set(0);
|
||||
this.dragPreviewCol.set(0);
|
||||
this.dragPreviewRow.set(0);
|
||||
this.dragPreviewColSpan.set(0);
|
||||
this.dragPreviewRowSpan.set(0);
|
||||
|
||||
return { widgetId, col, row };
|
||||
}
|
||||
|
||||
startResize(
|
||||
widgetId: string,
|
||||
direction: DbResizeDirection,
|
||||
colSpan: number,
|
||||
rowSpan: number,
|
||||
): void {
|
||||
this.isResizing.set(true);
|
||||
this.resizeWidgetId.set(widgetId);
|
||||
this.resizeDirection.set(direction);
|
||||
this.resizeStartColSpan.set(colSpan);
|
||||
this.resizeStartRowSpan.set(rowSpan);
|
||||
this.resizePreviewColSpan.set(colSpan);
|
||||
this.resizePreviewRowSpan.set(rowSpan);
|
||||
}
|
||||
|
||||
updateResizePreview(colSpan: number, rowSpan: number): void {
|
||||
this.resizePreviewColSpan.set(colSpan);
|
||||
this.resizePreviewRowSpan.set(rowSpan);
|
||||
}
|
||||
|
||||
endResize(): { widgetId: string; colSpan: number; rowSpan: number } | null {
|
||||
const widgetId = this.resizeWidgetId();
|
||||
const colSpan = this.resizePreviewColSpan();
|
||||
const rowSpan = this.resizePreviewRowSpan();
|
||||
|
||||
if (!widgetId) {
|
||||
this.cancelAll();
|
||||
return null;
|
||||
}
|
||||
|
||||
this.isResizing.set(false);
|
||||
this.resizeWidgetId.set(null);
|
||||
this.resizeDirection.set(null);
|
||||
this.resizeStartColSpan.set(0);
|
||||
this.resizeStartRowSpan.set(0);
|
||||
this.resizePreviewColSpan.set(0);
|
||||
this.resizePreviewRowSpan.set(0);
|
||||
|
||||
return { widgetId, colSpan, rowSpan };
|
||||
}
|
||||
|
||||
cancelAll(): void {
|
||||
this.isDragging.set(false);
|
||||
this.draggedWidgetId.set(null);
|
||||
this.dragStartCol.set(0);
|
||||
this.dragStartRow.set(0);
|
||||
this.dragPreviewCol.set(0);
|
||||
this.dragPreviewRow.set(0);
|
||||
this.dragPreviewColSpan.set(0);
|
||||
this.dragPreviewRowSpan.set(0);
|
||||
this.isResizing.set(false);
|
||||
this.resizeWidgetId.set(null);
|
||||
this.resizeDirection.set(null);
|
||||
this.resizeStartColSpan.set(0);
|
||||
this.resizeStartRowSpan.set(0);
|
||||
this.resizePreviewColSpan.set(0);
|
||||
this.resizePreviewRowSpan.set(0);
|
||||
}
|
||||
|
||||
calculateGridPosition(
|
||||
event: DragEvent | MouseEvent,
|
||||
gridEl: HTMLElement,
|
||||
columns: number,
|
||||
rowHeight: number,
|
||||
gap: number,
|
||||
): { col: number; row: number } {
|
||||
const gridRect = gridEl.getBoundingClientRect();
|
||||
return pixelToGridPosition(event.clientX, event.clientY, gridRect, columns, rowHeight, gap);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user