diff --git a/.workbench/image.png b/.workbench/image.png index 17aa388..2d7c269 100644 Binary files a/.workbench/image.png and b/.workbench/image.png differ diff --git a/.workbench/scenarie9.html b/.workbench/scenarie9.html new file mode 100644 index 0000000..1c6faec --- /dev/null +++ b/.workbench/scenarie9.html @@ -0,0 +1,11 @@ +
+ 12:00 - 13:00 + Scenario 9: Event A +
+ 12:30 - 13:30 + Scenario 9: Event B +
+ + 13:15 - 15:00 + Scenario 9: Event C + \ No newline at end of file diff --git a/src/managers/EventLayoutCoordinator.ts b/src/managers/EventLayoutCoordinator.ts index 8d4da38..b210876 100644 --- a/src/managers/EventLayoutCoordinator.ts +++ b/src/managers/EventLayoutCoordinator.ts @@ -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 + } + } } }