function Timer(callback, delay) { /* Private properties */ let timerId, start, remaining = delay; /* Public methods */ this.resume = () => { start = new Date(); timerId = setTimeout(() => { remaining = delay; this.resume(); callback(); }, remaining); }; this.pause = () => { clearTimeout(timerId); remaining -= new Date() - start; }; this.become = () => { clearTimeout(timerId); remaining = delay; this.resume(); }; /* Constructor */ this.resume(); }
function Carousel(setting) { /* Scope private methods and properties */ let private = {}, xDown, yDown, xUp, yUp, xDiff, yDiff; /* Private properties */ private.default = { "touch": true, "autoplay": false, "autoplayDelay": 3000, "pauseOnFocus": true, "pauseOnHover": true }; private.setting = Object.assign(private.default, setting); private.isAnimationEnd = true; private.sel = { "wrap": document.querySelector(private.setting.wrap), "children": document.querySelector(private.setting.wrap).children, "prev": document.querySelector(private.setting.prev), "next": document.querySelector(private.setting.next) }; private.opt = { "position": 0, "max_position": document.querySelector(private.setting.wrap).children.length }; /* Constructor */ // Clone first elem to end wrap private.sel.wrap.appendChild(private.sel.children[0].cloneNode(true)); // Autoplay if(private.setting.autoplay === true) { private.timer = new Timer(this.next_slide, private.setting.autoplayDelay); } // Control if(private.sel.prev !== null) { private.sel.prev.addEventListener('click', () => { this.prev_slide(); }); } if(private.sel.next !== null) { private.sel.next.addEventListener('click', () => { this.next_slide(); }); } // Touch events if(private.setting.touch === true) { private.sel.wrap.addEventListener('touchstart', private.hts, false); private.sel.wrap.addEventListener('touchmove', private.htm, false); } // Pause on hover if(private.setting.autoplay === true && private.setting.pauseOnHover === true) { private.sel.wrap.addEventListener('mouseenter', () => { private.timer.pause(); }); private.sel.wrap.addEventListener('mouseleave', () => { private.timer.become(); }); } private.hts = (e) => { xDown = e.touches[0].clientX; yDown = e.touches[0].clientY; }; private.htm = (e) => { if ( ! xDown || ! yDown ) { return; } xUp = e.touches[0].clientX; yUp = e.touches[0].clientY; xDiff = xDown - xUp; yDiff = yDown - yUp; if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) { if ( xDiff > 0 ) { this.next_slide(); } else { this.prev_slide(); } } xDown = 0; yDown = 0; }; }
// Prev slide this.prev_slide = () => { if(!private.isAnimationEnd) { return; } private.isAnimationEnd = false; --private.opt.position; if(private.opt.position < 0) { private.sel.wrap.classList.add('s-notransition'); private.sel.wrap.style["transform"] = `translateX(-${private.opt.max_position}00%)`; private.opt.position = private.opt.max_position - 1; } setTimeout(() => { private.sel.wrap.classList.remove('s-notransition'); private.sel.wrap.style["transform"] = `translateX(-${private.opt.position}00%)`; }, 10); private.sel.wrap.addEventListener('transitionend', () => { private.isAnimationEnd = true; }); if(private.setting.autoplay === true) { private.timer.become(); } }; // Next slide this.next_slide = () => { if(!private.isAnimationEnd) { return; } private.isAnimationEnd = false; if(private.opt.position < private.opt.max_position) { ++private.opt.position; } private.sel.wrap.classList.remove('s-notransition'); private.sel.wrap.style["transform"] = `translateX(-${private.opt.position}00%)`; private.sel.wrap.addEventListener('transitionend', () => { if(private.opt.position >= private.opt.max_position) { private.sel.wrap.style["transform"] = 'translateX(0)'; private.sel.wrap.classList.add('s-notransition'); private.opt.position = 0; } private.isAnimationEnd = true; }); if(private.setting.autoplay === true) { private.timer.become(); } };
Source: https://habr.com/ru/post/327690/
All Articles