Improves drag and drop with edge scrolling
Enhances the drag and drop experience by integrating edge scrolling, allowing users to scroll the calendar view while dragging events. Fixes issues with event positioning during scrolling by compensating for scroll changes during drag operations. Also, adds mock events to data.
This commit is contained in:
parent
a0344c6143
commit
faf8b50593
3 changed files with 244 additions and 60 deletions
|
|
@ -2675,5 +2675,135 @@
|
||||||
"duration": 60,
|
"duration": 60,
|
||||||
"color": "#dda15e"
|
"color": "#dda15e"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "169",
|
||||||
|
"title": "Morgen Standup",
|
||||||
|
"start": "2025-10-13T05:00:00Z",
|
||||||
|
"end": "2025-10-13T05:30:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 30,
|
||||||
|
"color": "#ff5722"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "170",
|
||||||
|
"title": "Produktvejledning",
|
||||||
|
"start": "2025-10-13T07:00:00Z",
|
||||||
|
"end": "2025-10-13T08:30:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 90,
|
||||||
|
"color": "#9c27b0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "171",
|
||||||
|
"title": "Team Standup",
|
||||||
|
"start": "2025-10-14T05:00:00Z",
|
||||||
|
"end": "2025-10-14T05:30:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 30,
|
||||||
|
"color": "#ff5722"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "172",
|
||||||
|
"title": "Udviklingssession",
|
||||||
|
"start": "2025-10-14T06:00:00Z",
|
||||||
|
"end": "2025-10-14T09:00:00Z",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 180,
|
||||||
|
"color": "#2196f3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "173",
|
||||||
|
"title": "Klient Gennemgang",
|
||||||
|
"start": "2025-10-15T11:00:00Z",
|
||||||
|
"end": "2025-10-15T12:00:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 60,
|
||||||
|
"color": "#795548"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "174",
|
||||||
|
"title": "Team Standup",
|
||||||
|
"start": "2025-10-16T05:00:00Z",
|
||||||
|
"end": "2025-10-16T05:30:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 30,
|
||||||
|
"color": "#ff5722"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "175",
|
||||||
|
"title": "Arkitektur Workshop",
|
||||||
|
"start": "2025-10-16T10:00:00Z",
|
||||||
|
"end": "2025-10-16T13:00:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 180,
|
||||||
|
"color": "#009688"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "176",
|
||||||
|
"title": "Team Standup",
|
||||||
|
"start": "2025-10-17T05:00:00Z",
|
||||||
|
"end": "2025-10-17T05:30:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 30,
|
||||||
|
"color": "#ff5722"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "177",
|
||||||
|
"title": "Sprint Review",
|
||||||
|
"start": "2025-10-17T10:00:00Z",
|
||||||
|
"end": "2025-10-17T11:00:00Z",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 60,
|
||||||
|
"color": "#607d8b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "178",
|
||||||
|
"title": "Weekend Kodning",
|
||||||
|
"start": "2025-10-18T06:00:00Z",
|
||||||
|
"end": "2025-10-18T10:00:00Z",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": {
|
||||||
|
"duration": 240,
|
||||||
|
"color": "#3f51b5"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -18,6 +18,7 @@ import {
|
||||||
DragColumnChangeEventPayload
|
DragColumnChangeEventPayload
|
||||||
} from '../types/EventTypes';
|
} from '../types/EventTypes';
|
||||||
import { MousePosition } from '../types/DragDropTypes';
|
import { MousePosition } from '../types/DragDropTypes';
|
||||||
|
import { CoreEvents } from '../constants/CoreEvents';
|
||||||
|
|
||||||
export class DragDropManager {
|
export class DragDropManager {
|
||||||
private eventBus: IEventBus;
|
private eventBus: IEventBus;
|
||||||
|
|
@ -41,6 +42,12 @@ export class DragDropManager {
|
||||||
// Movement threshold to distinguish click from drag
|
// Movement threshold to distinguish click from drag
|
||||||
private readonly dragThreshold = 5; // pixels
|
private readonly dragThreshold = 5; // pixels
|
||||||
|
|
||||||
|
// Scroll compensation
|
||||||
|
private scrollableContent: HTMLElement | null = null;
|
||||||
|
private initialScrollTop = 0;
|
||||||
|
private initialCloneTop = 0;
|
||||||
|
private isScrollCompensating = false; // Track if scroll compensation is active
|
||||||
|
private scrollListener: ((e: Event) => void) | null = null;
|
||||||
|
|
||||||
// Smooth drag animation
|
// Smooth drag animation
|
||||||
private dragAnimationId: number | null = null;
|
private dragAnimationId: number | null = null;
|
||||||
|
|
@ -53,6 +60,8 @@ export class DragDropManager {
|
||||||
// Get config values
|
// Get config values
|
||||||
const gridSettings = calendarConfig.getGridSettings();
|
const gridSettings = calendarConfig.getGridSettings();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +107,9 @@ export class DragDropManager {
|
||||||
// Initialize column bounds cache
|
// Initialize column bounds cache
|
||||||
ColumnDetectionUtils.updateColumnBoundsCache();
|
ColumnDetectionUtils.updateColumnBoundsCache();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Listen to resize events to update cache
|
// Listen to resize events to update cache
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
ColumnDetectionUtils.updateColumnBoundsCache();
|
ColumnDetectionUtils.updateColumnBoundsCache();
|
||||||
|
|
@ -108,6 +120,25 @@ export class DragDropManager {
|
||||||
ColumnDetectionUtils.updateColumnBoundsCache();
|
ColumnDetectionUtils.updateColumnBoundsCache();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.eventBus.on(CoreEvents.GRID_RENDERED, (event: Event) => {
|
||||||
|
this.handleGridRendered(event as CustomEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen to edge-scroll events to control scroll compensation
|
||||||
|
this.eventBus.on('edgescroll:started', () => {
|
||||||
|
this.isScrollCompensating = true;
|
||||||
|
console.log('🎬 DragDropManager: Edge-scroll started - disabling continueDrag()');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventBus.on('edgescroll:stopped', () => {
|
||||||
|
this.isScrollCompensating = false;
|
||||||
|
console.log('🛑 DragDropManager: Edge-scroll stopped - enabling continueDrag()');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
private handleGridRendered(event: CustomEvent) {
|
||||||
|
this.scrollableContent = document.querySelector('swp-scrollable-content');
|
||||||
|
this.scrollableContent!.addEventListener('scroll', this.handleScroll.bind(this), { passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleMouseDown(event: MouseEvent): void {
|
private handleMouseDown(event: MouseEvent): void {
|
||||||
|
|
@ -151,6 +182,8 @@ 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 {
|
||||||
|
|
||||||
|
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 };
|
||||||
|
|
||||||
|
|
@ -195,6 +228,8 @@ export class DragDropManager {
|
||||||
// Start drag
|
// Start drag
|
||||||
this.isDragStarted = true;
|
this.isDragStarted = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Set high z-index on event-group if exists, otherwise on event itself
|
// Set high z-index on event-group if exists, otherwise on event itself
|
||||||
const eventGroup = this.originalElement!.closest<HTMLElement>('swp-event-group');
|
const eventGroup = this.originalElement!.closest<HTMLElement>('swp-event-group');
|
||||||
if (eventGroup) {
|
if (eventGroup) {
|
||||||
|
|
@ -209,7 +244,7 @@ export class DragDropManager {
|
||||||
|
|
||||||
const dragStartPayload: DragStartEventPayload = {
|
const dragStartPayload: DragStartEventPayload = {
|
||||||
originalElement: this.originalElement!,
|
originalElement: this.originalElement!,
|
||||||
draggedClone: this.draggedClone,
|
draggedClone: this.draggedClone,
|
||||||
mousePosition: this.mouseDownPosition,
|
mousePosition: this.mouseDownPosition,
|
||||||
mouseOffset: this.mouseOffset,
|
mouseOffset: this.mouseOffset,
|
||||||
columnBounds: this.currentColumn
|
columnBounds: this.currentColumn
|
||||||
|
|
@ -221,6 +256,7 @@ export class DragDropManager {
|
||||||
|
|
||||||
|
|
||||||
private continueDrag(currentPosition: MousePosition): void {
|
private continueDrag(currentPosition: MousePosition): void {
|
||||||
|
|
||||||
if (!this.draggedClone!.hasAttribute("data-allday")) {
|
if (!this.draggedClone!.hasAttribute("data-allday")) {
|
||||||
// Calculate raw position from mouse (no snapping)
|
// Calculate raw position from mouse (no snapping)
|
||||||
const column = ColumnDetectionUtils.getColumnBounds(currentPosition);
|
const column = ColumnDetectionUtils.getColumnBounds(currentPosition);
|
||||||
|
|
@ -269,6 +305,7 @@ 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) {
|
||||||
|
|
||||||
|
|
@ -339,6 +376,7 @@ 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 = '';
|
||||||
|
|
@ -415,6 +453,51 @@ export class DragDropManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle scroll during drag - compensate clone position
|
||||||
|
*/
|
||||||
|
private handleScroll(): void {
|
||||||
|
if (!this.isDragStarted || !this.draggedClone || !this.scrollableContent || !this.isScrollCompensating) return;
|
||||||
|
|
||||||
|
// First time scrolling - save initial positions NOW!
|
||||||
|
|
||||||
|
this.initialScrollTop = this.scrollableContent.scrollTop;
|
||||||
|
this.initialCloneTop = parseFloat(this.draggedClone.style.top || '0');
|
||||||
|
|
||||||
|
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`;
|
||||||
|
|
||||||
|
console.log('📜 DragDropManager: Scroll compensation', {
|
||||||
|
initialScrollTop: this.initialScrollTop,
|
||||||
|
currentScrollTop,
|
||||||
|
totalScrollDelta,
|
||||||
|
initialCloneTop: this.initialCloneTop,
|
||||||
|
newTop
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,15 @@ export class EdgeScrollManager {
|
||||||
private scrollRAF: number | null = null;
|
private scrollRAF: number | null = null;
|
||||||
private mouseY = 0;
|
private mouseY = 0;
|
||||||
private isDragging = false;
|
private isDragging = false;
|
||||||
|
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 draggedClone: HTMLElement | null = null;
|
|
||||||
private initialScrollTop = 0;
|
|
||||||
private initialCloneTop = 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)
|
||||||
private readonly INNER_ZONE = 50; // px from edge (fast zone)
|
private readonly INNER_ZONE = 50; // px from edge (fast zone)
|
||||||
private readonly SLOW_SPEED_PXS = 800; // px/sec in outer zone
|
private readonly SLOW_SPEED_PXS = 80; // px/sec in outer zone
|
||||||
private readonly FAST_SPEED_PXS = 2400; // px/sec in inner zone
|
private readonly FAST_SPEED_PXS = 240; // px/sec in inner zone
|
||||||
|
|
||||||
constructor(private eventBus: IEventBus) {
|
constructor(private eventBus: IEventBus) {
|
||||||
this.init();
|
this.init();
|
||||||
|
|
@ -35,31 +32,26 @@ 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
|
|
||||||
this.scrollListener = this.handleScroll.bind(this);
|
|
||||||
this.scrollableContent.addEventListener('scroll', this.scrollListener, { passive: true });
|
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
|
// Listen to mousemove directly from document to always get mouse coords
|
||||||
|
document.body.addEventListener('mousemove', (e: MouseEvent) => {
|
||||||
|
if (this.isDragging) {
|
||||||
|
this.mouseY = e.clientY;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.subscribeToEvents();
|
this.subscribeToEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribeToEvents(): void {
|
private subscribeToEvents(): void {
|
||||||
|
|
||||||
// Listen to drag events from DragDropManager
|
// Listen to drag events from DragDropManager
|
||||||
this.eventBus.on('drag:start', (event: Event) => {
|
this.eventBus.on('drag:start', () => {
|
||||||
let customEvent = event as CustomEvent<DragStartEventPayload>;
|
|
||||||
this.draggedClone = customEvent.detail.draggedClone;
|
|
||||||
this.startDrag();
|
this.startDrag();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.eventBus.on('drag:move', (event: Event) => {
|
|
||||||
let customEvent = event as CustomEvent<DragMoveEventPayload>;
|
|
||||||
this.draggedClone = customEvent.detail.draggedClone;
|
|
||||||
this.updateMouseY(customEvent.detail.mousePosition.y);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.eventBus.on('drag:end', () => this.stopDrag());
|
this.eventBus.on('drag:end', () => this.stopDrag());
|
||||||
this.eventBus.on('drag:cancelled', () => this.stopDrag());
|
this.eventBus.on('drag:cancelled', () => this.stopDrag());
|
||||||
}
|
}
|
||||||
|
|
@ -67,62 +59,25 @@ export class EdgeScrollManager {
|
||||||
private startDrag(): void {
|
private startDrag(): void {
|
||||||
console.log('🎬 EdgeScrollManager: Starting drag');
|
console.log('🎬 EdgeScrollManager: Starting drag');
|
||||||
this.isDragging = true;
|
this.isDragging = true;
|
||||||
|
this.isScrolling = false; // Reset scroll state
|
||||||
this.lastTs = performance.now();
|
this.lastTs = performance.now();
|
||||||
|
|
||||||
// Gem initial scroll position OG clone position
|
// Don't save initial positions here - wait until scrolling actually starts!
|
||||||
this.initialScrollTop = this.scrollableContent?.scrollTop || 0;
|
|
||||||
this.initialCloneTop = parseFloat(this.draggedClone?.style.top || '0');
|
|
||||||
|
|
||||||
console.log('💾 EdgeScrollManager: Saved initial state', {
|
|
||||||
initialScrollTop: this.initialScrollTop,
|
|
||||||
initialCloneTop: this.initialCloneTop
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.scrollRAF === null) {
|
if (this.scrollRAF === null) {
|
||||||
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
|
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateMouseY(y: number): void {
|
|
||||||
// console.log('🖱️ EdgeScrollManager: updateMouseY called', { oldMouseY: this.mouseY, newMouseY: y });
|
|
||||||
this.mouseY = y;
|
|
||||||
// Ensure RAF loop is running during drag
|
|
||||||
if (this.isDragging && this.scrollRAF === null) {
|
|
||||||
this.lastTs = performance.now();
|
|
||||||
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private stopDrag(): void {
|
private stopDrag(): void {
|
||||||
this.isDragging = false;
|
this.isDragging = false;
|
||||||
|
this.isScrolling = false;
|
||||||
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.draggedClone = null;
|
|
||||||
this.initialScrollTop = 0;
|
|
||||||
this.initialCloneTop = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleScroll(): void {
|
|
||||||
if (!this.isDragging || !this.draggedClone || !this.scrollableContent) return;
|
|
||||||
|
|
||||||
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`;
|
|
||||||
|
|
||||||
console.log('📜 EdgeScrollManager: Scroll event - updated clone', {
|
|
||||||
initialScrollTop: this.initialScrollTop,
|
|
||||||
currentScrollTop,
|
|
||||||
totalScrollDelta,
|
|
||||||
initialCloneTop: this.initialCloneTop,
|
|
||||||
newTop
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private scrollTick(ts: number): void {
|
private scrollTick(ts: number): void {
|
||||||
|
|
@ -159,11 +114,27 @@ 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
|
||||||
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));
|
||||||
} else {
|
} else {
|
||||||
|
// Mouse moved away from edge - stop scrolling
|
||||||
|
if (this.isScrolling) {
|
||||||
|
this.isScrolling = false;
|
||||||
|
console.log('🛑 EdgeScrollManager: Edge-scroll stopped');
|
||||||
|
// Notify DragDropManager that scroll compensation should stop
|
||||||
|
this.eventBus.emit('edgescroll:stopped', {});
|
||||||
|
}
|
||||||
|
|
||||||
// Continue RAF loop even if not scrolling, to detect edge entry
|
// Continue RAF loop even if not scrolling, to detect edge entry
|
||||||
if (this.isDragging) {
|
if (this.isDragging) {
|
||||||
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
|
this.scrollRAF = requestAnimationFrame((ts) => this.scrollTick(ts));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue