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,23 +203,58 @@ export class SimpleEventOverlapManager {
|
||||||
const prevLink = this.getStackLink(prevElement);
|
const prevLink = this.getStackLink(prevElement);
|
||||||
const nextLink = this.getStackLink(nextElement);
|
const nextLink = this.getStackLink(nextElement);
|
||||||
|
|
||||||
this.setStackLink(prevElement, {
|
// CRITICAL: Check if prev and next actually overlap without the middle element
|
||||||
...prevLink!,
|
const actuallyOverlap = this.checkPixelOverlap(prevElement, nextElement);
|
||||||
next: link.next
|
|
||||||
});
|
|
||||||
|
|
||||||
// FIXED: Use prev's stackLevel + 1 instead of subtracting 1
|
if (!actuallyOverlap) {
|
||||||
const correctStackLevel = (prevLink?.stackLevel ?? 0) + 1;
|
// CHAIN BREAKING: prev and next don't overlap - break the chain
|
||||||
this.setStackLink(nextElement, {
|
console.log('Breaking stack chain - events do not overlap directly');
|
||||||
...nextLink!,
|
|
||||||
prev: link.prev,
|
|
||||||
stackLevel: correctStackLevel
|
|
||||||
});
|
|
||||||
|
|
||||||
// CRITICAL: Update visual styling to match new stackLevel
|
// Prev element: remove next link (becomes end of its own chain)
|
||||||
const marginLeft = correctStackLevel * SimpleEventOverlapManager.STACKING_WIDTH_REDUCTION_PX;
|
this.setStackLink(prevElement, {
|
||||||
nextElement.style.marginLeft = `${marginLeft}px`;
|
...prevLink!,
|
||||||
nextElement.style.zIndex = `${100 + correctStackLevel}`;
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
const correctStackLevel = (prevLink?.stackLevel ?? 0) + 1;
|
||||||
|
this.setStackLink(nextElement, {
|
||||||
|
...nextLink!,
|
||||||
|
prev: link.prev,
|
||||||
|
stackLevel: correctStackLevel
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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) {
|
} else if (link.prev) {
|
||||||
// Last element - remove next link from prev
|
// Last element - remove next link from 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 stack levels if we didn't break the chain
|
||||||
// Only update subsequent elements after the next one
|
|
||||||
if (link.prev && link.next) {
|
if (link.prev && link.next) {
|
||||||
// Middle removal - update elements after the next one
|
|
||||||
const nextElement = this.findElementById(link.next);
|
const nextElement = this.findElementById(link.next);
|
||||||
const nextLink = nextElement ? this.getStackLink(nextElement) : null;
|
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);
|
this.updateSubsequentStackLevels(nextLink.next, -1);
|
||||||
}
|
}
|
||||||
|
// If nextLink is null, chain was broken - no subsequent updates needed
|
||||||
} else {
|
} else {
|
||||||
// First or last removal - update all subsequent
|
// First or last removal - update all subsequent
|
||||||
this.updateSubsequentStackLevels(link.next, -1);
|
this.updateSubsequentStackLevels(link.next, -1);
|
||||||
|
|
@ -500,4 +536,23 @@ export class SimpleEventOverlapManager {
|
||||||
private findElementById(eventId: string): HTMLElement | null {
|
private findElementById(eventId: string): HTMLElement | null {
|
||||||
return document.querySelector(`swp-event[data-event-id="${eventId}"]`) as HTMLElement;
|
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