/** * EventStackManager - Manages visual stacking of overlapping calendar events * * This class handles the creation and maintenance of "stack chains" - doubly-linked * lists of overlapping events stored directly in DOM elements via data attributes. * * Implements 3-phase algorithm for grid + nested stacking: * Phase 1: Group events by start time proximity (configurable threshold) * Phase 2: Decide container type (GRID vs STACKING) * Phase 3: Handle late arrivals (nested stacking - NOT IMPLEMENTED) * * @see STACKING_CONCEPT.md for detailed documentation * @see stacking-visualization.html for visual examples */ import { ICalendarEvent } from '../types/CalendarTypes'; import { Configuration } from '../configurations/CalendarConfig'; export interface IStackLink { prev?: string; next?: string; stackLevel: number; } export interface IEventGroup { events: ICalendarEvent[]; containerType: 'NONE' | 'GRID' | 'STACKING'; startTime: Date; } export declare class EventStackManager { private static readonly STACK_OFFSET_PX; private config; constructor(config: Configuration); /** * Group events by time conflicts (both start-to-start and end-to-start within threshold) * * Events are grouped if: * 1. They start within ±threshold minutes of each other (start-to-start) * 2. One event starts within threshold minutes before another ends (end-to-start conflict) */ groupEventsByStartTime(events: ICalendarEvent[]): IEventGroup[]; /** * Decide container type for a group of events * * Rule: Events starting simultaneously (within threshold) should ALWAYS use GRID, * even if they overlap each other. This provides better visual indication that * events start at the same time. */ decideContainerType(group: IEventGroup): 'NONE' | 'GRID' | 'STACKING'; /** * Check if two events overlap in time */ doEventsOverlap(event1: ICalendarEvent, event2: ICalendarEvent): boolean; /** * Create optimized stack links (events share levels when possible) */ createOptimizedStackLinks(events: ICalendarEvent[]): Map; /** * Calculate marginLeft based on stack level */ calculateMarginLeft(stackLevel: number): number; /** * Calculate zIndex based on stack level */ calculateZIndex(stackLevel: number): number; /** * Serialize stack link to JSON string */ serializeStackLink(stackLink: IStackLink): string; /** * Deserialize JSON string to stack link */ deserializeStackLink(json: string): IStackLink | null; /** * Apply stack link to DOM element */ applyStackLinkToElement(element: HTMLElement, stackLink: IStackLink): void; /** * Get stack link from DOM element */ getStackLinkFromElement(element: HTMLElement): IStackLink | null; /** * Apply visual styling to element based on stack level */ applyVisualStyling(element: HTMLElement, stackLevel: number): void; /** * Clear stack link from element */ clearStackLinkFromElement(element: HTMLElement): void; /** * Clear visual styling from element */ clearVisualStyling(element: HTMLElement): void; }