108 lines
No EOL
4.3 KiB
JavaScript
108 lines
No EOL
4.3 KiB
JavaScript
export class AllDayLayoutEngine {
|
|
constructor(weekDates) {
|
|
this.weekDates = weekDates;
|
|
this.tracks = [];
|
|
}
|
|
/**
|
|
* Calculate layout for all events using clean day-based logic
|
|
*/
|
|
calculateLayout(events) {
|
|
let layouts = [];
|
|
// 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 = {
|
|
calenderEvent: event,
|
|
gridArea: `${track + 1} / ${startDay} / ${track + 2} / ${endDay + 1}`,
|
|
startColumn: startDay,
|
|
endColumn: endDay,
|
|
row: track + 1,
|
|
columnSpan: endDay - startDay + 1
|
|
};
|
|
layouts.push(layout);
|
|
}
|
|
}
|
|
return layouts;
|
|
}
|
|
/**
|
|
* Find available track for event spanning from startDay to endDay (0-based indices)
|
|
*/
|
|
findAvailableTrack(startDay, endDay) {
|
|
for (let trackIndex = 0; trackIndex < this.tracks.length; trackIndex++) {
|
|
if (this.isTrackAvailable(trackIndex, startDay, endDay)) {
|
|
return trackIndex;
|
|
}
|
|
}
|
|
// Create new track if none available
|
|
this.tracks.push(new Array(this.weekDates.length).fill(false));
|
|
return this.tracks.length - 1;
|
|
}
|
|
/**
|
|
* Check if track is available for the given day range (0-based indices)
|
|
*/
|
|
isTrackAvailable(trackIndex, startDay, endDay) {
|
|
for (let day = startDay; day <= endDay; day++) {
|
|
if (this.tracks[trackIndex][day]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
* Get start day index for event (1-based, 0 if not visible)
|
|
*/
|
|
getEventStartDay(event) {
|
|
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;
|
|
}
|
|
/**
|
|
* Get end day index for event (1-based, 0 if not visible)
|
|
*/
|
|
getEventEndDay(event) {
|
|
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;
|
|
}
|
|
/**
|
|
* Check if event is visible in the current date range
|
|
*/
|
|
isEventVisible(event) {
|
|
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);
|
|
}
|
|
/**
|
|
* Format date to YYYY-MM-DD string using local date
|
|
*/
|
|
formatDate(date) {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
}
|
|
//# sourceMappingURL=AllDayLayoutEngine.js.map
|