'Adaptable size on slider js only
Somehow I feel like there must be an answer somewhere already, but I've failed to find it, please drop the link if so.
Here's my trouble: I got this hand made slider that was doing the job until I had to make the number of element in it dynamic.
Since am using width to calculate how much space each element takes, once I change the number of element appearing, the slider jumps out of proportion.
What I'd like is for the slider to never change its size on any amount of slide showed. I'd like the image to be resized adequately.
You can check it out here: https://codepen.io/kaijuVegan/pen/abVzRmv
Here's are my js and css:
class Carouselle {
/**
* @param {HTMLElement} element
* @param {Object} options
* @param {number} options.slidesVisible how many element visible(must be lower than resourceArr.length and higher than slidesVisible)
* @param {number} options.slidesToScroll how many slides to scroll at once(must be lower than slidesVisible)
* @param {array} resourceArr array of array containing in that order id, name and img path
* @param {string} path path to images folder
*/
constructor(element, options = {}, resourceArr, path) {
this.element = element;
this.options = Object.assign({}, {
slidesVisible: 1,
slidesToScroll: 1,
}, options);
this.resourceArr = resourceArr;
this.path = path;
this.root = this.createDivWithClass('carousel');
this.container = this.createDivWithClass('carousel-container');
this.root.appendChild(this.container);
this.element.appendChild(this.root);
this.isMobile();
this.dragFeature();
this.gotoItem(this.offset, false)
this.currentItem = this.offset;
this.container.addEventListener('transitionend', this.resetInfinite.bind(this));
}
/**
* @param {string} className
* @returns {HTMLElement}
*/
createDivWithClass(className) {
let div = document.createElement('div');
div.setAttribute('class', className);
return div;
}
/**
* Mobile features, hide unrequited button, make slide visible to 5 if mobile
*/
isMobile() {
if (window.innerWidth > 600) {
this.carouselDisplay();
this.navigation(false);
} else {
this.carouselDisplay(5);
this.navigation(true);
}
}
carouselDisplay(slidesVisible = null) {
if (slidesVisible != null) {
this.options.slidesVisible = slidesVisible;
}
this.offset = this.options.slidesVisible;
// reorganize array to allow infinite loop
let newArr = [];
this.resourceArr.forEach(arr => {
let insertBefore = arr.slice(arr.length - this.offset);
let insertAfter = arr.slice(0, this.offset);
let someArr = [
...insertBefore,
...arr,
...insertAfter
]
newArr.push(someArr)
})
this.resourceArr = newArr;
for (let i = 0; i < this.resourceArr[0].length; i++) {
let item = this.createDivWithClass('item');
item.setAttribute('data-id', this.resourceArr[0][i]);
this.container.appendChild(item);
let img = document.createElement('img');
img.setAttribute('src', this.path + this.resourceArr[2][i]);
img.setAttribute('class', 'carousel-img');
item.appendChild(img);
let itemName = this.createDivWithClass('item-name')
itemName.innerHTML = "" + this.resourceArr[1][i].charAt(0).toUpperCase() + this.resourceArr[1][i].slice(1) + ""
item.appendChild(itemName);
}
this.items = [].slice.call(this.container.children);
let ratio = this.items.length / this.options.slidesVisible;
this.container.style.width = (ratio * 100) + "%";
this.itemsWidth = (100 / this.options.slidesVisible / ratio);
this.items.forEach(item => {
item.style.width = this.itemsWidth + "%";
});
let img = document.getElementsByClassName("carousel-img");
this.images = [].slice.call(img)
this.images.forEach(img => {
img.style.width = '25%'
})
}
/**
* Add next and previous buttons
*/
navigation(mobile = false) {
this.nextButton = document.createElement('button');
this.nextButton.setAttribute('class', "carousel-nextBtn");
this.nextButton.setAttribute('style', 'width:' + this.itemsWidth + '%');
this.nextButton.innerHTML = "<img src='/img/assets/right-arrow.png' alt='previous_item'>";
this.prevButton = document.createElement('button');
this.prevButton.setAttribute('class', "carousel-prevBtn");
this.prevButton.setAttribute('style', 'width:' + this.itemsWidth + '%');
this.prevButton.innerHTML = "<img src='/img/assets/left-arrow.png\' alt='next_item'>";
this.root.appendChild(this.nextButton);
this.root.appendChild(this.prevButton);
this.nextButton.addEventListener('click', this.next.bind(this));
this.prevButton.addEventListener('click', this.prev.bind(this));
}
next() {
this.gotoItem(this.currentItem + this.options.slidesToScroll)
}
prev() {
this.gotoItem(this.currentItem - this.options.slidesToScroll)
}
/**
* Goto slide x
* @param {number} index
* @param {boolean} [animation = true]
*/
gotoItem(index, animation = true) {
let translateX = index * -100 / this.items.length;
this.currentItem = index;
if (animation === false) {
this.container.style.transition = 'none';
}
this.container.style.transform = 'translate3d(' + translateX + '% ,0 ,0)';
this.nextButton.disabled = true;
this.nextButton.disabled = true;
this.container.offsetHeight//force repaint
if (animation === false) {
this.container.style.transition = '';
}
}
/**
* Make the slider infinite
*/
resetInfinite() {
this.nextButton.disabled = false;
this.prevButton.disabled = false;
if (this.currentItem <= this.options.slidesToScroll) {
this.gotoItem(this.currentItem + (this.items.length - 2 * this.offset), false)
} else if (this.currentItem >= this.items.length - this.offset) {
this.gotoItem(this.currentItem - (this.items.length - 2 * this.offset), false)
}
}
/**
* Allow slider to be draggable
*/
dragFeature() {
this.container.addEventListener('dragstart', (e) => {
e.preventDefault()
})
this.container.addEventListener('mousedown', this.startDrag.bind(this))
this.container.addEventListener('touchstart', this.startDrag.bind(this), {passive: false})
window.addEventListener('mousemove', this.drag.bind(this))
window.addEventListener('touchmove', this.drag.bind(this))
window.addEventListener('touchend', this.endDrag.bind(this))
window.addEventListener('mouseup', this.endDrag.bind(this))
window.addEventListener('touchcancel', this.endDrag.bind(this))
}
startDrag(e) {
if (e.touches) {
if (e.touches.length > 1) {
return
} else {
e = e.touches[0]
}
}
this.origin = {x: e.screenX, y: e.screenY}
this.width = this.container.offsetWidth;
this.container.style.transition = "none";
this.container.style.cursor = 'grabbing';
}
drag(e) {
e.preventDefault();
if (this.origin) {
let point = e.touches ? e.touches[0] : e;
let translate = {x: point.screenX - this.origin.x, y: point.screenY - this.origin.y};
let baseTranslate = (this.currentItem * -100) / this.items.length;
this.lastTranslate = translate;
let translateX = baseTranslate + (100 * translate.x / this.width);
this.container.style.transform = 'translate3d(' + translateX + '%, 0, 0)';
}
}
endDrag() {
this.container.style.cursor = 'grab';
if (this.origin && this.lastTranslate) {
this.container.style.transition = '';
let target = Math.round((this.lastTranslate.x / this.element.offsetWidth) / ((100 / this.options.slidesVisible) / 100));
this.gotoItem(this.currentItem + (target * -1));
}
this.origin = null;
this.lastTranslate = null;
}
}//class
let category = [[0,1,2,3,4,5,6,7],["flower", "flower", "flower", "flower", "flower", "flower", "flower", "flower"],[ "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159", "https://cdn-icons.flaticon.com/png/512/2396/premium/2396481.png?token=exp=1643277263~hmac=aab3f9406f8b4c4eceb7af2ba6858159"] ]
let logoPath = ""
console.log(document.querySelector('.slider'))
new Carouselle(document.querySelector('.slider'),
{
slidesVisible: 3,
slidesToScroll: 1,
},
category,
logoPath
)
.carousel {
position: relative;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.90);
text-align: center;
display: flex;
flex-direction: column;
justify-content: space-evenly;
border-radius: 0.5rem;
}
.carousel > button > img{
display: none;
/* @media (min-width: 992px) {
display: block;
} */
}
.carousel-container {
transition: transform 0.3s;
display: inline-block;
}
.carousel::after {
content: '';
clear: both;
display: table;
}
.item {
float: left;
transition-duration: 0.3s;
transform-origin: center;
transform: scale(0.6);
border-radius: 50%;
}
.item:hover {
transform: scale(0.8);
background-color: rgba(255, 255, 255, 100);
border-radius: 50%;
cursor: pointer;
}
#selected{
float: left;
transform: scale(0.8);
background-color: rgba(255, 255, 255, 100);
border-radius: 50%
}
.item-selected{
float: left;
transform: scale(0.8);
background-color: rgba(255, 255, 255, 100);
border-radius: 50%
}
.item-selected > img {
max-width: 45%;
max-height: 45%;
}
.item-selected > .item-name {
margin-top: 25%;
font-family: "Baloo Tamma 2", sans-serif;
font-weight: bold;
font-size: 20px;
white-space: nowrap;
margin-left: -100%;
margin-right: -100%;
text-align: center;
}
.carousel-nextBtn, .carousel-prevBtn {
position: absolute;
border-style: unset;
background: initial;
right: 0.2%;
border-radius: 0.5rem;
cursor: pointer;
transition-duration: 0.3s;
}
.carousel-prevBtn {
left: 0.2%;
}
.carousel-nextBtn:hover {
transform: scale(1.2) translate(15%, 0);
}
.carousel-prevBtn:hover {
transform: scale(1.2) translate(-15%, 0);
}
.item > img {
max-width: 45%;
max-height: 45%;
}
.item > .item-name {
margin-top: 25%;
font-family: "Baloo Tamma 2", sans-serif;
font-weight: bold;
font-size: 20px;
white-space: nowrap;
margin-left: -100%;
margin-right: -100%;
text-align: center;
}
So far i've been trying to change the img width since it's the only css attribute that behaves the way I like. But then am struggling with the math. How to calculate a proportional image width in order the slider stay the same height?
If you have much more elegant way to solve this, I'll gladly take it too!
By the way, I'd like it to remain javascript/css only :)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
