Refactors edge scroll start detection

Improves edge scroll detection by listening for actual scroll events instead of relying on mouse position.

This change ensures that the 'edgescroll:started' event is only emitted when scrolling has actually begun, preventing false positives and improving the accuracy of scroll compensation. It also removes the unnecessary scroll listener from the DragDropManager, consolidating scroll handling in the EdgeScrollManager.
This commit is contained in:
Janus C. H. Knudsen 2025-10-13 17:49:19 +02:00
parent faf8b50593
commit d259620371
2 changed files with 41 additions and 28 deletions

View file

@ -182,7 +182,7 @@ export class DragDropManager {
* Optimized mouse move handler with consolidated position calculations * Optimized mouse move handler with consolidated position calculations
*/ */
private handleMouseMove(event: MouseEvent): void { private handleMouseMove(event: MouseEvent): void {
console.log('handleMouseMove', event)
if (this.isScrollCompensating) return; if (this.isScrollCompensating) return;
//this.currentMouseY = event.clientY; //this.currentMouseY = event.clientY;
// this.lastMousePosition = { x: event.clientX, y: event.clientY }; // this.lastMousePosition = { x: event.clientX, y: event.clientY };
@ -305,7 +305,6 @@ export class DragDropManager {
*/ */
private handleMouseUp(event: MouseEvent): void { private handleMouseUp(event: MouseEvent): void {
this.stopDragAnimation(); this.stopDragAnimation();
this.removeScrollListener();
if (this.originalElement) { if (this.originalElement) {
@ -376,7 +375,6 @@ export class DragDropManager {
console.log('🚫 DragDropManager: Cancelling drag - mouse left grid container'); console.log('🚫 DragDropManager: Cancelling drag - mouse left grid container');
this.cleanupAllClones(); this.cleanupAllClones();
this.removeScrollListener();
this.originalElement.style.opacity = ''; this.originalElement.style.opacity = '';
this.originalElement.style.cursor = ''; this.originalElement.style.cursor = '';
@ -486,19 +484,6 @@ export class DragDropManager {
}); });
} }
/**
* Remove scroll listener
*/
private removeScrollListener(): void {
if (this.scrollListener && this.scrollableContent) {
this.scrollableContent.removeEventListener('scroll', this.scrollListener);
this.scrollListener = null;
}
this.isScrollCompensating = false;
this.initialScrollTop = 0;
this.initialCloneTop = 0;
}
/** /**
* Stop drag animation * Stop drag animation
*/ */

View file

@ -14,6 +14,8 @@ export class EdgeScrollManager {
private isScrolling = false; // Track if edge-scroll is active private isScrolling = false; // Track if edge-scroll is active
private lastTs = 0; private lastTs = 0;
private rect: DOMRect | null = null; private rect: DOMRect | null = null;
private initialScrollTop = 0;
private scrollListener: ((e: Event) => void) | null = null;
// Constants - fixed values as per requirements // Constants - fixed values as per requirements
private readonly OUTER_ZONE = 100; // px from edge (slow zone) private readonly OUTER_ZONE = 100; // px from edge (slow zone)
@ -32,6 +34,10 @@ export class EdgeScrollManager {
if (this.scrollableContent) { if (this.scrollableContent) {
// Disable smooth scroll for instant auto-scroll // Disable smooth scroll for instant auto-scroll
this.scrollableContent.style.scrollBehavior = 'auto'; this.scrollableContent.style.scrollBehavior = 'auto';
// Add scroll listener to detect actual scrolling
this.scrollListener = this.handleScroll.bind(this);
this.scrollableContent.addEventListener('scroll', this.scrollListener, { passive: true });
} }
}, 100); }, 100);
@ -62,7 +68,10 @@ export class EdgeScrollManager {
this.isScrolling = false; // Reset scroll state this.isScrolling = false; // Reset scroll state
this.lastTs = performance.now(); this.lastTs = performance.now();
// Don't save initial positions here - wait until scrolling actually starts! // Save initial scroll position
if (this.scrollableContent) {
this.initialScrollTop = this.scrollableContent.scrollTop;
}
if (this.scrollRAF === null) { if (this.scrollRAF === null) {
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts)); this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
@ -71,13 +80,39 @@ export class EdgeScrollManager {
private stopDrag(): void { private stopDrag(): void {
this.isDragging = false; this.isDragging = false;
this.isScrolling = false;
// Emit stopped event if we were scrolling
if (this.isScrolling) {
this.isScrolling = false;
console.log('🛑 EdgeScrollManager: Edge-scroll stopped (drag ended)');
this.eventBus.emit('edgescroll:stopped', {});
}
if (this.scrollRAF !== null) { if (this.scrollRAF !== null) {
cancelAnimationFrame(this.scrollRAF); cancelAnimationFrame(this.scrollRAF);
this.scrollRAF = null; this.scrollRAF = null;
} }
this.rect = null; this.rect = null;
this.lastTs = 0; this.lastTs = 0;
this.initialScrollTop = 0;
}
private handleScroll(): void {
if (!this.isDragging || !this.scrollableContent) return;
const currentScrollTop = this.scrollableContent.scrollTop;
const scrollDelta = Math.abs(currentScrollTop - this.initialScrollTop);
// Only emit started event if we've actually scrolled more than 1px
if (scrollDelta > 1 && !this.isScrolling) {
this.isScrolling = true;
console.log('💾 EdgeScrollManager: Edge-scroll started (actual scroll detected)', {
initialScrollTop: this.initialScrollTop,
currentScrollTop,
scrollDelta
});
this.eventBus.emit('edgescroll:started', {});
}
} }
private scrollTick(ts: number): void { private scrollTick(ts: number): void {
@ -114,15 +149,8 @@ export class EdgeScrollManager {
} }
if (vy !== 0 && this.isDragging) { if (vy !== 0 && this.isDragging) {
// Mark that scrolling is active
if (!this.isScrolling) {
this.isScrolling = true;
console.log('💾 EdgeScrollManager: Edge-scroll started');
// Notify DragDropManager that scroll compensation should start
this.eventBus.emit('edgescroll:started', {});
}
// Time-based scrolling for frame-rate independence // Time-based scrolling for frame-rate independence
// The scroll listener will detect actual scrolling and emit edgescroll:started
this.scrollableContent.scrollTop += vy * dt; this.scrollableContent.scrollTop += vy * dt;
this.rect = null; // Invalidate cache for next frame this.rect = null; // Invalidate cache for next frame
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts)); this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
@ -130,8 +158,8 @@ export class EdgeScrollManager {
// Mouse moved away from edge - stop scrolling // Mouse moved away from edge - stop scrolling
if (this.isScrolling) { if (this.isScrolling) {
this.isScrolling = false; this.isScrolling = false;
console.log('🛑 EdgeScrollManager: Edge-scroll stopped'); this.initialScrollTop = this.scrollableContent.scrollTop; // Reset for next scroll
// Notify DragDropManager that scroll compensation should stop console.log('🛑 EdgeScrollManager: Edge-scroll stopped (mouse left edge)');
this.eventBus.emit('edgescroll:stopped', {}); this.eventBus.emit('edgescroll:stopped', {});
} }