Я хотел сделать трехмерную вращающуюся карусель, как в фрагменте стека, но требуется вид изнутри, как на изображении ниже. Как я могу достичь этого?
window.addEventListener('load', () => {
var carousels = document.querySelectorAll('.carousel');
for (var i = 0; i < carousels.length; i++) {
carousel(carousels[i]);
}
});
function carousel(root) {
var
figure = root.querySelector('figure'),
nav = root.querySelector('nav'),
images = figure.children,
n = images.length,
gap = root.dataset.gap || 0,
bfc = 'bfc' in root.dataset,
theta = 2 * Math.PI / n,
currImage = 0;
setupCarousel(n, parseFloat(getComputedStyle(images[0]).width));
window.addEventListener('resize', () => {
setupCarousel(n, parseFloat(getComputedStyle(images[0]).width))
});
setupNavigation();
function setupCarousel(n, s) {
var apothem = s / (2 * Math.tan(Math.PI / n));
figure.style.transformOrigin = `50% 50% ${- apothem}px`;
for (var i = 0; i < n; i++) {
images[i].style.padding = `${gap}px`;
}
for (i = 1; i < n; i++) {
images[i].style.transformOrigin = `50% 50% ${- apothem}px`;
images[i].style.transform = `rotateY(${i * theta}rad)`;
}
if (bfc) {
for (i = 0; i < n; i++) {
images[i].style.backfaceVisibility = 'hidden';
}
}
rotateCarousel(currImage);
}
function setupNavigation() {
nav.addEventListener('click', onClick, true);
function onClick(e) {
e.stopPropagation();
var t = e.target;
if (t.tagName.toUpperCase() != 'BUTTON') {
return;
}
if (t.classList.contains('next')) {
currImage++;
}
else {
currImage--;
}
rotateCarousel(currImage);
}
}
function rotateCarousel(imageIndex) {
figure.style.transform = `rotateY(${imageIndex * -theta}rad)`;
}
}
body {
margin: 0;
font-family: 'Roboto', sans-serif;
font-size: 16px;
}
h1 {
text-align: center;
margin-bottom: 1.5em;
}
h2 {
text-align: center;
color: #555;
margin-bottom: 0;
}
.carousel {
padding: 20px;
perspective: 500px;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
}
.carousel>* {
flex: 0 0 auto;
}
.carousel figure {
margin: 0;
width: 40%;
transform-style: preserve-3d;
transition: transform 0.5s;
}
.carousel figure img {
width: 100%;
box-sizing: border-box;
padding: 0 0px;
}
.carousel figure img:not(:first-of-type) {
position: absolute;
left: 0;
top: 0;
}
.carousel nav {
display: flex;
justify-content: center;
margin: 20px 0 0;
}
.carousel nav button {
flex: 0 0 auto;
margin: 0 5px;
cursor: pointer;
color: #333;
background: none;
border: 1px solid;
letter-spacing: 1px;
padding: 5px 10px;
}
<h2>Eight images, with 80px gap</h2>
<div class = "carousel" data-gap = "80">
<figure>
<img src = "https://source.unsplash.com/VkwRmha1_tI/800x533" alt = "">
<img src = "https://source.unsplash.com/EbuaKnSm8Zw/800x533" alt = "">
<img src = "https://source.unsplash.com/kG38b7CFzTY/800x533" alt = "">
<img src = "https://source.unsplash.com/nvzvOPQW0gc/800x533" alt = "">
<img src = "https://source.unsplash.com/mCg0ZgD7BgU/800x533" alt = "">
<img src = "https://source.unsplash.com/1FWICvPQdkY/800x533" alt = "">
<img src = "https://source.unsplash.com/bjhrzvzZeq4/800x533" alt = "">
<img src = "https://source.unsplash.com/7mUXaBBrhoA/800x533" alt = "">
</figure>
<nav>
<button class = "nav prev">Prev</button>
<button class = "nav next">Next</button>
</nav>
</div>
Карусель необходимо вращать и перемещать в противоположном направлении, чтобы сделать ее вид внутреннего вращения.
transform-origin
устанавливает центр карусели. Первые два числа — это x и y, которые просто центрируют карусель на экране. Третье число — z, которое определяет, перемещается ли карусель к экрану или от экрана. Знак минус на apothem
удаляется, чтобы вытащить его за пределы экрана, чтобы центр стал ближе к камере и достиг внутренней карусели. backface-visibility
всегда должен быть скрыт, потому что теперь за камерой могут быть изображения. Затем, чтобы зафиксировать направление вращения с помощью следующей кнопки, * -theta
меняется на положительное.
window.addEventListener('load', () => {
var carousels = document.querySelectorAll('.carousel');
for (var i = 0; i < carousels.length; i++) {
carousel(carousels[i]);
}
});
function carousel(root) {
var
figure = root.querySelector('figure'),
nav = root.querySelector('nav'),
images = figure.children,
n = images.length,
gap = root.dataset.gap || 0,
theta = 2 * Math.PI / n,
currImage = 0;
setupCarousel(n, parseFloat(getComputedStyle(images[0]).width));
window.addEventListener('resize', () => {
setupCarousel(n, parseFloat(getComputedStyle(images[0]).width))
});
setupNavigation();
function setupCarousel(n, s) {
var apothem = s / (2 * Math.tan(Math.PI / n));
figure.style.transformOrigin = `50% 50% ${apothem}px`;
for (var i = 0; i < n; i++) {
images[i].style.padding = `${gap}px`;
}
for (i = 1; i < n; i++) {
images[i].style.transformOrigin = `50% 50% ${apothem}px`;
images[i].style.transform = `rotateY(${i * theta}rad)`;
}
rotateCarousel(currImage);
}
function setupNavigation() {
nav.addEventListener('click', onClick, true);
function onClick(e) {
e.stopPropagation();
var t = e.target;
if (t.tagName.toUpperCase() != 'BUTTON') {
return;
}
if (t.classList.contains('next')) {
currImage++;
}
else {
currImage--;
}
rotateCarousel(currImage);
}
}
function rotateCarousel(imageIndex) {
figure.style.transform = `rotateY(${imageIndex * theta}rad)`;
}
}
body {
margin: 0;
font-family: 'Roboto', sans-serif;
font-size: 16px;
}
h1 {
text-align: center;
margin-bottom: 1.5em;
}
h2 {
text-align: center;
color: #555;
margin-bottom: 0;
}
.carousel {
padding: 20px;
perspective: 500px;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
}
.carousel>* {
flex: 0 0 auto;
}
.carousel figure {
margin: 0;
width: 40%;
transform-style: preserve-3d;
transition: transform 0.5s;
}
.carousel figure img {
width: 100%;
box-sizing: border-box;
padding: 0 0px;
backface-visibility: hidden;
}
.carousel figure img:not(:first-of-type) {
position: absolute;
left: 0;
top: 0;
}
.carousel nav {
display: flex;
justify-content: center;
margin: 20px 0 0;
}
.carousel nav button {
flex: 0 0 auto;
margin: 0 5px;
cursor: pointer;
color: #333;
background: none;
border: 1px solid;
letter-spacing: 1px;
padding: 5px 10px;
}
<h2>Eight images, with 80px gap</h2>
<div class = "carousel" data-gap = "80">
<figure>
<img src = "https://source.unsplash.com/VkwRmha1_tI/800x533" alt = "">
<img src = "https://source.unsplash.com/EbuaKnSm8Zw/800x533" alt = "">
<img src = "https://source.unsplash.com/kG38b7CFzTY/800x533" alt = "">
<img src = "https://source.unsplash.com/nvzvOPQW0gc/800x533" alt = "">
<img src = "https://source.unsplash.com/mCg0ZgD7BgU/800x533" alt = "">
<img src = "https://source.unsplash.com/1FWICvPQdkY/800x533" alt = "">
<img src = "https://source.unsplash.com/bjhrzvzZeq4/800x533" alt = "">
<img src = "https://source.unsplash.com/7mUXaBBrhoA/800x533" alt = "">
</figure>
<nav>
<button class = "nav prev">Prev</button>
<button class = "nav next">Next</button>
</nav>
</div>