Refactors all-day event layout calculation

Simplifies all-day event rendering by streamlining the layout
calculation and event placement process, using the AllDayLayoutEngine
to determine the grid positions. This removes deprecated methods
and improves overall code clarity.
This commit is contained in:
Janus C. H. Knudsen 2025-09-27 15:01:22 +02:00
parent 9dfd4574d8
commit 4141bffca4
7 changed files with 76 additions and 321 deletions

View file

@ -1,7 +1,7 @@
import { CalendarEvent } from '../types/CalendarTypes';
export interface EventLayout {
id: string;
calenderEvent: CalendarEvent;
gridArea: string; // "row-start / col-start / row-end / col-end"
startColumn: number;
endColumn: number;
@ -21,42 +21,38 @@ export class AllDayLayoutEngine {
/**
* Calculate layout for all events using clean day-based logic
*/
public calculateLayout(events: CalendarEvent[]): Map<string, EventLayout> {
const layouts = new Map<string, EventLayout>();
if (this.weekDates.length === 0) {
return layouts;
}
public calculateLayout(events: CalendarEvent[]): EventLayout[] {
let layouts: EventLayout[] = [];
// Reset tracks for new calculation
this.tracks = [new Array(this.weekDates.length).fill(false)];
// Filter to only visible events
const visibleEvents = events.filter(event => this.isEventVisible(event));
// Process events in input order (no sorting)
for (const event of visibleEvents) {
const startDay = this.getEventStartDay(event);
const endDay = this.getEventEndDay(event);
if (startDay > 0 && endDay > 0) {
const track = this.findAvailableTrack(startDay - 1, endDay - 1); // Convert to 0-based for tracks
// Mark days as occupied
for (let day = startDay - 1; day <= endDay - 1; day++) {
this.tracks[track][day] = true;
}
const layout: EventLayout = {
id: event.id,
calenderEvent: event,
gridArea: `${track + 1} / ${startDay} / ${track + 2} / ${endDay + 1}`,
startColumn: startDay,
endColumn: endDay,
row: track + 1,
columnSpan: endDay - startDay + 1
};
layouts.set(event.id, layout);
layouts.push(layout);
}
}
@ -72,7 +68,7 @@ export class AllDayLayoutEngine {
return trackIndex;
}
}
// Create new track if none available
this.tracks.push(new Array(this.weekDates.length).fill(false));
return this.tracks.length - 1;
@ -96,10 +92,10 @@ export class AllDayLayoutEngine {
private getEventStartDay(event: CalendarEvent): number {
const eventStartDate = this.formatDate(event.start);
const firstVisibleDate = this.weekDates[0];
// If event starts before visible range, clip to first visible day
const clippedStartDate = eventStartDate < firstVisibleDate ? firstVisibleDate : eventStartDate;
const dayIndex = this.weekDates.indexOf(clippedStartDate);
return dayIndex >= 0 ? dayIndex + 1 : 0;
}
@ -110,10 +106,10 @@ export class AllDayLayoutEngine {
private getEventEndDay(event: CalendarEvent): number {
const eventEndDate = this.formatDate(event.end);
const lastVisibleDate = this.weekDates[this.weekDates.length - 1];
// If event ends after visible range, clip to last visible day
const clippedEndDate = eventEndDate > lastVisibleDate ? lastVisibleDate : eventEndDate;
const dayIndex = this.weekDates.indexOf(clippedEndDate);
return dayIndex >= 0 ? dayIndex + 1 : 0;
}
@ -123,12 +119,12 @@ export class AllDayLayoutEngine {
*/
private isEventVisible(event: CalendarEvent): boolean {
if (this.weekDates.length === 0) return false;
const eventStartDate = this.formatDate(event.start);
const eventEndDate = this.formatDate(event.end);
const firstVisibleDate = this.weekDates[0];
const lastVisibleDate = this.weekDates[this.weekDates.length - 1];
// Event overlaps if it doesn't end before visible range starts
// AND doesn't start after visible range ends
return !(eventEndDate < firstVisibleDate || eventStartDate > lastVisibleDate);