UNPKG

simple-marquee-js

Version:

A lightweight JavaScript marquee/ticker library with CSS

163 lines (145 loc) 5.59 kB
/** * 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;