Stacking and Sharecolumn WIP
This commit is contained in:
parent
c788a1695e
commit
6b8c5d4673
7 changed files with 763 additions and 51 deletions
|
|
@ -1415,6 +1415,397 @@ Result: One algorithm handles ALL scenarios!</pre>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scenario 8: Edge Case - Exactly 15 min apart with overlap -->
|
||||
<div class="section">
|
||||
<h2>Scenario 8: Edge Case - Events Starting Exactly 15 Minutes Apart (WITH Overlap)</h2>
|
||||
<p><strong>Edge Case:</strong> What happens when events start exactly at the ±15 min threshold AND overlap?</p>
|
||||
|
||||
<p><strong>Events:</strong></p>
|
||||
<ul style="margin: 10px 0 20px 20px;">
|
||||
<li>Event A: 11:00 - 12:00 (1 hour)</li>
|
||||
<li>Event B: 11:15 - 12:30 (1.25 hours)</li>
|
||||
</ul>
|
||||
|
||||
<div class="note">
|
||||
<strong>Analysis:</strong><br>
|
||||
• A starts at 11:00<br>
|
||||
• B starts at 11:15 (diff = 15 min ≤ 15 min) → <strong>Within threshold</strong> ✓<br>
|
||||
• A and B overlap (11:15 - 12:00) → <strong>They DO overlap</strong> ✓<br>
|
||||
• <strong>Visual priority:</strong> Show that they start simultaneously (±15 min)<br>
|
||||
• <strong>Result:</strong> Use GRID (column sharing) even though they overlap
|
||||
</div>
|
||||
|
||||
<div class="comparison">
|
||||
<!-- Wrong: Stacking -->
|
||||
<div class="calendar-column">
|
||||
<div class="column-title">❌ Wrong: Stacking (Hides Simultaneity)</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div class="time-marker" style="top: 0%">11:00</div>
|
||||
<div class="time-marker" style="top: 33%">11:30</div>
|
||||
<div class="time-marker" style="top: 66%">12:00</div>
|
||||
<div class="time-marker" style="top: 100%">12:30</div>
|
||||
</div>
|
||||
|
||||
<div class="events-container" style="height: 180px;">
|
||||
<!-- Event A: 11:00-12:00 (60 min = 66.7% of 90 min total) -->
|
||||
<div class="event event-a" style="top: 0%; height: 66.7%; left: 2px; right: 2px; z-index: 100;">
|
||||
Event A<br>
|
||||
<span style="font-size: 11px; opacity: 0.8;">11:00-12:00</span>
|
||||
</div>
|
||||
|
||||
<!-- Event B: 11:15-12:30 (75 min = 83.3% of 90 min total, starts at 16.7%) -->
|
||||
<div class="event event-b" style="top: 16.7%; height: 83.3%; left: 17px; right: 2px; z-index: 101; margin-left: 15px;">
|
||||
Event B<br>
|
||||
<span style="font-size: 11px; opacity: 0.8;">11:15-12:30</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="savings wrong">
|
||||
<strong>Problems:</strong><br>
|
||||
• B is offset to the right → looks like it happens AFTER A<br>
|
||||
• Doesn't convey that they start almost simultaneously (15 min apart)<br>
|
||||
• Wastes horizontal space
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: GRID -->
|
||||
<div class="calendar-column">
|
||||
<div class="column-title">✅ Correct: GRID Column Sharing</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div class="time-marker" style="top: 0%">11:00</div>
|
||||
<div class="time-marker" style="top: 33%">11:30</div>
|
||||
<div class="time-marker" style="top: 66%">12:00</div>
|
||||
<div class="time-marker" style="top: 100%">12:30</div>
|
||||
</div>
|
||||
|
||||
<div class="events-container" style="height: 180px;">
|
||||
<!-- Grid container for A and B -->
|
||||
<div style="position: absolute; top: 0%; left: 2px; right: 2px; display: grid; grid-template-columns: 1fr 1fr; gap: 2px; z-index: 100;">
|
||||
<!-- Event A: 11:00-12:00 -->
|
||||
<div class="event event-a" style="position: relative; height: 120px;">
|
||||
Event A<br>
|
||||
<span style="font-size: 11px; opacity: 0.8;">11:00-12:00</span>
|
||||
</div>
|
||||
|
||||
<!-- Event B: 11:15-12:30 (starts 15 min later = 10% offset) -->
|
||||
<div class="event event-b" style="position: relative; height: 150px; top: 10%;">
|
||||
Event B<br>
|
||||
<span style="font-size: 11px; opacity: 0.8;">11:15-12:30</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="savings">
|
||||
<strong>Benefits:</strong><br>
|
||||
• Side-by-side layout shows they're concurrent<br>
|
||||
• Each event gets 50% width<br>
|
||||
• Clear visual: these events start nearly simultaneously (±15 min)<br>
|
||||
• Despite overlapping, simultaneity is visual priority
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
<strong>Key Rule:</strong> Events starting within ±15 minutes should ALWAYS use GRID (column sharing),
|
||||
even if they overlap. The visual priority is to show that events start <em>simultaneously</em>,
|
||||
not to avoid overlap. Overlap is handled by the grid container having appropriate height.
|
||||
</div>
|
||||
|
||||
<div class="code-example">
|
||||
<strong>Expected Behavior:</strong>
|
||||
<pre style="background: #f8f8f8; padding: 15px; border-radius: 4px; overflow-x: auto; font-size: 13px;">
|
||||
// Phase 1: Group by start time
|
||||
groupEventsByStartTime([A, B])
|
||||
→ Group 1: [A, B] // 15 min apart ≤ threshold
|
||||
|
||||
// Phase 2: Decide container type
|
||||
decideContainerType(Group 1)
|
||||
→ GRID // Always GRID for grouped events, even if overlapping
|
||||
|
||||
// Phase 3: Calculate stack level
|
||||
calculateGridGroupStackLevel(Group 1)
|
||||
→ stackLevel: 0 // No other events to stack above
|
||||
|
||||
// Result:
|
||||
<swp-event-group class="cols-2 stack-level-0" style="top: 0px; margin-left: 0px; z-index: 100;">
|
||||
<swp-event data-event-id="A" style="height: 120px;">Event A</swp-event>
|
||||
<swp-event data-event-id="B" style="height: 150px; top: 10%;">Event B</swp-event>
|
||||
</swp-event-group></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================================ -->
|
||||
<!-- SCENARIO 9: Grid with Staggered Start Times -->
|
||||
<!-- ============================================ -->
|
||||
<div class="section">
|
||||
<h2>Scenario 9: Grid with Staggered Start Times</h2>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><strong>Event A:</strong> 09:00 - 10:00 (1 hour)</div>
|
||||
<div class="legend-item"><strong>Event B:</strong> 09:30 - 10:30 (1 hour, starts 30 min after A)</div>
|
||||
<div class="legend-item"><strong>Event C:</strong> 10:15 - 12:00 (1h 45min, starts 45 min after B)</div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
<strong>Special Case: End-to-Start Conflicts Create Shared Columns</strong><br><br>
|
||||
• Event A: 09:00 - 10:00<br>
|
||||
• Event B: 09:30 - 10:30 (starts 30 min before A ends → conflicts with A)<br>
|
||||
• Event C: 10:15 - 12:00 (starts 15 min before B ends → conflicts with B)<br><br>
|
||||
<strong>Key Rule:</strong> Events share columns (GRID) when they conflict within threshold<br>
|
||||
• Conflict = Event starts within ±threshold minutes of another event's end time<br>
|
||||
• A and B: B starts 30 min before A ends → conflict (≤ 30 min threshold)<br>
|
||||
• B and C: C starts 15 min before B ends → conflict (≤ 30 min threshold)<br>
|
||||
• Therefore: A, B, and C all share columns in a 3-column GRID<br><br>
|
||||
<strong>With threshold = 15 min:</strong> Only A-B conflict (30 min > 15), C is separate → Stack<br>
|
||||
<strong>With threshold = 30 min:</strong> Both A-B and B-C conflict → All 3 share columns in GRID
|
||||
</div>
|
||||
|
||||
<div class="comparison">
|
||||
<!-- Threshold = 15 min -->
|
||||
<div class="calendar-column">
|
||||
<div class="column-title">With Threshold = 15 min</div>
|
||||
<div class="timeline">
|
||||
<div class="time-marker" style="top: 0%;">09:00</div>
|
||||
<div class="time-marker" style="top: 25%;">10:00</div>
|
||||
<div class="time-marker" style="top: 50%;">11:00</div>
|
||||
<div class="time-marker" style="top: 75%;">12:00</div>
|
||||
</div>
|
||||
|
||||
<div class="events-container">
|
||||
<!-- Event A: 09:00-10:00 (stackLevel 0) -->
|
||||
<div class="event event-a" style="top: 0px; left: 2px; right: 2px; height: 60px; margin-left: 0px; z-index: 100;">
|
||||
Event A<br>09:00-10:00
|
||||
</div>
|
||||
|
||||
<!-- Event B: 09:30-10:30 (stackLevel 1, overlaps A) -->
|
||||
<div class="event event-b" style="top: 30px; left: 2px; right: 2px; height: 60px; margin-left: 15px; z-index: 101;">
|
||||
Event B<br>09:30-10:30
|
||||
</div>
|
||||
|
||||
<!-- Event C: 10:15-12:00 (stackLevel 2, overlaps B) -->
|
||||
<div class="event event-c" style="top: 75px; left: 2px; right: 2px; height: 105px; margin-left: 30px; z-index: 102;">
|
||||
Event C<br>10:15-12:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Threshold = 30 min -->
|
||||
<div class="calendar-column">
|
||||
<div class="column-title">With Threshold = 30 min</div>
|
||||
<div class="timeline">
|
||||
<div class="time-marker" style="top: 0%;">09:00</div>
|
||||
<div class="time-marker" style="top: 25%;">10:00</div>
|
||||
<div class="time-marker" style="top: 50%;">11:00</div>
|
||||
<div class="time-marker" style="top: 75%;">12:00</div>
|
||||
</div>
|
||||
|
||||
<div class="events-container">
|
||||
<!-- Grid Group for A, B & C: stackLevel 0 (2 columns, A and C share column 1) -->
|
||||
<div style="position: absolute; top: 0px; left: 2px; right: 2px; margin-left: 0px; z-index: 100; display: grid; grid-template-columns: 1fr 1fr; gap: 2px;">
|
||||
<!-- Column 1: Event A and C (no overlap) -->
|
||||
<div style="position: relative;">
|
||||
<div class="event event-a" style="position: absolute; top: 0px; height: 60px; left: 0; right: 0;">
|
||||
Event A<br>09:00-10:00
|
||||
</div>
|
||||
<div class="event event-c" style="position: absolute; top: 75px; height: 105px; left: 0; right: 0;">
|
||||
Event C<br>10:15-12:00
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 2: Event B -->
|
||||
<div style="position: relative;">
|
||||
<div class="event event-b" style="position: absolute; top: 30px; height: 60px; left: 0; right: 0;">
|
||||
Event B<br>09:30-10:30
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Stack Analysis</h3>
|
||||
<div class="legend">
|
||||
<p><strong>Threshold = 15 min (Stack):</strong></p>
|
||||
<ul>
|
||||
<li>Event A: stackLevel 0</li>
|
||||
<li>Event B: stackLevel 1 (starts 30 min before A ends, but 30 > 15 threshold) → Stack with margin-left: 15px</li>
|
||||
<li>Event C: stackLevel 2 (starts 15 min before B ends, but separate from A-B stack) → Stack with margin-left: 30px</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Threshold = 30 min (Shared GRID with 2 columns):</strong></p>
|
||||
<ul>
|
||||
<li>Grid Group (A, B & C): 2-column grid layout</li>
|
||||
<li><strong>Column 1:</strong> Event A (09:00-10:00) + Event C (10:15-12:00) - they don't overlap!</li>
|
||||
<li><strong>Column 2:</strong> Event B (09:30-10:30) - overlaps both A and C</li>
|
||||
<li>Event A: grid column 1, top: 0px</li>
|
||||
<li>Event B: grid column 2, top: 30px</li>
|
||||
<li>Event C: grid column 1, top: 75px (shares column with A, no overlap)</li>
|
||||
<li>All events: stackLevel 0, margin-left: 0px (no stacking, all in same grid container)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============================================ -->
|
||||
<!-- SCENARIO 10: Complex Column Sharing with Multiple Events -->
|
||||
<!-- ============================================ -->
|
||||
<div class="section">
|
||||
<h2>Scenario 10: Complex Column Sharing</h2>
|
||||
|
||||
<div class="legend">
|
||||
<div class="legend-item"><strong>Event A:</strong> 12:00 - 15:00 (3 hours)</div>
|
||||
<div class="legend-item"><strong>Event B:</strong> 12:30 - 13:00 (30 min, starts 30 min after A)</div>
|
||||
<div class="legend-item"><strong>Event C:</strong> 13:30 - 14:30 (1 hour, starts 30 min after B ends)</div>
|
||||
<div class="legend-item"><strong>Event D:</strong> 14:00 - 15:00 (1 hour, starts 30 min before C ends)</div>
|
||||
<div class="legend-item"><strong>Event E:</strong> 14:00 - 15:00 (1 hour, starts same time as D)</div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
<strong>Analysis with threshold = 30 min:</strong><br>
|
||||
• A-B conflict: B starts 30 min after A (≤ 30) → grouped<br>
|
||||
• B-C conflict: C starts 30 min after B ends (≤ 30) → grouped with A-B<br>
|
||||
• C-D conflict: D starts 30 min before C ends (≤ 30) → grouped with A-B-C<br>
|
||||
• D-E conflict: D and E start at same time (0 min) → grouped with all<br>
|
||||
• Therefore: All 5 events in ONE grid group<br><br>
|
||||
<strong>Column allocation:</strong><br>
|
||||
• A overlaps: B, C, D, E → needs own column<br>
|
||||
• B overlaps: A → needs own column<br>
|
||||
• C overlaps: A, D, E → needs own column<br>
|
||||
• D overlaps: A, C, E → needs own column<br>
|
||||
• E overlaps: A, C, D → can share column with B (they don't overlap)<br>
|
||||
• Result: 4 columns needed
|
||||
</div>
|
||||
|
||||
<div class="comparison">
|
||||
<!-- Threshold = 15 min -->
|
||||
<div class="calendar-column">
|
||||
<div class="column-title">With Threshold = 15 min</div>
|
||||
<div class="timeline">
|
||||
<div class="time-marker" style="top: 0%;">12:00</div>
|
||||
<div class="time-marker" style="top: 33%;">13:00</div>
|
||||
<div class="time-marker" style="top: 67%;">14:00</div>
|
||||
<div class="time-marker" style="top: 100%;">15:00</div>
|
||||
</div>
|
||||
|
||||
<div class="events-container">
|
||||
<!-- Event A: stackLevel 0 -->
|
||||
<div class="event event-a" style="position: absolute; top: 0px; left: 2px; right: 2px; height: 180px; margin-left: 0px; z-index: 100;">
|
||||
Event A<br>12:00-15:00
|
||||
</div>
|
||||
|
||||
<!-- Event B: stackLevel 1 (overlaps A) -->
|
||||
<div class="event event-b" style="position: absolute; top: 30px; left: 2px; right: 2px; height: 30px; margin-left: 15px; z-index: 101;">
|
||||
Event B<br>12:30-13:00
|
||||
</div>
|
||||
|
||||
<!-- Event C: stackLevel 2 (overlaps A, not B) -->
|
||||
<div class="event event-c" style="position: absolute; top: 90px; left: 2px; right: 2px; height: 60px; margin-left: 30px; z-index: 102;">
|
||||
Event C<br>13:30-14:30
|
||||
</div>
|
||||
|
||||
<!-- Grid Group for D & E: stackLevel 3 (start simultaneously, overlap A and C) -->
|
||||
<div style="position: absolute; top: 120px; left: 2px; right: 2px; margin-left: 45px; z-index: 103; display: grid; grid-template-columns: 1fr 1fr; gap: 2px;">
|
||||
<div style="position: relative;">
|
||||
<div class="event event-d" style="position: absolute; top: 0px; height: 60px; left: 0; right: 0;">
|
||||
Event D<br>14:00-15:00
|
||||
</div>
|
||||
</div>
|
||||
<div style="position: relative;">
|
||||
<div class="event event-d" style="position: absolute; top: 0px; height: 60px; left: 0; right: 0;">
|
||||
Event E<br>14:00-15:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Threshold = 30 min -->
|
||||
<div class="calendar-column">
|
||||
<div class="column-title">With Threshold = 30 min</div>
|
||||
<div class="timeline">
|
||||
<div class="time-marker" style="top: 0%;">12:00</div>
|
||||
<div class="time-marker" style="top: 33%;">13:00</div>
|
||||
<div class="time-marker" style="top: 67%;">14:00</div>
|
||||
<div class="time-marker" style="top: 100%;">15:00</div>
|
||||
</div>
|
||||
|
||||
<div class="events-container">
|
||||
<!-- Grid Group: All 5 events (4 columns) -->
|
||||
<div style="position: absolute; top: 0px; left: 2px; right: 2px; margin-left: 0px; z-index: 100; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 2px;">
|
||||
|
||||
<!-- Column 1: Event A -->
|
||||
<div style="position: relative;">
|
||||
<div class="event event-a" style="position: absolute; top: 0px; height: 180px; left: 0; right: 0;">
|
||||
Event A<br>12:00-15:00
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 2: Event B + E (don't overlap) -->
|
||||
<div style="position: relative;">
|
||||
<div class="event event-b" style="position: absolute; top: 30px; height: 30px; left: 0; right: 0;">
|
||||
Event B<br>12:30-13:00
|
||||
</div>
|
||||
<div class="event event-d" style="position: absolute; top: 120px; height: 60px; left: 0; right: 0;">
|
||||
Event E<br>14:00-15:00
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 3: Event C -->
|
||||
<div style="position: relative;">
|
||||
<div class="event event-c" style="position: absolute; top: 90px; height: 60px; left: 0; right: 0;">
|
||||
Event C<br>13:30-14:30
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Column 4: Event D -->
|
||||
<div style="position: relative;">
|
||||
<div class="event event-d" style="position: absolute; top: 120px; height: 60px; left: 0; right: 0;">
|
||||
Event D<br>14:00-15:00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Expected Layout</h3>
|
||||
<div class="legend">
|
||||
<p><strong>Threshold = 15 min (Stack + Small Grid):</strong></p>
|
||||
<ul>
|
||||
<li>Event A: stackLevel 0</li>
|
||||
<li>Event B: stackLevel 1 (overlaps A, 30 min > 15 threshold) → margin-left: 15px</li>
|
||||
<li>Event C: stackLevel 2 (overlaps A, 30 min > 15 threshold) → margin-left: 30px</li>
|
||||
<li>Grid Group (D & E): stackLevel 3 (start simultaneously) → margin-left: 45px
|
||||
<ul>
|
||||
<li>2-column grid: D in column 1, E in column 2</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Threshold = 30 min (Large Grid):</strong></p>
|
||||
<ul>
|
||||
<li>Grid Group (A, B, C, D, E): All in ONE grid group
|
||||
<ul>
|
||||
<li><strong>Column 1:</strong> Event A (top: 0px, height: 180px)</li>
|
||||
<li><strong>Column 2:</strong> Event B (top: 30px) + Event E (top: 120px)</li>
|
||||
<li><strong>Column 3:</strong> Event C (top: 90px)</li>
|
||||
<li><strong>Column 4:</strong> Event D (top: 120px)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Key Points:</strong></p>
|
||||
<ul>
|
||||
<li>With threshold = 30: All events grouped due to chained end-to-start conflicts</li>
|
||||
<li>With threshold = 15: Only D & E grouped (start simultaneously), A/B/C stacked separately</li>
|
||||
<li>B and E can share column 2 (they don't overlap: B ends 13:00, E starts 14:00)</li>
|
||||
<li>D and E start at same time but need separate columns (they overlap perfectly)</li>
|
||||
<li>Result with 30 min: 4 columns instead of 5 (optimization saves 1 column)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer style="text-align: center; color: #999; margin-top: 40px; padding: 20px;">
|
||||
<p>Event Stacking Visualization - Calendar Plantempus</p>
|
||||
<p style="font-size: 12px;">Static documentation for event stacking concepts</p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue