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.
This commit is contained in:
Janus Knudsen 2025-09-04 20:32:25 +02:00
parent 1aef54bffb
commit f5a6b80549
2 changed files with 39 additions and 10 deletions

View file

@ -25,6 +25,7 @@ export class EventOverlapManager {
private static readonly STACKING_WIDTH_REDUCTION_PX = 15; private static readonly STACKING_WIDTH_REDUCTION_PX = 15;
private nextZIndex = 100; private nextZIndex = 100;
/** /**
* Detect overlap mellem events baseret faktisk time overlap og start tid forskel * Detect overlap mellem events baseret faktisk time overlap og start tid forskel
*/ */
@ -200,6 +201,7 @@ export class EventOverlapManager {
eventElement.style.zIndex = ''; eventElement.style.zIndex = '';
} }
/** /**
* Beregn position for event gruppe * Beregn position for event gruppe
*/ */

View file

@ -355,6 +355,35 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
// Behold z-index for stacked events // 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 * Detect overlaps with other events in target column and handle repositioning
*/ */
@ -378,10 +407,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
let overlapsWithGroup = false; let overlapsWithGroup = false;
for (const groupEvent of groupEvents) { for (const groupEvent of groupEvents) {
const existingEvent = this.elementToCalendarEvent(groupEvent); const overlapType = this.detectPixelOverlap(droppedElement, groupEvent);
if (!existingEvent) continue;
const overlapType = this.overlapManager.detectOverlap(droppedEvent, existingEvent);
if (overlapType === OverlapType.COLUMN_SHARING) { if (overlapType === OverlapType.COLUMN_SHARING) {
overlapsWithGroup = true; overlapsWithGroup = true;
break; break;
@ -405,18 +431,18 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
const overlappingEvents: CalendarEvent[] = []; const overlappingEvents: CalendarEvent[] = [];
for (const existingElement of existingEvents) { for (const existingElement of existingEvents) {
const existingEvent = this.elementToCalendarEvent(existingElement);
if (!existingEvent) continue;
// Skip if it's the same event (comparing IDs) // 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) { if (overlapType !== OverlapType.NONE) {
hasOverlaps = true; hasOverlaps = true;
const existingEvent = this.elementToCalendarEvent(existingElement);
if (existingEvent) {
overlappingEvents.push(existingEvent); overlappingEvents.push(existingEvent);
} }
} }
}
// Add dropped event LAST so it appears rightmost in flexbox // Add dropped event LAST so it appears rightmost in flexbox
overlappingEvents.push(droppedEvent); overlappingEvents.push(droppedEvent);
@ -941,6 +967,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy {
return !(event1End < event2Span.startColumn || event2End < event1Span.startColumn); return !(event1End < event2Span.startColumn || event2End < event1Span.startColumn);
} }
/** /**
* Render column sharing group with flexbox container * Render column sharing group with flexbox container
*/ */