Improves event grid layout logic

Refines the event grid layout algorithm to more accurately
identify conflicting events for stacking within the grid.

Now uses an expanding search to find chains of conflicting events,
ensuring that all events that should be grouped together are
correctly identified.
This commit is contained in:
Janus C. H. Knudsen 2025-10-06 18:46:07 +02:00
parent 06356df2a3
commit b590467f60
3 changed files with 51 additions and 7 deletions

View file

@ -54,18 +54,51 @@ export class EventLayoutCoordinator {
const firstEvent = remaining[0];
// Find events that could be in GRID with first event
// (start within threshold AND overlap)
// Use expanding search to find chains (A→B→C where each conflicts with next)
const gridSettings = calendarConfig.getGridSettings();
const thresholdMinutes = gridSettings.gridStartThresholdMinutes;
const gridCandidates = [firstEvent];
for (let i = 1; i < remaining.length; i++) {
const candidate = remaining[i];
const startDiff = Math.abs(candidate.start.getTime() - firstEvent.start.getTime()) / (1000 * 60);
let candidatesChanged = true;
// Only add if starts within threshold AND overlaps with firstEvent
if (startDiff <= thresholdMinutes && this.stackManager.doEventsOverlap(firstEvent, candidate)) {
gridCandidates.push(candidate);
// Keep expanding until no new candidates can be added
while (candidatesChanged) {
candidatesChanged = false;
for (let i = 1; i < remaining.length; i++) {
const candidate = remaining[i];
// Skip if already in candidates
if (gridCandidates.includes(candidate)) continue;
// Check if candidate conflicts with ANY event in gridCandidates
for (const existingCandidate of gridCandidates) {
let hasConflict = false;
// Check 1: Start-to-start conflict (starts within threshold)
const startToStartDiff = Math.abs(candidate.start.getTime() - existingCandidate.start.getTime()) / (1000 * 60);
if (startToStartDiff <= thresholdMinutes && this.stackManager.doEventsOverlap(candidate, existingCandidate)) {
hasConflict = true;
}
// Check 2: End-to-start conflict (candidate starts within threshold before existingCandidate ends)
const endToStartMinutes = (existingCandidate.end.getTime() - candidate.start.getTime()) / (1000 * 60);
if (endToStartMinutes > 0 && endToStartMinutes <= thresholdMinutes) {
hasConflict = true;
}
// Check 3: Reverse end-to-start (existingCandidate starts within threshold before candidate ends)
const reverseEndToStart = (candidate.end.getTime() - existingCandidate.start.getTime()) / (1000 * 60);
if (reverseEndToStart > 0 && reverseEndToStart <= thresholdMinutes) {
hasConflict = true;
}
if (hasConflict) {
gridCandidates.push(candidate);
candidatesChanged = true;
break; // Found conflict, move to next candidate
}
}
}
}