ldc-le-gaulois-pro/resources/js/components/carousel.js
2022-09-06 09:02:11 +00:00

227 lines
No EOL
6.8 KiB
JavaScript

/*js doc*/
export class Carrousel {
/**
*
* This callback type is called 'requestCallback' and is displayed as a global symbol
*
* @callback moveCallback
* @param {number} index
*/
/**
*
*
* @param {HTMLElement} element
* @param {Object} options
* @param {Object} [options.slidesToScroll=1] Nombre d'éléments à faire défiler
* @param {Object} [options.slidesVisible=1] Nombre d'éléments visible dans un slide
* @param {boolean} [options.loop=false] Doit-on boucler en fin de carrousel
* @param {boolean} [options.pagination=false]
* @param {boolean} [options.navigation=true]
*/
constructor(element, options = {}) {
this.element = element
this.options = Object.assign({}, {
slidesToScroll: 1,
slidesVisible: 1,
loop: true,
play: true,
interval: 3000,
pagination: false,
navigation: true
}, options)
let children = [].slice.call(element.children)
this.isMobile = false
this.currentItem = 0
this.moveCallbacks = []
//Modification du DOM
this.root = this.createDivWithClass('carrousel')
this.container = this.createDivWithClass('carrousel__container')
this.root.setAttribute('tabindex', '0')
this.root.appendChild(this.container)
this.element.appendChild(this.root)
this.items = children.map((child) => {
let item = this.createDivWithClass('carrousel__item')
item.appendChild(child)
this.container.appendChild(item)
return item
})
this.setStyle()
if (this.options.navigation) {
this.createNavigation()
}
if (this.options.pagination) {
this.createPagination()
}
//Evenements
this.moveCallbacks.forEach(cb => cb(0))
this.onWindowResize()
window.addEventListener('resize', this.onWindowResize.bind(this))
this.root.addEventListener('keyup', e => {
if (e.key === 'ArrowRight' || e.key === 'Right') {
this.next()
} else if (e.key === 'ArrowLeft' || e.key === 'Left') {
this.prev()
}
})
// Interval
if (this.options.play) {
let playpause = setInterval(() => this.next(), this.options.interval);
}
}
/**
* Applique les bonnes dimensions aux éléments du carrousel
*/
setStyle() {
let ratio = this.items.length / this.slidesVisible
this.container.style.width = (ratio * 100) + "%"
this.items.forEach(item => item.style.width = ((100 / this.slidesVisible) / ratio) + "%")
}
/**
* Créer les flêches de navigation dans le DOM
*/
createNavigation() {
let nextButton = this.createDivWithClass('carrousel__next')
let prevButton = this.createDivWithClass('carrousel__prev')
this.root.appendChild(nextButton)
this.root.appendChild(prevButton)
nextButton.addEventListener('click', this.next.bind(this))
prevButton.addEventListener('click', this.prev.bind(this))
if (this.options.loop === true) {
return
}
this.onMove(index => {
if (index === 0) {
prevButton.classList.add('carrousel__prev--hidden')
} else {
prevButton.classList.remove('carrousel__prev--hidden')
}
if (this.items[this.currentItem + this.slidesVisible] === undefined) {
nextButton.classList.add('carrousel__next--hidden')
} else {
nextButton.classList.remove('carrousel__next--hidden')
}
})
}
/**
* Créer la pagination dans le DOM
*/
createPagination() {
let pagination = this.createDivWithClass('carrousel__pagination')
let buttons = []
this.root.appendChild(pagination)
for (let i = 0; i < this.items.length; i = i + this.options.slidesToScroll) {
let button = this.createDivWithClass('carrousel__pagination__button')
button.addEventListener('click', () => this.gotoItem(i))
pagination.appendChild(button)
buttons.push(button)
}
this.onMove(index => {
let activeButton = buttons[Math.floor(index / this.options.slidesToScroll)]
if (activeButton) {
buttons.forEach(button => button.classList.remove('carrousel__pagination__button--active'))
activeButton.classList.add('carrousel__pagination__button--active')
}
})
}
next() {
this.gotoItem(this.currentItem + this.slidesToScroll)
}
prev() {
this.gotoItem(this.currentItem - this.slidesToScroll)
}
/**
* Déplace le carrousel vers l'élément ciblé
* @param {number} index
*/
gotoItem(index) {
if (index < 0) {
if (this.options.loop) {
index = this.items.length - this.slidesVisible
} else {
return
}
} else if (index >= this.items.length || (this.items[this.currentItem + this.slidesVisible] === undefined && index > this.currentItem)) {
if (this.options.loop) {
index = 0
} else {
return
}
}
let translateX = index * -100 / this.items.length
this.container.style.transform = 'translate3d(' + translateX + '%, 0, 0)'
this.currentItem = index
this.moveCallbacks.forEach(cb => cb(index))
}
/**
*
* @param {moveCallback} cb
*/
onMove(cb) {
this.moveCallbacks.push(cb)
}
onWindowResize() {
let mobile = window.innerWidth < 800
if (mobile !== this.isMobile) {
this.isMobile = mobile
this.setStyle()
this.moveCallbacks.forEach(cb => cb(this.currentItem))
}
}
/**
*
* @param {string} className
* @returns {HTMLElement}
*/
createDivWithClass(className) {
let div = document.createElement('div')
div.setAttribute('class', className)
return div
}
/**
* @returns {number}
*/
get slidesToScroll() {
return this.isMobile ? 1 : this.options.slidesToScroll
}
/**
* @returns {number}
*/
get slidesVisible() {
return this.isMobile ? 1 : this.options.slidesVisible
}
}
document.addEventListener('DOMContentLoaded', function () {
if (document.querySelector('#carrousel1')) {
new Carrousel(document.querySelector('#carrousel1'), {
pagination: true,
navigation: false,
})
}
if (document.querySelector('#carrousel2')) {
new Carrousel(document.querySelector('#carrousel2'), {})
}
})