Improves drag and drop functionality

Enhances drag and drop behavior by introducing free positioning during auto-scroll and snapping to grid intervals.

- Introduces a `calculateFreePosition` method to allow events to follow the mouse exactly during auto-scroll.
- Modifies the drag move event to emit the snapped position during normal drag behavior.
- Updates event rendering to use grid settings for snap intervals.
- Updates grid styles to configure CSS variables dynamically.
This commit is contained in:
Janus Knudsen 2025-09-03 20:48:23 +02:00
parent b4d758b6d9
commit 7a1c776bc1
4 changed files with 50 additions and 25 deletions

View file

@ -47,7 +47,7 @@ export class DragDropManager {
// Snap configuration
private snapIntervalMinutes = 15; // Default 15 minutes
private hourHeightPx = 60; // From CSS --hour-height
private hourHeightPx: number; // Will be set from config
// Event listener references for proper cleanup
private boundHandlers = {
@ -66,6 +66,7 @@ export class DragDropManager {
// Get config values
const gridSettings = calendarConfig.getGridSettings();
this.hourHeightPx = gridSettings.hourHeight;
this.snapIntervalMinutes = gridSettings.snapInterval;
this.init();
}
@ -164,14 +165,14 @@ export class DragDropManager {
const currentPosition: Position = { x: event.clientX, y: event.clientY };
const deltaY = Math.abs(currentPosition.y - this.lastLoggedPosition.y);
// Check for snap interval vertical movement
// Check for snap interval vertical movement (normal drag behavior)
if (deltaY >= this.snapDistancePx) {
this.lastLoggedPosition = currentPosition;
// Consolidated position calculations
// Consolidated position calculations with snapping for normal drag
const positionData = this.calculateDragPosition(currentPosition);
// Emit drag move event with consolidated data
// Emit drag move event with snapped position (normal behavior)
this.eventBus.emit('drag:move', {
eventId: this.draggedEventId,
mousePosition: currentPosition,
@ -240,7 +241,24 @@ export class DragDropManager {
}
/**
* Optimized snap position calculation with caching
* Calculate free position (follows mouse exactly)
*/
private calculateFreePosition(mouseY: number, column: string | null = null): number {
const targetColumn = column || this.currentColumn;
// Use cached column element if available
const columnElement = this.getCachedColumnElement(targetColumn);
if (!columnElement) return mouseY;
const columnRect = columnElement.getBoundingClientRect();
const relativeY = mouseY - columnRect.top - this.mouseOffset.y;
// Return free position (no snapping)
return Math.max(0, relativeY);
}
/**
* Optimized snap position calculation with caching (used only on drop)
*/
private calculateSnapPosition(mouseY: number, column: string | null = null): number {
const targetColumn = column || this.currentColumn;
@ -371,14 +389,13 @@ export class DragDropManager {
const columnElement = this.getCachedColumnElement(this.currentColumn);
if (columnElement) {
const columnRect = columnElement.getBoundingClientRect();
// Calculate position relative to column, accounting for scroll movement
// Calculate free position relative to column, accounting for scroll movement (no snapping during scroll)
const relativeY = this.currentMouseY - columnRect.top - this.mouseOffset.y;
const snappedY = Math.round(relativeY / this.snapDistancePx) * this.snapDistancePx;
const finalSnappedY = Math.max(0, snappedY);
const freeY = Math.max(0, relativeY);
this.eventBus.emit('drag:auto-scroll', {
eventId: this.draggedEventId,
snappedY: finalSnappedY,
snappedY: freeY, // Actually free position during scroll
scrollTop: this.cachedElements.scrollContainer.scrollTop
});
}

View file

@ -8,6 +8,7 @@ import { calendarConfig } from '../core/CalendarConfig';
import { CoreEvents } from '../constants/CoreEvents';
import { ResourceCalendarData, CalendarView } from '../types/CalendarTypes';
import { GridRenderer } from '../renderers/GridRenderer';
import { GridStyleManager } from '../renderers/GridStyleManager';
import { DateCalculator } from '../utils/DateCalculator';
/**
@ -19,11 +20,13 @@ export class GridManager {
private resourceData: ResourceCalendarData | null = null;
private currentView: CalendarView = 'week';
private gridRenderer: GridRenderer;
private styleManager: GridStyleManager;
private eventCleanup: (() => void)[] = [];
constructor() {
// Initialize GridRenderer with config
// Initialize GridRenderer and StyleManager with config
this.gridRenderer = new GridRenderer();
this.styleManager = new GridStyleManager();
this.init();
}
@ -85,6 +88,9 @@ export class GridManager {
return;
}
// Update CSS variables first
this.styleManager.updateGridStyles(this.resourceData);
// Delegate to GridRenderer with current view context
this.gridRenderer.renderGrid(
this.container,