UNPKG

materialize-css

Version:

Builds Materialize distribution packages

454 lines (384 loc) 14.1 kB
(function ($) { var methods = { init : function(options) { var defaults = { time_constant: 200, // ms dist: -100, // zoom scale TODO: make this more intuitive as an option shift: 0, // spacing for center image padding: 0, // Padding between non center items full_width: false, // Change to full width styles indicators: false, // Toggle indicators no_wrap: false // Don't wrap around and cycle through items. }; options = $.extend(defaults, options); return this.each(function() { var images, offset, center, pressed, dim, count, reference, referenceY, amplitude, target, velocity, xform, frame, timestamp, ticker, dragged, vertical_dragged; var $indicators = $('<ul class="indicators"></ul>'); // Initialize var view = $(this); var showIndicators = view.attr('data-indicators') || options.indicators; // Don't double initialize. if (view.hasClass('initialized')) { // Redraw carousel. $(this).trigger('carouselNext', [0.000001]); return true; } // Options if (options.full_width) { options.dist = 0; var firstImage = view.find('.carousel-item img').first(); if (firstImage.length) { imageHeight = firstImage.load(function(){ view.css('height', $(this).height()); }); } else { imageHeight = view.find('.carousel-item').first().height(); view.css('height', imageHeight); } // Offset fixed items when indicators. if (showIndicators) { view.find('.carousel-fixed-item').addClass('with-indicators'); } } view.addClass('initialized'); pressed = false; offset = target = 0; images = []; item_width = view.find('.carousel-item').first().innerWidth(); dim = item_width * 2 + options.padding; view.find('.carousel-item').each(function (i) { images.push($(this)[0]); if (showIndicators) { var $indicator = $('<li class="indicator-item"></li>'); // Add active to first by default. if (i === 0) { $indicator.addClass('active'); } // Handle clicks on indicators. $indicator.click(function () { var index = $(this).index(); cycleTo(index); }); $indicators.append($indicator); } }); if (showIndicators) { view.append($indicators); } count = images.length; function setupEvents() { if (typeof window.ontouchstart !== 'undefined') { view[0].addEventListener('touchstart', tap); view[0].addEventListener('touchmove', drag); view[0].addEventListener('touchend', release); } view[0].addEventListener('mousedown', tap); view[0].addEventListener('mousemove', drag); view[0].addEventListener('mouseup', release); view[0].addEventListener('mouseleave', release); view[0].addEventListener('click', click); } function xpos(e) { // touch event if (e.targetTouches && (e.targetTouches.length >= 1)) { return e.targetTouches[0].clientX; } // mouse event return e.clientX; } function ypos(e) { // touch event if (e.targetTouches && (e.targetTouches.length >= 1)) { return e.targetTouches[0].clientY; } // mouse event return e.clientY; } function wrap(x) { return (x >= count) ? (x % count) : (x < 0) ? wrap(count + (x % count)) : x; } function scroll(x) { var i, half, delta, dir, tween, el, alignment, xTranslation; offset = (typeof x === 'number') ? x : offset; center = Math.floor((offset + dim / 2) / dim); delta = offset - center * dim; dir = (delta < 0) ? 1 : -1; tween = -dir * delta * 2 / dim; half = count >> 1; if (!options.full_width) { alignment = 'translateX(' + (view[0].clientWidth - item_width) / 2 + 'px) '; alignment += 'translateY(' + (view[0].clientHeight - item_width) / 2 + 'px)'; } else { alignment = 'translateX(0)'; } // Set indicator active if (showIndicators) { var diff = (center % count); var activeIndicator = $indicators.find('.indicator-item.active'); if (activeIndicator.index() !== diff) { activeIndicator.removeClass('active'); $indicators.find('.indicator-item').eq(diff).addClass('active'); } } // center // Don't show wrapped items. if (!options.no_wrap || (center >= 0 && center < count)) { el = images[wrap(center)]; el.style[xform] = alignment + ' translateX(' + (-delta / 2) + 'px)' + ' translateX(' + (dir * options.shift * tween * i) + 'px)' + ' translateZ(' + (options.dist * tween) + 'px)'; el.style.zIndex = 0; if (options.full_width) { tweenedOpacity = 1; } else { tweenedOpacity = 1 - 0.2 * tween; } el.style.opacity = tweenedOpacity; el.style.display = 'block'; } for (i = 1; i <= half; ++i) { // right side if (options.full_width) { zTranslation = options.dist; tweenedOpacity = (i === half && delta < 0) ? 1 - tween : 1; } else { zTranslation = options.dist * (i * 2 + tween * dir); tweenedOpacity = 1 - 0.2 * (i * 2 + tween * dir); } // Don't show wrapped items. if (!options.no_wrap || center + i < count) { el = images[wrap(center + i)]; el.style[xform] = alignment + ' translateX(' + (options.shift + (dim * i - delta) / 2) + 'px)' + ' translateZ(' + zTranslation + 'px)'; el.style.zIndex = -i; el.style.opacity = tweenedOpacity; el.style.display = 'block'; } // left side if (options.full_width) { zTranslation = options.dist; tweenedOpacity = (i === half && delta > 0) ? 1 - tween : 1; } else { zTranslation = options.dist * (i * 2 - tween * dir); tweenedOpacity = 1 - 0.2 * (i * 2 - tween * dir); } // Don't show wrapped items. if (!options.no_wrap || center - i >= 0) { el = images[wrap(center - i)]; el.style[xform] = alignment + ' translateX(' + (-options.shift + (-dim * i - delta) / 2) + 'px)' + ' translateZ(' + zTranslation + 'px)'; el.style.zIndex = -i; el.style.opacity = tweenedOpacity; el.style.display = 'block'; } } // center // Don't show wrapped items. if (!options.no_wrap || (center >= 0 && center < count)) { el = images[wrap(center)]; el.style[xform] = alignment + ' translateX(' + (-delta / 2) + 'px)' + ' translateX(' + (dir * options.shift * tween) + 'px)' + ' translateZ(' + (options.dist * tween) + 'px)'; el.style.zIndex = 0; if (options.full_width) { tweenedOpacity = 1; } else { tweenedOpacity = 1 - 0.2 * tween; } el.style.opacity = tweenedOpacity; el.style.display = 'block'; } } function track() { var now, elapsed, delta, v; now = Date.now(); elapsed = now - timestamp; timestamp = now; delta = offset - frame; frame = offset; v = 1000 * delta / (1 + elapsed); velocity = 0.8 * v + 0.2 * velocity; } function autoScroll() { var elapsed, delta; if (amplitude) { elapsed = Date.now() - timestamp; delta = amplitude * Math.exp(-elapsed / options.time_constant); if (delta > 2 || delta < -2) { scroll(target - delta); requestAnimationFrame(autoScroll); } else { scroll(target); } } } function click(e) { // Disable clicks if carousel was dragged. if (dragged) { e.preventDefault(); e.stopPropagation(); return false; } else if (!options.full_width) { var clickedIndex = $(e.target).closest('.carousel-item').index(); var diff = (center % count) - clickedIndex; // Disable clicks if carousel was shifted by click if (diff !== 0) { e.preventDefault(); e.stopPropagation(); } cycleTo(clickedIndex); } } function cycleTo(n) { var diff = (center % count) - n; // Account for wraparound. if (!options.no_wrap) { if (diff < 0) { if (Math.abs(diff + count) < Math.abs(diff)) { diff += count; } } else if (diff > 0) { if (Math.abs(diff - count) < diff) { diff -= count; } } } // Call prev or next accordingly. if (diff < 0) { view.trigger('carouselNext', [Math.abs(diff)]); } else if (diff > 0) { view.trigger('carouselPrev', [diff]); } } function tap(e) { pressed = true; dragged = false; vertical_dragged = false; reference = xpos(e); referenceY = ypos(e); velocity = amplitude = 0; frame = offset; timestamp = Date.now(); clearInterval(ticker); ticker = setInterval(track, 100); } function drag(e) { var x, delta, deltaY; if (pressed) { x = xpos(e); y = ypos(e); delta = reference - x; deltaY = Math.abs(referenceY - y); if (deltaY < 30 && !vertical_dragged) { // If vertical scrolling don't allow dragging. if (delta > 2 || delta < -2) { dragged = true; reference = x; scroll(offset + delta); } } else if (dragged) { // If dragging don't allow vertical scroll. e.preventDefault(); e.stopPropagation(); return false; } else { // Vertical scrolling. vertical_dragged = true; } } if (dragged) { // If dragging don't allow vertical scroll. e.preventDefault(); e.stopPropagation(); return false; } } function release(e) { if (pressed) { pressed = false; } else { return; } clearInterval(ticker); target = offset; if (velocity > 10 || velocity < -10) { amplitude = 0.9 * velocity; target = offset + amplitude; } target = Math.round(target / dim) * dim; // No wrap of items. if (options.no_wrap) { if (target >= dim * (count - 1)) { target = dim * (count - 1); } else if (target < 0) { target = 0; } } amplitude = target - offset; timestamp = Date.now(); requestAnimationFrame(autoScroll); if (dragged) { e.preventDefault(); e.stopPropagation(); } return false; } xform = 'transform'; ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { var e = prefix + 'Transform'; if (typeof document.body.style[e] !== 'undefined') { xform = e; return false; } return true; }); window.onresize = scroll; setupEvents(); scroll(offset); $(this).on('carouselNext', function(e, n) { if (n === undefined) { n = 1; } target = offset + dim * n; if (offset !== target) { amplitude = target - offset; timestamp = Date.now(); requestAnimationFrame(autoScroll); } }); $(this).on('carouselPrev', function(e, n) { if (n === undefined) { n = 1; } target = offset - dim * n; if (offset !== target) { amplitude = target - offset; timestamp = Date.now(); requestAnimationFrame(autoScroll); } }); $(this).on('carouselSet', function(e, n) { if (n === undefined) { n = 0; } cycleTo(n); }); }); }, next : function(n) { $(this).trigger('carouselNext', [n]); }, prev : function(n) { $(this).trigger('carouselPrev', [n]); }, set : function(n) { $(this).trigger('carouselSet', [n]); } }; $.fn.carousel = function(methodOrOptions) { if ( methods[methodOrOptions] ) { return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { // Default to "init" return methods.init.apply( this, arguments ); } else { $.error( 'Method ' + methodOrOptions + ' does not exist on jQuery.carousel' ); } }; // Plugin end }( jQuery ));