I’m developing a rotating slider interface where several circles are arranged in a circular layout. I want the slider to have two main functionalities:
Clickable Circles: When a user clicks on any circle, it should smoothly rotate and reposition so that the clicked circle becomes the central, prominent element.
Arrow Controls: In addition to clicking the circles, I’d like to include left/right arrow buttons that allow the user to rotate through the circles.
I’ve attempted to implement this behavior using HTML/CSS/JavaScript, but I’m encountering issues with the position of circles, rotation animations and ensuring the clicked circle transitions correctly to the main position. Additionally, managing the arrow control rotations has proven challenging.
Could someone provide guidance or examples on how to achieve this functionality? Any suggestions for libraries, frameworks, or code examples that can help me implement a smooth, interactive rotating slider would be greatly appreciated.
Thank you in advance for your help.
// Grab all carousel items and the main circle
const items = document.querySelectorAll('.carousel-item');
const mainCircle = document.getElementById('mainCircle');
const arrowLeft = document.getElementById('arrowLeft');
const arrowRight = document.getElementById('arrowRight');
// Track which item is "active"
let activeIndex = 0;
// Update positions based on the active index
function updateCarousel() {
// Update main circle text to match the active item
mainCircle.textContent = items[activeIndex].textContent;
const totalItems = items.length;
const angleStep = 360 / totalItems;
// Define ellipse radii (must match the SVG ellipse)
const radiusX = 250; // horizontal radius
const radiusY = 50; // vertical radius
items.forEach((item, i) => {
// Calculate angle relative to the active index
const angle = (i - activeIndex) * angleStep;
const rad = angle * Math.PI / 180;
// Calculate x/y positions for elliptical orbit
const x = radiusX * Math.cos(rad);
const y = radiusY * Math.sin(rad);
// Move each item into position around the main circle
item.style.transform = `translate(-50%, -50%) translate(${x}px, ${y}px)`;
});
}
// Event listeners for arrow clicks
arrowLeft.addEventListener('click', () => {
activeIndex = (activeIndex - 1 + items.length) % items.length;
updateCarousel();
});
arrowRight.addEventListener('click', () => {
activeIndex = (activeIndex + 1) % items.length;
updateCarousel();
});
// Event listener for clicking on an outer item
items.forEach((item, i) => {
item.addEventListener('click', () => {
activeIndex = i;
updateCarousel();
});
});
// Initialize the carousel on page load
updateCarousel();
.carousel-container {
position: relative;
width: 900px;
height: 300px;
margin: auto;
overflow: hidden;
/* Remove the container border since we use an SVG for the orbit */
}
/* SVG orbit drawn behind the circles */
.orbit {
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
/* The central circle (the "sun") */
.carousel-center {
position: absolute;
top: 80%; /* Orbit center vertical position */
left: 50%;
width: 120px;
height: 120px;
background-color: orange;
border-radius: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-weight: bold;
color: #fff;
z-index: 10;
box-shadow: 0 0 8px rgba(0,0,0,0.3);
cursor: default;
}
/* Outer circles (the "planets") */
.carousel-item {
position: absolute;
top: 80%; /* Same center as the main circle */
left: 50%;
width: 80px;
height: 80px;
background-color: #ffe0a2;
border-radius: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
cursor: pointer;
transition: transform 0.5s;
box-shadow: 0 0 5px rgba(0,0,0,0.2);
z-index: 5;
}
/* Arrows for manual sliding */
.carousel-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: #ddd;
border: none;
padding: 10px 15px;
cursor: pointer;
z-index: 20;
font-size: 16px;
border-radius: 4px;
box-shadow: 0 0 5px rgba(0,0,0,0.2);
}
.carousel-arrow.left {
left: 10px;
}
.carousel-arrow.right {
right: 10px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Carousel Orbit</title>
</head>
<body>
<div class="carousel-container">
<!-- SVG Orbit Path matching the ellipse in JS -->
<svg class="orbit" width="900" height="300">
<!-- The ellipse is centered at (450, 240) which is 50% (450px) horizontally and 80% (240px of 300px) vertically -->
<ellipse cx="450" cy="240" rx="250" ry="50" fill="none" stroke="#ccc" stroke-dasharray="5,5" />
</svg>
<!-- Main circle (active item) -->
<div class="carousel-center" id="mainCircle">API Applications</div>
<!-- Outer circles (planets) -->
<div class="carousel-item" data-index="0">E2E Testing</div>
<div class="carousel-item" data-index="1">API Portal</div>
<div class="carousel-item" data-index="2">API Governance</div>
<div class="carousel-item" data-index="3">API Navigator</div>
<!-- Navigation arrows -->
<button class="carousel-arrow left" id="arrowLeft"><</button>
<button class="carousel-arrow right" id="arrowRight">></button>
</div>
</body>
</html>