From 9a7a90c12430d66bc3a12160c8888d9156252e5c Mon Sep 17 00:00:00 2001 From: "Janus C. H. Knudsen" Date: Mon, 13 Oct 2025 20:24:19 +0200 Subject: [PATCH] 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. --- src/managers/DragDropManager.ts | 62 ++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/managers/DragDropManager.ts b/src/managers/DragDropManager.ts index 3a2f4ab..ee23303 100644 --- a/src/managers/DragDropManager.ts +++ b/src/managers/DragDropManager.ts @@ -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; } /**