simple-marquee-js
Version:
A lightweight JavaScript marquee/ticker library with CSS
163 lines (145 loc) • 5.59 kB
JavaScript
/**
* Simple Marquee JS v1.0.1
* A lightweight, responsive marquee ticker library
* https://github.com/jonabIqbal/simple-marquee-js
* MIT Licensed
*/
class SimpleMarquee {
constructor(container, options = {}) {
this.container =
typeof container === 'string'
? document.querySelector(container)
: container;
this.options = {
speed: 500, // pixels per second
direction: 'left', // 'left', 'right', 'up', 'down'
pauseOnHover: true,
duplicateItems: true,
slidesPerView: 3,
slidesPerViewTablet: 2,
slidesPerViewMobile: 1,
spaceBetween: 24,
spaceBetweenTablet: 16,
spaceBetweenMobile: 8,
...options,
};
this.content = this.container.querySelector('.simple_marquee-content');
this.items = Array.from(this.content.children);
this.isPaused = false;
this.itemWidth = 300; // Default width for items, can be adjusted.
this.init();
}
getCurrentBreakpoint() {
const width = window.innerWidth;
if (width <= 600) return 'mobile';
if (width <= 1024) return 'tablet';
return 'desktop';
}
init() {
const containerWidth = this.container.offsetWidth;
// Duplicate until content is longer than container by at least one screen
if (this.options.duplicateItems) {
while (this.content.scrollWidth < containerWidth * 2) {
this.items.forEach((item) => {
const clone = item.cloneNode(true);
this.content.appendChild(clone);
});
}
}
// Set animation direction and speed
this.setDirection(this.options.direction);
this.setSpeed(this.options.speed);
// Add hover events
if (this.options.pauseOnHover) {
this.container.addEventListener('mouseenter', () => this.pause());
this.container.addEventListener('mouseleave', () => this.resume());
}
window.addEventListener('resize', () => {
this.setSlidesPerView();
this.updateAnimation();
});
}
// setSlidesPerView() {
// this.options.slidesPerView = this.options.slidesPerView || 3;
// const containerWidth = this.container.offsetWidth;
// // Calculate item width based on slidesPerView
// console.log(this.options.slidesPerView);
// const itemWidth = containerWidth / this.options.slidesPerView;
// this.items.forEach(item => {
// item.style.width = `${itemWidth}px`;
// });
// }
setSlidesPerView() {
const breakpoint = this.getCurrentBreakpoint();
const slidesPerView = {
desktop: this.options.slidesPerView,
tablet: this.options.slidesPerViewTablet,
mobile: this.options.slidesPerViewMobile,
}[breakpoint];
const spaceBetween = {
desktop: this.options.spaceBetween,
tablet: this.options.spaceBetweenTablet,
mobile: this.options.spaceBetweenMobile,
}[breakpoint];
const containerWidth = this.container.offsetWidth;
const totalSpacing = spaceBetween * (slidesPerView - 1);
const itemWidth = (containerWidth - totalSpacing) / slidesPerView;
this.itemWidth = itemWidth; // Store item width for later use
this.items.forEach((item, index) => {
item.style.width = `${this.itemWidth}px`;
item.style.marginRight =
index !== this.items.length - 1 ? `${spaceBetween}px` : '0';
});
}
setDirection(direction) {
// Remove previous direction classes
this.content.classList.remove(
'simple_marquee-left',
'simple_marquee-right',
'simple_marquee-up',
'simple_marquee-down'
);
// Add new direction class
this.content.classList.add(`simple_marquee-${direction}`);
// Update animation
this.updateAnimation();
}
// setSpeed(speed) {
// // Calculate duration based on content width and speed
// const itemWidth = this.items[0].offsetWidth +
// parseInt(window.getComputedStyle(this.items[0]).marginRight) * 2;
// const totalWidth = itemWidth * this.items.length;
// const duration = totalWidth / speed;
// this.content.style.animationDuration = `${duration}s`;
// }
setSpeed(speed) {
// Get full content width
//const contentWidth = this.content.scrollWidth;
const containerWidth = this.container.offsetWidth;
this.items = Array.from(this.content.children);
this.setSlidesPerView();
// count total items
const speed_x = this.content.scrollWidth / containerWidth;
const duration = speed_x * speed;
this.content.style.animationDuration = `${duration}ms`;
}
pause() {
this.content.style.animationPlayState = 'paused';
this.isPaused = true;
}
resume() {
if (this.isPaused) {
this.content.style.animationPlayState = 'running';
this.isPaused = false;
}
}
updateAnimation() {
// Force reflow to restart animation
this.content.style.animation = 'none';
this.content.offsetHeight; // Trigger reflow
this.content.style.animation = '';
// Reapply speed
this.setSpeed(this.options.speed);
}
}
export default SimpleMarquee;