From f5a6b80549bd929308d68feef5f9f8432a129a74 Mon Sep 17 00:00:00 2001 From: Janus Knudsen Date: Thu, 4 Sep 2025 20:32:25 +0200 Subject: [PATCH] Improves event overlap detection Refactors event overlap detection to use pixel-based comparison. This improves accuracy and addresses issues with incorrect overlap calculations when events have slight time differences but visually overlap. It removes dependency on the event manager and the need to convert elements to calendar events for overlap detection. --- src/managers/EventOverlapManager.ts | 2 ++ src/renderers/EventRenderer.ts | 47 +++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/managers/EventOverlapManager.ts b/src/managers/EventOverlapManager.ts index c03bfd2..e796f11 100644 --- a/src/managers/EventOverlapManager.ts +++ b/src/managers/EventOverlapManager.ts @@ -25,6 +25,7 @@ export class EventOverlapManager { private static readonly STACKING_WIDTH_REDUCTION_PX = 15; private nextZIndex = 100; + /** * Detect overlap mellem events baseret på faktisk time overlap og start tid forskel */ @@ -200,6 +201,7 @@ export class EventOverlapManager { eventElement.style.zIndex = ''; } + /** * Beregn position for event gruppe */ diff --git a/src/renderers/EventRenderer.ts b/src/renderers/EventRenderer.ts index a361f7f..ccdedcf 100644 --- a/src/renderers/EventRenderer.ts +++ b/src/renderers/EventRenderer.ts @@ -355,6 +355,35 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { // Behold z-index for stacked events } + /** + * Detect pixel-based overlap between two event elements + */ + private detectPixelOverlap(element1: HTMLElement, element2: HTMLElement): OverlapType { + const top1 = parseFloat(element1.style.top) || 0; + const height1 = parseFloat(element1.style.height) || 0; + const bottom1 = top1 + height1; + + const top2 = parseFloat(element2.style.top) || 0; + const height2 = parseFloat(element2.style.height) || 0; + const bottom2 = top2 + height2; + + // Check if events overlap in time (pixel space) + if (bottom1 <= top2 || bottom2 <= top1) { + return OverlapType.NONE; + } + + // Events overlap - check start position difference for overlap type + const startDifference = Math.abs(top1 - top2); + + // Over 40px start difference = stacking + if (startDifference > 40) { + return OverlapType.STACKING; + } + + // Within 40px start difference = column sharing + return OverlapType.COLUMN_SHARING; + } + /** * Detect overlaps with other events in target column and handle repositioning */ @@ -378,10 +407,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { let overlapsWithGroup = false; for (const groupEvent of groupEvents) { - const existingEvent = this.elementToCalendarEvent(groupEvent); - if (!existingEvent) continue; - - const overlapType = this.overlapManager.detectOverlap(droppedEvent, existingEvent); + const overlapType = this.detectPixelOverlap(droppedElement, groupEvent); if (overlapType === OverlapType.COLUMN_SHARING) { overlapsWithGroup = true; break; @@ -405,16 +431,16 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { const overlappingEvents: CalendarEvent[] = []; for (const existingElement of existingEvents) { - const existingEvent = this.elementToCalendarEvent(existingElement); - if (!existingEvent) continue; - // Skip if it's the same event (comparing IDs) - if (existingEvent.id === droppedEvent.id) continue; + if (existingElement.dataset.eventId === droppedEvent.id) continue; - const overlapType = this.overlapManager.detectOverlap(droppedEvent, existingEvent); + const overlapType = this.detectPixelOverlap(droppedElement, existingElement); if (overlapType !== OverlapType.NONE) { hasOverlaps = true; - overlappingEvents.push(existingEvent); + const existingEvent = this.elementToCalendarEvent(existingElement); + if (existingEvent) { + overlappingEvents.push(existingEvent); + } } } @@ -941,6 +967,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { return !(event1End < event2Span.startColumn || event2End < event1Span.startColumn); } + /** * Render column sharing group with flexbox container */