This commit is contained in:
Janus Knudsen 2025-09-09 14:35:21 +02:00
parent 727a6ec53a
commit 72019a3d9a
15 changed files with 1056 additions and 1230 deletions

View file

@ -0,0 +1,75 @@
/**
* OverlapDetector - Ren tidbaseret overlap detection
* Ingen DOM manipulation, kun tidsberegninger
*/
import { CalendarEvent } from '../types/CalendarTypes';
// Branded type for event IDs
export type EventId = string & { readonly __brand: 'EventId' };
export type OverlapResult = {
overlappingEvents: CalendarEvent[];
stackLinks: Map<EventId, StackLink>;
};
export interface StackLink {
prev?: EventId; // Event ID of previous event in stack
next?: EventId; // Event ID of next event in stack
stackLevel: number; // 0 = base event, 1 = first stacked, etc
}
export class OverlapDetector {
/**
* Resolver hvilke events et givent event overlapper med i en kolonne
* @param event - CalendarEvent der skal checkes for overlap
* @param columnEvents - Array af CalendarEvent objekter i kolonnen
* @returns Array af events som det givne event overlapper med
*/
public resolveOverlap(event: CalendarEvent, columnEvents: CalendarEvent[]): CalendarEvent[] {
return columnEvents.filter(existingEvent => {
// To events overlapper hvis:
// event starter før existing slutter OG
// event slutter efter existing starter
return event.start < existingEvent.end && event.end > existingEvent.start;
});
}
/**
* Dekorerer events med stack linking data
* @param newEvent - Det nye event der skal tilføjes
* @param overlappingEvents - Events som det nye event overlapper med
* @returns OverlapResult med overlappende events og stack links
*/
public decorateWithStackLinks(newEvent: CalendarEvent, overlappingEvents: CalendarEvent[]): OverlapResult {
const stackLinks = new Map<EventId, StackLink>();
if (overlappingEvents.length === 0) {
return {
overlappingEvents: [],
stackLinks
};
}
// Kombiner nyt event med eksisterende og sortér efter start tid (tidligste første)
const allEvents = [...overlappingEvents, newEvent].sort((a, b) =>
a.start.getTime() - b.start.getTime()
);
// Opret sammenhængende kæde - alle events bindes sammen
allEvents.forEach((event, index) => {
const stackLink: StackLink = {
stackLevel: index,
prev: index > 0 ? allEvents[index - 1].id as EventId : undefined,
next: index < allEvents.length - 1 ? allEvents[index + 1].id as EventId : undefined
};
stackLinks.set(event.id as EventId, stackLink);
});
return {
overlappingEvents,
stackLinks
};
}
}