Refactors and optimizes core calendar managers
Streamlines several core managers by removing unnecessary complexity, caching, and redundant methods Key improvements: - Simplified event and view management logic - Removed unnecessary caching mechanisms - Reduced method complexity in managers - Improved code readability and performance
This commit is contained in:
parent
1ae4f00f2b
commit
b6ab1ff50e
6 changed files with 193 additions and 327 deletions
|
|
@ -1,6 +1,135 @@
|
|||
/**
|
||||
* DragDropManager - Optimized drag and drop with consolidated position calculations
|
||||
* Reduces redundant DOM queries and improves performance through caching
|
||||
* DragDropManager - Advanced drag-and-drop system with smooth animations and event type conversion
|
||||
*
|
||||
* ARCHITECTURE OVERVIEW:
|
||||
* =====================
|
||||
* DragDropManager provides a sophisticated drag-and-drop system for calendar events that supports:
|
||||
* - Smooth animated dragging with requestAnimationFrame
|
||||
* - Automatic event type conversion (timed events ↔ all-day events)
|
||||
* - Scroll compensation during edge scrolling
|
||||
* - Grid snapping for precise event placement
|
||||
* - Column detection and change tracking
|
||||
*
|
||||
* KEY FEATURES:
|
||||
* =============
|
||||
* 1. DRAG DETECTION
|
||||
* - Movement threshold (5px) to distinguish clicks from drags
|
||||
* - Immediate visual feedback with cloned element
|
||||
* - Mouse offset tracking for natural drag feel
|
||||
*
|
||||
* 2. SMOOTH ANIMATION
|
||||
* - Uses requestAnimationFrame for 60fps animations
|
||||
* - Interpolated movement (30% per frame) for smooth transitions
|
||||
* - Continuous drag:move events for real-time updates
|
||||
*
|
||||
* 3. EVENT TYPE CONVERSION
|
||||
* - Timed → All-day: When dragging into calendar header
|
||||
* - All-day → Timed: When dragging into day columns
|
||||
* - Automatic clone replacement with appropriate element type
|
||||
*
|
||||
* 4. SCROLL COMPENSATION
|
||||
* - Tracks scroll delta during edge-scrolling
|
||||
* - Compensates dragged element position during scroll
|
||||
* - Prevents visual "jumping" when scrolling while dragging
|
||||
*
|
||||
* 5. GRID SNAPPING
|
||||
* - Snaps to time grid on mouse up
|
||||
* - Uses PositionUtils for consistent positioning
|
||||
* - Accounts for mouse offset within event
|
||||
*
|
||||
* STATE MANAGEMENT:
|
||||
* =================
|
||||
* Mouse Tracking:
|
||||
* - mouseDownPosition: Initial click position
|
||||
* - currentMousePosition: Latest mouse position
|
||||
* - mouseOffset: Click offset within event (for natural dragging)
|
||||
*
|
||||
* Drag State:
|
||||
* - originalElement: Source event being dragged
|
||||
* - draggedClone: Animated clone following mouse
|
||||
* - currentColumn: Column mouse is currently over
|
||||
* - previousColumn: Last column (for detecting changes)
|
||||
* - isDragStarted: Whether drag threshold exceeded
|
||||
*
|
||||
* Scroll State:
|
||||
* - scrollDeltaY: Accumulated scroll offset during drag
|
||||
* - lastScrollTop: Previous scroll position
|
||||
* - isScrollCompensating: Whether edge-scroll is active
|
||||
*
|
||||
* Animation State:
|
||||
* - dragAnimationId: requestAnimationFrame ID
|
||||
* - targetY: Desired position for smooth interpolation
|
||||
* - currentY: Current interpolated position
|
||||
*
|
||||
* EVENT FLOW:
|
||||
* ===========
|
||||
* 1. Mouse Down (handleMouseDown)
|
||||
* ├─ Store originalElement and mouse offset
|
||||
* └─ Wait for movement
|
||||
*
|
||||
* 2. Mouse Move (handleMouseMove)
|
||||
* ├─ Check movement threshold
|
||||
* ├─ Initialize drag if threshold exceeded (initializeDrag)
|
||||
* │ ├─ Create clone
|
||||
* │ ├─ Emit drag:start
|
||||
* │ └─ Start animation loop
|
||||
* ├─ Continue drag (continueDrag)
|
||||
* │ ├─ Calculate target position with scroll compensation
|
||||
* │ └─ Update animation target
|
||||
* └─ Detect column changes (detectColumnChange)
|
||||
* └─ Emit drag:column-change
|
||||
*
|
||||
* 3. Animation Loop (animateDrag)
|
||||
* ├─ Interpolate currentY toward targetY
|
||||
* ├─ Emit drag:move on each frame
|
||||
* └─ Schedule next frame until target reached
|
||||
*
|
||||
* 4. Event Type Conversion
|
||||
* ├─ Entering header (handleHeaderMouseEnter)
|
||||
* │ ├─ Emit drag:mouseenter-header
|
||||
* │ └─ AllDayManager creates all-day clone
|
||||
* └─ Entering column (handleColumnMouseEnter)
|
||||
* ├─ Emit drag:mouseenter-column
|
||||
* └─ EventRenderingService creates timed clone
|
||||
*
|
||||
* 5. Mouse Up (handleMouseUp)
|
||||
* ├─ Stop animation
|
||||
* ├─ Snap to grid
|
||||
* ├─ Detect drop target (header or column)
|
||||
* ├─ Emit drag:end with final position
|
||||
* └─ Cleanup drag state
|
||||
*
|
||||
* SCROLL COMPENSATION SYSTEM:
|
||||
* ===========================
|
||||
* Problem: When EdgeScrollManager scrolls the grid during drag, the dragged element
|
||||
* can appear to "jump" because the mouse position stays the same but the
|
||||
* coordinate system (scrollable content) has moved.
|
||||
*
|
||||
* Solution: Track cumulative scroll delta and add it to mouse position calculations
|
||||
*
|
||||
* Flow:
|
||||
* 1. EdgeScrollManager starts scrolling → emit edgescroll:started
|
||||
* 2. DragDropManager sets isScrollCompensating = true
|
||||
* 3. On each scroll event:
|
||||
* ├─ Calculate scrollDelta = currentScrollTop - lastScrollTop
|
||||
* ├─ Accumulate into scrollDeltaY
|
||||
* └─ Call continueDrag with adjusted position
|
||||
* 4. continueDrag adds scrollDeltaY to mouse Y coordinate
|
||||
* 5. On event conversion, reset scrollDeltaY (new clone, new coordinate system)
|
||||
*
|
||||
* PERFORMANCE OPTIMIZATIONS:
|
||||
* ==========================
|
||||
* - Uses ColumnDetectionUtils cache for fast column lookups
|
||||
* - Single requestAnimationFrame loop (not per-mousemove)
|
||||
* - Interpolated animation reduces update frequency
|
||||
* - Passive scroll listeners
|
||||
* - Event delegation for header/column detection
|
||||
*
|
||||
* USAGE:
|
||||
* ======
|
||||
* const dragDropManager = new DragDropManager(eventBus, positionUtils);
|
||||
* // Automatically attaches event listeners and manages drag lifecycle
|
||||
* // Other managers listen to drag:start, drag:move, drag:end, etc.
|
||||
*/
|
||||
|
||||
import { IEventBus } from '../types/CalendarTypes';
|
||||
|
|
@ -122,24 +251,19 @@ export class DragDropManager {
|
|||
if (this.scrollableContent) {
|
||||
this.lastScrollTop = this.scrollableContent.scrollTop;
|
||||
}
|
||||
|
||||
console.log('🎬 DragDropManager: Edge-scroll started');
|
||||
});
|
||||
|
||||
this.eventBus.on('edgescroll:stopped', () => {
|
||||
this.isScrollCompensating = false;
|
||||
console.log('🛑 DragDropManager: Edge-scroll stopped');
|
||||
});
|
||||
|
||||
// Reset scrollDeltaY when event converts (new clone created)
|
||||
this.eventBus.on('drag:mouseenter-header', () => {
|
||||
console.log('🔄 DragDropManager: Event converting to all-day - resetting scrollDeltaY');
|
||||
this.scrollDeltaY = 0;
|
||||
this.lastScrollTop = 0;
|
||||
});
|
||||
|
||||
this.eventBus.on('drag:mouseenter-column', () => {
|
||||
console.log('🔄 DragDropManager: Event converting to timed - resetting scrollDeltaY');
|
||||
this.scrollDeltaY = 0;
|
||||
this.lastScrollTop = 0;
|
||||
});
|
||||
|
|
@ -340,8 +464,6 @@ export class DragDropManager {
|
|||
target: dropTarget
|
||||
};
|
||||
|
||||
console.log('DragEndEventPayload', dragEndPayload);
|
||||
|
||||
this.eventBus.emit('drag:end', dragEndPayload);
|
||||
|
||||
this.cleanupDragState();
|
||||
|
|
@ -361,7 +483,6 @@ export class DragDropManager {
|
|||
const allClones = document.querySelectorAll('[data-event-id^="clone"]');
|
||||
|
||||
if (allClones.length > 0) {
|
||||
console.log(`🧹 DragDropManager: Removing ${allClones.length} clone(s)`);
|
||||
allClones.forEach(clone => clone.remove());
|
||||
}
|
||||
}
|
||||
|
|
@ -373,8 +494,6 @@ export class DragDropManager {
|
|||
private cancelDrag(): void {
|
||||
if (!this.originalElement || !this.draggedClone) return;
|
||||
|
||||
console.log('🚫 DragDropManager: Cancelling drag - mouse left grid container');
|
||||
|
||||
// Get current clone position
|
||||
const cloneRect = this.draggedClone.getBoundingClientRect();
|
||||
|
||||
|
|
@ -486,13 +605,6 @@ export class DragDropManager {
|
|||
|
||||
// Kald continueDrag med nuværende mus position
|
||||
this.continueDrag(this.currentMousePosition);
|
||||
|
||||
console.log('📜 DragDropManager: Scroll compensation', {
|
||||
currentScrollTop,
|
||||
lastScrollTop: this.lastScrollTop - scrollDelta,
|
||||
scrollDelta,
|
||||
scrollDeltaY: this.scrollDeltaY
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -564,7 +676,6 @@ export class DragDropManager {
|
|||
this.dragAnimationId === null;
|
||||
}
|
||||
};
|
||||
console.log('DragMouseEnterHeaderEventPayload', dragMouseEnterPayload);
|
||||
this.eventBus.emit('drag:mouseenter-header', dragMouseEnterPayload);
|
||||
}
|
||||
}
|
||||
|
|
@ -578,13 +689,10 @@ export class DragDropManager {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('🎯 DragDropManager: Mouse entered day column');
|
||||
|
||||
const position: MousePosition = { x: event.clientX, y: event.clientY };
|
||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||
|
||||
if (!targetColumn) {
|
||||
console.warn("No column detected when entering day column");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -619,13 +727,10 @@ export class DragDropManager {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('🚪 DragDropManager: Mouse left header');
|
||||
|
||||
const position: MousePosition = { x: event.clientX, y: event.clientY };
|
||||
const targetColumn = ColumnDetectionUtils.getColumnBounds(position);
|
||||
|
||||
if (!targetColumn) {
|
||||
console.warn("No column detected when leaving header");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue