Круговой слайдер из 5-и элементов
Как реализовать анимацию кругового слайдера из 5-и элементов, похожего на тот, что на изображении ниже?
На сколько градусов правильно повернуть item? Тут ведь не правильный пятиугольник нужен, а изображения должны идти перпендикулярно области наблюдения.
Вот начальная заготовка:
body {
margin: 0;
padding: 0;
width: 100% ;
}
.circularSlider_full {
position: relative;
width: 100% ;
display: flex;
flex-direction: row;
justify-content: center;
z-index: 3;
}
.circularSlider {
margin: 100px auto 0;
width: 250px;
height: 390px;
perspective: 1000px;
}
.circularSlider_content {
width: 100% ;
height: 390px;
position: relative;
transform-style: preserve-3d;
animation: rotate 10s infinite;
}
.circularSlider_item {
width: 240px;
height: 390px;
position: absolute;
transform-origin: 50% 50% ;
border: 1px solid #000;
background: rgba(255, 255, 255, 0.5);
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
}
.circularSlider_item:nth-child(1) {
transform: rotateY(0deg) translateZ(180px);
}
.circularSlider_item:nth-child(2) {
transform: rotateY(72deg) translateZ(180px);
}
.circularSlider_item:nth-child(3) {
transform: rotateY(144deg) translateZ(180px);
}
.circularSlider_item:nth-child(4) {
transform: rotateY(216deg) translateZ(180px);
}
.circularSlider_item:nth-child(5) {
transform: rotateY(288deg) translateZ(180px);
}
@keyframes rotate {
0% {
transform: translateZ(180px) rotateY(0deg);
}
12.5% {
transform: translateZ(180px) rotateY(-72deg);
}
25% {
transform: translateZ(180px) rotateY(-144deg);
}
37.5% {
transform: translateZ(180px) rotateY(-216deg);
}
50% {
transform: translateZ(180px) rotateY(-288deg);
}
100% {
transform: translateZ(180px) rotateY(-360deg);
}
}
<div class="circularSlider_full">
<div class="circularSlider">
<div class="circularSlider_content">
<div class="circularSlider_item">
<img width="148" height="142" src="https://raw.githubusercontent.com/BlackStar1991/Pictures-for-sharing-/master/Chest/chest.svg" alt="chest">
</div>
<div class="circularSlider_item">
<img width="148" height="142" src="https://raw.githubusercontent.com/BlackStar1991/Pictures-for-sharing-/master/Chest/chest.svg" alt="chest">
</div>
<div class="circularSlider_item">
<img width="148" height="142" src="https://raw.githubusercontent.com/BlackStar1991/Pictures-for-sharing-/master/Chest/chest.svg" alt="chest">
</div>
<div class="circularSlider_item">
<img width="148" height="142" src="https://raw.githubusercontent.com/BlackStar1991/Pictures-for-sharing-/master/Chest/chest.svg" alt="chest">
</div>
<div class="circularSlider_item">
<img width="148" height="142" src="https://raw.githubusercontent.com/BlackStar1991/Pictures-for-sharing-/master/Chest/chest.svg" alt="chest">
</div>
</div>
</div>
</div>
Буду благодарен за объяснения относительно анимации.
Ответы (2 шт):
Автор решения: ᅠhᅠ
→ Ссылка
class Slider {
constructor(node) {
this.node = node
this.list = null
this._counter = 0
this.sides = 0
this.step = 0
this.shift = 0
this.findParts()
this.prepare()
this.listen()
}
findParts() {
this.list = this.node.querySelector('[data-slider-list]')
this.items = [...this.list.children]
this.step_buttons = [...this.node.querySelectorAll('[data-slider-step-button]')].map((button) => {
return {
node: button,
value: !!button.dataset.sliderStepButton ? +button.dataset.sliderStepButton: 1
}
})
}
prepare() {
this.sides = this.items.length
this.step = 2 * Math.PI / this.sides
this.shift = Math.PI / 2
this.counter = 0
}
listen() {
this.step_buttons.forEach(button => {
button.node.addEventListener('click', () => {
this.counter = this.counter + button.value
})
})
}
listenKeys(e) {
if(e.key === 'ArrowLeft') {
this.counter = this.counter - 1
} else if(e.key === 'ArrowRight') {
this.counter = this.counter + 1
}
}
notify() {
this.items.forEach((item, i) => {
const pos = (i + this.counter) * this.step + this.shift
const cos = Math.cos(pos)
const sin = Math.sin(pos)
const scale = Math.max(0.3, (sin + 1) / 2)
item.style.setProperty('--cos', cos)
item.style.setProperty('--sin', sin)
item.style.setProperty('--scale', scale)
})
}
get counter() {
return this._counter
}
set counter(new_value) {
this._counter = new_value < 0 ? this.sides + new_value : new_value % this.sides
this.notify()
}
}
const slider = new Slider(document.querySelector('.slider'))
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-size: calc(100vw / 106);
--radius-x: 30em;
--radius-y: 10em;
}
.slider {
position: relative;
height: 100vh;
width: 100vw;
overflow: hidden;
}
.slider__list {
position: relative;
list-style: none;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.slider__list__item {
position: absolute;
width: 10em;
height: 10em;
background-image: url('https://market.games.mail.ru/s3/media/product/picture/2020/2/f88a19d82b0e76c6905b2b4afab42452.png');
background-size: cover;
transition: transform 0.5s;
transform:
translateX(calc(var(--cos) * var(--radius-x)))
translateY(calc(var(--sin) * var(--radius-y)))
scale(calc(var(--scale) * 2))
;
}
.slider__list__step-button {
position: absolute;
z-index: 1;
top: 50%;
transform: translateY(-50%);
background: black;
border: none;
color: white;
padding: 1em;
cursor: pointer;
}
.slider__list__step-button_prev {
left: 0;
}
.slider__list__step-button_next {
right: 0;
}
<div class="slider">
<button class="slider__list__step-button slider__list__step-button_prev" data-slider-step-button="-1">Назад</button>
<ul class="slider__list" data-slider-list>
<li class="slider__list__item"></li>
<li class="slider__list__item"></li>
<li class="slider__list__item"></li>
<li class="slider__list__item"></li>
<li class="slider__list__item"></li>
</ul>
<button class="slider__list__step-button slider__list__step-button_next" data-slider-step-button="1">Вперед</button>
</div>
Автор решения: user436559
→ Ссылка
А почему бы не использовать готовую библиотеку gsap, она не слишком обьемная и можно легко реализовать нужный слайдер без проблем, я с помощью неё реализовал подобный слайдер. По этому примеру ( https://codepen.io/jonathan/pen/KVmpOG )
$(window).on("load",function(){
var boxes = $(".box"),
stage = $(".stage");
TweenLite.set(stage, {
css: {
perspective: 1100,
transformStyle: "preserve-3d"
}
});
boxes.each(function(index, element) {
TweenLite.set(element, {
css: {
rotationY: index * 360 / 13,
transformOrigin: "50% 50% -420"
}
});
TweenMax.to(element, 20, {
css: {
z:0.01,
rotationY: "+=359"
},
repeat: -1, // 20
ease: Linear.easeNone
});
});
});
