wip
This commit is contained in:
parent
727a6ec53a
commit
72019a3d9a
15 changed files with 1056 additions and 1230 deletions
204
docs/stack-binding-system.md
Normal file
204
docs/stack-binding-system.md
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
# 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:
|
||||
```typescript
|
||||
// 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:
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
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 * 15px`
|
||||
- `z-index = 100 + stackLevel`
|
||||
|
||||
### Stack Chain Navigation
|
||||
|
||||
Systemet kan traversere stack chains i begge retninger:
|
||||
|
||||
```typescript
|
||||
// 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:
|
||||
|
||||
1. **Middle element fjernet**: Prev og next events linkes direkte sammen
|
||||
2. **Chain breaking**: Hvis events ikke længere overlapper, brydes chain
|
||||
3. **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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
1. **Ingen global state** - alt information er på DOM elementerne
|
||||
2. **Persistent** - overlever DOM manipulationer
|
||||
3. **Debuggable** - kan inspiceres i browser dev tools
|
||||
4. **Performant** - ingen in-memory maps at vedligeholde
|
||||
5. **Robust** - automatisk cleanup når elements fjernes
|
||||
|
||||
## Se Også
|
||||
|
||||
- [`SimpleEventOverlapManager.ts`](../src/managers/SimpleEventOverlapManager.ts) - Implementation
|
||||
- [`EventRenderer.ts`](../src/renderers/EventRenderer.ts) - Usage
|
||||
- [Event Overlap CSS](../wwwroot/css/calendar-events-css.css) - Styling
|
||||
- [Complexity Comparison](../complexity_comparison.md) - Before/after analysis
|
||||
Loading…
Add table
Add a link
Reference in a new issue