5.8 KiB
Stack Binding System - Calendar Plantempus
Oversigt
Dette dokument beskriver hvordan overlappende events er bundet sammen i Calendar Plantempus systemet, specifikt hvordan 2 eller flere events der ligger oven i hinanden (stacked) er forbundet.
Stack Binding Mekanisme
SimpleEventOverlapManager
Systemet bruger SimpleEventOverlapManager til at håndtere event overlap og stacking. Denne implementation bruger data-attributes på DOM elementerne til at holde styr på stack chains.
Hvordan Stacked Events er Bundet Sammen
Når 2 eller flere events ligger oven i hinanden, oprettes en linked list struktur via data-stack-link attributter:
Eksempel med 2 Events:
// Event A (base event):
<swp-event data-stack-link='{"stackLevel":0,"next":"event-B"}'>
// Event B (stacked event):
<swp-event data-stack-link='{"prev":"event-A","stackLevel":1}'>
Eksempel med 3 Events:
// Event A (base event):
<swp-event data-stack-link='{"stackLevel":0,"next":"event-B"}'>
// Event B (middle event):
<swp-event data-stack-link='{"prev":"event-A","next":"event-C","stackLevel":1}'>
// Event C (top event):
<swp-event data-stack-link='{"prev":"event-B","stackLevel":2}'>
StackLink Interface
interface StackLink {
prev?: string; // Event ID af forrige event i stacken
next?: string; // Event ID af næste event i stacken
stackLevel: number; // 0 = base event, 1 = første stacked, etc
}
Visual Styling
Hvert stacked event får automatisk styling baseret på deres stackLevel:
- Event A (base):
margin-left: 0px,z-index: 100 - Event B (middle):
margin-left: 15px,z-index: 101 - Event C (top):
margin-left: 30px,z-index: 102
Formel:
margin-left = stackLevel * 15pxz-index = 100 + stackLevel
Stack Chain Navigation
Systemet kan traversere stack chains i begge retninger:
// Find næste event i stacken
const link = getStackLink(currentElement);
if (link?.next) {
const nextElement = document.querySelector(`swp-event[data-event-id="${link.next}"]`);
}
// Find forrige event i stacken
if (link?.prev) {
const prevElement = document.querySelector(`swp-event[data-event-id="${link.prev}"]`);
}
Automatisk Chain Opdatering
Når events fjernes fra en stack, opdateres chain automatisk:
- Middle element fjernet: Prev og next events linkes direkte sammen
- Chain breaking: Hvis events ikke længere overlapper, brydes chain
- Stack level opdatering: Alle efterfølgende events får opdateret stackLevel
Overlap Detection
Events klassificeres som stacking hvis:
- De overlapper i tid OG
- Start tid forskel > 30 minutter
const timeDiffMinutes = Math.abs(
new Date(event1.start).getTime() - new Date(event2.start).getTime()
) / (1000 * 60);
return timeDiffMinutes > 30 ? OverlapType.STACKING : OverlapType.COLUMN_SHARING;
Eksempler
2 Events Stack
Event A: 09:00-11:00 (base) → margin-left: 0px, z-index: 100
Event B: 09:45-10:30 (stacked) → margin-left: 15px, z-index: 101
Stack chain:
A ←→ B
Data attributes:
- A:
{"stackLevel":0,"next":"B"} - B:
{"prev":"A","stackLevel":1}
3 Events Stack
Event A: 09:00-11:00 (base) → margin-left: 0px, z-index: 100
Event B: 09:45-10:30 (middle) → margin-left: 15px, z-index: 101
Event C: 10:15-11:15 (top) → margin-left: 30px, z-index: 102
Stack chain:
A ←→ B ←→ C
Data attributes:
- A:
{"stackLevel":0,"next":"B"} - B:
{"prev":"A","next":"C","stackLevel":1} - C:
{"prev":"B","stackLevel":2}
Visual Stack Chain Diagram
graph TD
A[Event A - Base Event] --> A1[data-stack-link]
B[Event B - Middle Event] --> B1[data-stack-link]
C[Event C - Top Event] --> C1[data-stack-link]
A1 --> A2[stackLevel: 0<br/>next: event-B]
B1 --> B2[prev: event-A<br/>next: event-C<br/>stackLevel: 1]
C1 --> C2[prev: event-B<br/>stackLevel: 2]
A2 --> A3[margin-left: 0px<br/>z-index: 100]
B2 --> B3[margin-left: 15px<br/>z-index: 101]
C2 --> C3[margin-left: 30px<br/>z-index: 102]
subgraph Stack Chain Navigation
A4[Event A] -.->|next| B4[Event B]
B4 -.->|next| C4[Event C]
C4 -.->|prev| B4
B4 -.->|prev| A4
end
subgraph Visual Result
V1[Event A - Full Width]
V2[Event B - 15px Offset]
V3[Event C - 30px Offset]
V1 -.-> V2
V2 -.-> V3
end
Stack Chain Operations
sequenceDiagram
participant DOM as DOM Element
participant SM as SimpleEventOverlapManager
participant Chain as Stack Chain
Note over DOM,Chain: Creating Stack Chain
DOM->>SM: createStackedEvent(eventB, eventA, 1)
SM->>Chain: Set eventA: {stackLevel:0, next:"eventB"}
SM->>Chain: Set eventB: {prev:"eventA", stackLevel:1}
SM->>DOM: Apply margin-left: 15px, z-index: 101
Note over DOM,Chain: Removing from Chain
DOM->>SM: removeStackedStyling(eventB)
SM->>Chain: Get eventB links
SM->>Chain: Link eventA -> eventC directly
SM->>Chain: Update eventC stackLevel: 1
SM->>DOM: Update eventC margin-left: 15px
SM->>Chain: Delete eventB entry
Fordele ved Data-Attribute Approach
- Ingen global state - alt information er på DOM elementerne
- Persistent - overlever DOM manipulationer
- Debuggable - kan inspiceres i browser dev tools
- Performant - ingen in-memory maps at vedligeholde
- Robust - automatisk cleanup når elements fjernes
Se Også
SimpleEventOverlapManager.ts- ImplementationEventRenderer.ts- Usage- Event Overlap CSS - Styling
- Complexity Comparison - Before/after analysis