Improves event overlap stacking logic
Ensures event stacking only occurs when events actually overlap in pixel space, preventing visual artifacts. Breaks stacking chains when events no longer overlap due to middle element removal, and correctly resets styling.
This commit is contained in:
parent
5bdb2f578d
commit
c7716d1b8f
1 changed files with 75 additions and 20 deletions
|
|
@ -203,12 +203,46 @@ export class SimpleEventOverlapManager {
|
|||
const prevLink = this.getStackLink(prevElement);
|
||||
const nextLink = this.getStackLink(nextElement);
|
||||
|
||||
// CRITICAL: Check if prev and next actually overlap without the middle element
|
||||
const actuallyOverlap = this.checkPixelOverlap(prevElement, nextElement);
|
||||
|
||||
if (!actuallyOverlap) {
|
||||
// CHAIN BREAKING: prev and next don't overlap - break the chain
|
||||
console.log('Breaking stack chain - events do not overlap directly');
|
||||
|
||||
// Prev element: remove next link (becomes end of its own chain)
|
||||
this.setStackLink(prevElement, {
|
||||
...prevLink!,
|
||||
next: undefined
|
||||
});
|
||||
|
||||
// Next element: becomes standalone (remove all stack links and styling)
|
||||
this.setStackLink(nextElement, null);
|
||||
nextElement.style.marginLeft = '';
|
||||
nextElement.style.zIndex = '';
|
||||
|
||||
// If next element had subsequent events, they also become standalone
|
||||
if (nextLink?.next) {
|
||||
let subsequentId: string | undefined = nextLink.next;
|
||||
while (subsequentId) {
|
||||
const subsequentElement = this.findElementById(subsequentId);
|
||||
if (!subsequentElement) break;
|
||||
|
||||
const subsequentLink = this.getStackLink(subsequentElement);
|
||||
this.setStackLink(subsequentElement, null);
|
||||
subsequentElement.style.marginLeft = '';
|
||||
subsequentElement.style.zIndex = '';
|
||||
|
||||
subsequentId = subsequentLink?.next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// NORMAL STACKING: they overlap, maintain the chain
|
||||
this.setStackLink(prevElement, {
|
||||
...prevLink!,
|
||||
next: link.next
|
||||
});
|
||||
|
||||
// FIXED: Use prev's stackLevel + 1 instead of subtracting 1
|
||||
const correctStackLevel = (prevLink?.stackLevel ?? 0) + 1;
|
||||
this.setStackLink(nextElement, {
|
||||
...nextLink!,
|
||||
|
|
@ -216,11 +250,12 @@ export class SimpleEventOverlapManager {
|
|||
stackLevel: correctStackLevel
|
||||
});
|
||||
|
||||
// CRITICAL: Update visual styling to match new stackLevel
|
||||
// Update visual styling to match new stackLevel
|
||||
const marginLeft = correctStackLevel * SimpleEventOverlapManager.STACKING_WIDTH_REDUCTION_PX;
|
||||
nextElement.style.marginLeft = `${marginLeft}px`;
|
||||
nextElement.style.zIndex = `${100 + correctStackLevel}`;
|
||||
}
|
||||
}
|
||||
} else if (link.prev) {
|
||||
// Last element - remove next link from prev
|
||||
const prevElement = this.findElementById(link.prev);
|
||||
|
|
@ -244,15 +279,16 @@ export class SimpleEventOverlapManager {
|
|||
}
|
||||
}
|
||||
|
||||
// For middle element removal, we've already set the correct stackLevel for next element
|
||||
// Only update subsequent elements after the next one
|
||||
// Only update subsequent stack levels if we didn't break the chain
|
||||
if (link.prev && link.next) {
|
||||
// Middle removal - update elements after the next one
|
||||
const nextElement = this.findElementById(link.next);
|
||||
const nextLink = nextElement ? this.getStackLink(nextElement) : null;
|
||||
if (nextLink?.next) {
|
||||
|
||||
// If next element still has a stack link, the chain wasn't broken
|
||||
if (nextLink && nextLink.next) {
|
||||
this.updateSubsequentStackLevels(nextLink.next, -1);
|
||||
}
|
||||
// If nextLink is null, chain was broken - no subsequent updates needed
|
||||
} else {
|
||||
// First or last removal - update all subsequent
|
||||
this.updateSubsequentStackLevels(link.next, -1);
|
||||
|
|
@ -500,4 +536,23 @@ export class SimpleEventOverlapManager {
|
|||
private findElementById(eventId: string): HTMLElement | null {
|
||||
return document.querySelector(`swp-event[data-event-id="${eventId}"]`) as HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two elements overlap in pixel space
|
||||
*/
|
||||
private checkPixelOverlap(element1: HTMLElement, element2: HTMLElement): boolean {
|
||||
if (!element1 || !element2) return false;
|
||||
|
||||
const top1 = parseFloat(element1.style.top) || 0;
|
||||
const height1 = parseFloat(element1.style.height) || 0;
|
||||
const bottom1 = top1 + height1;
|
||||
|
||||
const top2 = parseFloat(element2.style.top) || 0;
|
||||
const height2 = parseFloat(element2.style.height) || 0;
|
||||
const bottom2 = top2 + height2;
|
||||
|
||||
// Add tolerance for small gaps (borders, etc)
|
||||
const tolerance = 2;
|
||||
return !(bottom1 <= (top2 + tolerance) || bottom2 <= (top1 + tolerance));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue