I have a simple timeline on my website with cards. The cards get placed on the timeline using a simple function. But some of the cards overlap. I want to make it so if a card overlaps it gets put under the original card. And if it still overlaps it gets put above the timeline. But I’m not sure how to implement this correctly.
Here’s some code I have up until now:
— Calculating card positions —
const calculateCardPosition = (card) => {
const start = -13800000000;
const end = 0;
let x = ((card.date - start) / (end - start)) * 100;
if (x < 10) {
x = x + 10;
} else if (x > 90) {
x = x - 10;
}
return { x };
};
— Timeline section —
<section id="timeline" className="bg-gray-100 dark:bg-gray-800 py-10">
<div className="container mx-auto h-96 bg-sections-intro-light dark:bg-sections-intro-dark">
<h2 className="text-3xl font-bold text-center mb-8">Timeline</h2>
{/* Timeline */}
<div className="relative">
{/* Timeline line */}
<div className="border-2 border-gray-300 dark:border-gray-700 absolute w-full h-0 left-0 top-1/2 transform -translate-y-1/2"></div>
{/* Timeline cards */}
<ul className="gap-4 absolute top-0 left-0 w-full">
{timelineContent.map((item) => (
<li
id={item.id}
key={item.id}
className={`bg-white dark:bg-gray-700 rounded-md shadow-md p-2 cursor-pointer ${
activeCard === item.date ? "border-2 border-blue-500" : ""
} timeline-card`}
style={{
position: "absolute",
left: `${calculateCardPosition(item).x}%`,
transform: "translateX(-50%)",
width: "150px",
}}
onClick={() => scrollToSection(item.scrollTo)}
onMouseEnter={() => handleCardHover(item.date)}
onMouseLeave={() => handleCardHover(null)}
>
<h3 className="text-base font-semibold">{item.title}</h3>
{activeCard === item.date && <p className="mt-2 text-sm">{item.description}</p>}
</li>
))}
</ul>
</div>
</div>
</section>
2
Answers
Check if two cards overlap
Adjust card positions to avoid overlapping
Update the calculateCardPosition
Styling
Hope it helps.
Run through the list of cards and calculate if they would overlap by first getting their
x
values.This is a proof-of-concept but for production code, you may need to listen for if the timeline container resizes, and recalculate the
y
positions accordingly. They
offset of3rem
here is arbitrary and is something that might need to be calculated dynamically too in production code.