Improves drag-and-drop scroll compensation.

Enhances drag-and-drop functionality by accurately compensating for scroll during drag operations.
This ensures the dragged element remains correctly positioned relative to the mouse,
even when the user scrolls the content during the drag.

It achieves this by:
- Tracking whether scrolling has occurred during a drag operation.
- Factoring scroll delta into target position calculation.
- Updating targetY/currentY instead of directly manipulating the clone's style.
This commit is contained in:
Janus C. H. Knudsen 2025-10-13 20:24:19 +02:00
parent dbbd19de13
commit 9a7a90c124

View file

@ -47,6 +47,7 @@ export class DragDropManager {
private initialScrollTop = 0;
private initialCloneTop = 0;
private isScrollCompensating = false; // Track if scroll compensation is active
private hasScrolledDuringDrag = false; // Track if we have scrolled during this drag operation
private scrollListener: ((e: Event) => void) | null = null;
// Smooth drag animation
@ -127,6 +128,7 @@ export class DragDropManager {
// Listen to edge-scroll events to control scroll compensation
this.eventBus.on('edgescroll:started', () => {
this.isScrollCompensating = true;
this.hasScrolledDuringDrag = true;
console.log('🎬 DragDropManager: Edge-scroll started - disabling continueDrag()');
});
@ -194,21 +196,20 @@ export class DragDropManager {
}
if (event.buttons === 1) {
const currentPosition: MousePosition = { x: event.clientX, y: event.clientY };
this.currentMousePosition = currentPosition; // Track current mouse position
// Always update mouse position from event
this.currentMousePosition = { x: event.clientX, y: event.clientY };
// Try to initialize drag if not started
if (!this.isDragStarted && this.originalElement) {
if (!this.initializeDrag(currentPosition)) {
if (!this.initializeDrag(this.currentMousePosition)) {
return; // Not enough movement yet
}
}
// Continue drag if started //TODO: This has to be fixed... it fires way too many events, we can do better
// Continue drag if started
if (this.isDragStarted && this.originalElement && this.draggedClone) {
//console.log("Continue drag if started", this.draggedClone);
this.continueDrag(currentPosition);
this.detectColumnChange(currentPosition);
this.continueDrag(this.currentMousePosition);
this.detectColumnChange(this.currentMousePosition);
}
}
}
@ -265,7 +266,14 @@ export class DragDropManager {
if (column) {
// Calculate raw Y position relative to column (accounting for mouse offset)
const columnRect = column.boundingClientRect;
const eventTopY = currentPosition.y - columnRect.top - this.mouseOffset.y;
let eventTopY = currentPosition.y - columnRect.top - this.mouseOffset.y;
// Kompenser for scroll bevægelse hvis vi har scrollet
if (this.scrollableContent && this.initialScrollTop > 0) {
const totalScrollDelta = this.scrollableContent.scrollTop - this.initialScrollTop;
eventTopY += totalScrollDelta;
}
this.targetY = Math.max(0, eventTopY);
this.targetColumn = column;
@ -453,38 +461,47 @@ export class DragDropManager {
}
/**
* Handle scroll during drag - compensate clone position
* Handle scroll during drag - compensate clone position via targetY/currentY
*/
private handleScroll(): void {
if (!this.isDragStarted || !this.draggedClone || !this.scrollableContent || !this.isScrollCompensating) return;
// First time scrolling - save initial positions NOW!
if(this.initialScrollTop == 0)
if(this.initialScrollTop == 0) {
this.initialScrollTop = this.scrollableContent.scrollTop;
if(this.initialCloneTop == 0)
}
if(this.initialCloneTop == 0) {
this.initialCloneTop = parseFloat(this.draggedClone.style.top || '0');
console.log('💾 DragDropManager: Scroll compensation started', {
initialScrollTop: this.initialScrollTop,
initialCloneTop: this.initialCloneTop
});
console.log('💾 DragDropManager: Scroll compensation started', {
initialScrollTop: this.initialScrollTop,
initialCloneTop: this.initialCloneTop
});
}
const currentScrollTop = this.scrollableContent.scrollTop;
const totalScrollDelta = currentScrollTop - this.initialScrollTop;
// Beregn ny position baseret på initial position + total scroll delta
const newTop = this.initialCloneTop + totalScrollDelta;
this.draggedClone.style.top = `${newTop}px`;
// Opdater targetY og currentY i stedet for direkte clone opdatering
this.targetY = newTop;
this.currentY = newTop;
// Kald animateDrag() hvis ikke allerede kører
if (this.dragAnimationId === null) {
this.animateDrag();
}
console.log('📜 DragDropManager: Scroll compensation', {
initialScrollTop: this.initialScrollTop,
currentScrollTop,
totalScrollDelta,
initialCloneTop: this.initialCloneTop,
newTop
newTop,
targetY: this.targetY,
currentY: this.currentY
});
}
@ -507,6 +524,9 @@ export class DragDropManager {
this.draggedClone = null;
this.currentColumn = null;
this.isDragStarted = false;
this.hasScrolledDuringDrag = false;
this.initialScrollTop = 0;
this.initialCloneTop = 0;
}
/**