# Data-Attribute Stack Tracking Solution
## Implementation Summary
Vi har nu implementeret stack tracking via data attributes i stedet for komplekse Map-baserede linked lists.
### π― **How it works:**
#### **Stack Links via Data Attributes**
```html
```
### π§ **Key Methods:**
#### **createStackedEvent()**
```typescript
// Links new event to end of chain
let lastElement = underlyingElement;
while (lastLink?.next) {
lastElement = this.findElementById(lastLink.next);
lastLink = this.getStackLink(lastElement);
}
// Create bidirectional link
this.setStackLink(lastElement, { ...lastLink, next: eventId });
this.setStackLink(eventElement, { prev: lastElementId, stackLevel });
```
#### **removeStackedStyling()**
```typescript
// Re-link prev and next
if (link.prev && link.next) {
this.setStackLink(prevElement, { ...prevLink, next: link.next });
this.setStackLink(nextElement, { ...nextLink, prev: link.prev });
}
// Update subsequent stack levels
this.updateSubsequentStackLevels(link.next, -1);
```
#### **restackEventsInContainer()**
```typescript
// Group by stack chains (not all stacked events together!)
for (const element of stackedEvents) {
// Find root of chain
while (rootLink?.prev) {
rootElement = this.findElementById(rootLink.prev);
}
// Collect entire chain
// Re-stack each chain separately
}
```
---
## π **Advantages vs Map Solution:**
### β
**Simplified State Management**
| Aspect | Map + Linked List | Data Attributes |
|--------|------------------|-----------------|
| **State Location** | Separate Map object | In DOM elements |
| **Synchronization** | Manual sync required | Automatic with DOM |
| **Memory Cleanup** | Manual Map cleanup | Automatic with element removal |
| **Debugging** | Console logs only | DevTools inspection |
| **State Consistency** | Possible sync bugs | Always consistent |
### β
**Code Complexity Reduction**
```typescript
// OLD: Complex Map management
private stackChains = new Map();
// Find last event in chain - complex iteration
let lastEventId = underlyingId;
while (this.stackChains.has(lastEventId) && this.stackChains.get(lastEventId)?.next) {
lastEventId = this.stackChains.get(lastEventId)!.next!;
}
// Link events - error prone
this.stackChains.get(lastEventId)!.next = eventId;
this.stackChains.set(eventId, { prev: lastEventId, stackLevel });
// NEW: Simple data attribute management
let lastElement = underlyingElement;
while (lastLink?.next) {
lastElement = this.findElementById(lastLink.next);
}
this.setStackLink(lastElement, { ...lastLink, next: eventId });
this.setStackLink(eventElement, { prev: lastElementId, stackLevel });
```
### β
**Better Error Handling**
```typescript
// DOM elements can't get out of sync with their own attributes
// When element is removed, its state automatically disappears
// No orphaned Map entries
```
---
## π§ͺ **Test Scenarios:**
### **Scenario 1: Multiple Separate Stacks**
```
Column has:
Stack A: Event1 β Event2 β Event3 (times: 09:00-10:00, 09:15-10:15, 09:30-10:30)
Stack B: Event4 β Event5 (times: 14:00-15:00, 14:10-15:10)
Remove Event2 (middle of Stack A):
β
Expected: Event1 β Event3 (Event3 moves to 15px margin)
β
Expected: Stack B unchanged (Event4βEvent5 still at 0pxβ15px)
β Old naive approach: Would group all events together
```
### **Scenario 2: Remove Base Event**
```
Stack: EventA(base) β EventB β EventC
Remove EventA:
β
Expected: EventB becomes base (0px), EventC moves to 15px
β
Data-attribute solution: EventB.stackLevel = 0, EventC.stackLevel = 1
```
### **Scenario 3: Drag and Drop**
```
Drag Event2 from Stack A to new position:
β
removeStackedStyling() handles re-linking
β
Other stack events maintain their relationships
β
No Map synchronization issues
```
---
## π **Debugging Benefits:**
### **Browser DevTools Inspection:**
```html
```
### **Console Debugging:**
```javascript
// Easy to inspect stack chains
const element = document.querySelector('[data-event-id="456"]');
const link = JSON.parse(element.dataset.stackLink);
console.log('Stack chain:', link);
```
---
## π **Performance Comparison:**
| Operation | Map Solution | Data-Attribute Solution |
|-----------|--------------|-------------------------|
| **Create Stack** | Map.set() + element.style | JSON.stringify() + element.style |
| **Remove Stack** | Map manipulation + DOM queries | JSON.parse/stringify + DOM queries |
| **Find Chain** | Map iteration | DOM traversal |
| **Memory Usage** | Map + DOM | DOM only |
| **Sync Overhead** | High (keep Map in sync) | None (DOM is source) |
### **Performance Notes:**
- **JSON.parse/stringify**: Very fast for small objects (~10 properties max)
- **DOM traversal**: Limited by chain length (typically 2-5 events)
- **Memory**: Significant reduction (no separate Map)
- **Garbage collection**: Better (automatic cleanup)
---
## β
**Solution Status:**
### **Completed:**
- [x] StackLink interface definition
- [x] Helper methods (getStackLink, setStackLink, findElementById)
- [x] createStackedEvent with data-attribute linking
- [x] removeStackedStyling with proper re-linking
- [x] restackEventsInContainer respects separate chains
- [x] isStackedEvent checks both style and data-attributes
- [x] Compilation successful
### **Ready for Testing:**
- [ ] Manual UI testing of stack behavior
- [ ] Drag and drop stacked events
- [ ] Multiple stacks in same column
- [ ] Edge cases (remove first/middle/last)
---
## π **Conclusion:**
This data-attribute solution provides:
1. **Same functionality** as the Map-based approach
2. **Simpler implementation** (DOM as single source of truth)
3. **Better debugging experience** (DevTools visibility)
4. **Automatic memory management** (no manual cleanup)
5. **No synchronization bugs** (state follows element)
The solution maintains all the precision of the original complex system while dramatically simplifying the implementation and eliminating entire classes of potential bugs.