Slider per qualsiasi elemento del DOM con jQuery

  • 13 Jul 2012
  • Resources, jQuery

Lo scopo di questo plugin è di fare uno slider con gli elementi di un elenco HTML.

In questo caso, si trattava di un insieme d'immagini con la loro descrizione che raccontano la storia di un'azienda lungo i suoi quasi 150 anni. Il risultato finale si può vedere qui

Il codice HTML di partenza era più o meno questo:

<div id="slideme">
  <div id="slides">
    <ul>
      <li>
        <div>
          <h4 id="button">
                  1854</h4>
          <h4>
                  First factory for the chestnut extraction production &nbsp;in Italy</h4>
          <p>In Corsaglia di Frabosa.....</p>
        </div>
        [immagine]
      </li>
      <li>
          ....
      </li>
    </ul>
  </div>
</div>

Queste sono le funzioni del plugin:

  • Costruire un elemento contenendo i bottoni che permettono all'utente di navigare lungo tutte le immagini.
  • Aggiungere un bottone che permetta all'utente di fare una pausa.
  • Eseguire la riproduzione automatica dello slider.
/*  jQuery Plugin
 *  Muestra en forma rotativa cada elemento en forma de lista contenido
 *  dentro de otro que deja mostrar solo uno
 *
 *  FX1: Desplaza los elementos hacia arriba y llegado el fin, vuelve a 
 *  mostrar el primero
 *  FX2: Oculta el elemento que se esta viendo (fadeout) y muestra el 
 *  siguiente (fadeto)
 
  pause 
    type: number
    descr: tiempo en milisegundos en que la animación permanecerá inmovil
  controls 
    type: boolean
    descr: genera html con botones para moverse a través de las diapositivas
  go_to 
    type: number
    descr: indice del elemento que se mostrará en primer lugar
  display
    type: enum
    opts: horizontal, vertical, fade
    descr: tipo de animacion entre cada elemento. Horizontal y vertical hacen
           movimiento. Fade hace un efecto de transparencia entre los elementos
 
 */
jQuery.fn.penny_slider = function(options){

	var defaults = {
		elements:     'li',
		go_to:        -1,
		fade_over:    1,
		fade_to:      0.4,
		fx_delay:     600,
		pause:        0,
		controls:     false,
		display:      'horizontal'
	};

	/* merge options given with defaults */
	var opts = $.extend(defaults, options);
	var slider = this;
	var len = slider.find(opts['elements']).length;

	/* check for requiered values */
	if (!options['width']) {
		options['width'] = slider.find(opts['elements']).outerWidth(true);
	} 
	if (!options['height']) {
		options['height'] = slider.find('ul').outerHeight(true)/len;
	} 

	if (!options['slide_dist']) {
		switch (opts['display'])
		{
		case 'horizontal':
			opts['slide_dist'] = options['width'];
			break;
		case 'vertical':
			opts['slide_dist'] = options['height'];			
			break;
		}
	} 

	var slider_width = opts['width']*len;

	// create buttons
	if (opts['controls'] == true && slider.find('.slider_control').length == 0) {
		var html = "";
		for (n=0; n < len; n++) {
			var element = slider.find('li:eq('+n+')');
			if (opts['display'] == 'horizontal') {
				element.css("float","left");
			}
			var button_wrapper = element.find('#button');
			var button_name = button_wrapper.html();
			button_wrapper.remove();
			html += "<span id='"+(n+1)+"' >"+button_name+"</span>";
		}
		controls_  = "<div id='controls'>";
		controls_ += "  <div class='repro'></div>";
		controls_ += "  <div class='pause'></div>";
		controls_ += "  <div class='time'></div>";
		controls_ += "</div>";
		
		slider.prepend(controls_+"<div class='slider_control_wpr'><div class='slider_control'>"+html+"</div></div>");
		slider.find(".time").html(opts['pause']/1000);

		/* control events */
		slider.find(".repro").click(function(){
			clock();
			showme ();
			start();
		}).mouseover(function(){
			$(this).css('cursor','pointer');
		});
		slider.find(".pause").click(function(){
			pause();
		}).mouseover(function(){
			$(this).css('cursor','pointer');
		});

		/*  botones creados
		 *
		 */
		var wp_width = slider.find('.slider_control_wpr').width();
		$(".slider_control").data('wp_width', wp_width); 
		var wp_pos = slider.offset(); 
		var bt_wp = slider.find('.slider_control');
		$(".slider_control").data('bt_wp', bt_wp); 

		var bt_wp_pos = bt_wp.offset();
		$(".slider_control").data('bt_wp_pos', bt_wp.offset());

		/*  width del contenedor de los botones */
		var bt_wp_width = 0;
		slider.find(".slider_control span").each(function(){
			bt_wp_width += $(this).outerWidth(true);
		});


		/* control buttons wrapper */
		var bt_wp_width = 0;
		$(".slider_control").find('span').each(function(){

			if (opts['go_to'] == $(".slider_control span").index($(this))+1) {
				$(".slider_control").data("active", $(this).attr('id'));
				$(this).addClass("active");
			}

			bt_wp_width += $(this).outerWidth(true);

			$(this).click(function(){
				/* distinguish active */
				pause ();
				active_id = $('.slider_control').data('active');
				$(".slider_control #"+active_id).removeClass('active');
				$(".slider_control").data("active", $(this).attr('id'));
				$(this).addClass("active");

				//control_move ($(this));

				slider.penny_slider({
					fade_to:      1,
					slide_dist:   opts['slide_dist'],
					elements:     opts['elements'],
					go_to:        $(this).attr('id'),
					display:      opts['display'],
					pause:        0
				})
				
			}).mouseover(function(){
				$(this).css("cursor","pointer");
			})
		});

		/* correct wrapper width */
		slider.find(".slider_control").width(bt_wp_width);
		$(".slider_control").data('bt_wp_width', bt_wp_width);

	}
	/* botones listos */
	
	if (opts['fade_to'] != 1) {
		slider.find(opts['elements']+':first').fadeTo(opts['fx_delay'], opts['fade_to']);
	}
	slider.find(opts['elements']).fadeTo(opts['fx_delay'], opts['fade_to']);

	goto_n = opts['go_to']-1;

	function control_move (button) {
		/* porcentaje del ancho del boton cliqueado
		 *
		 */				
		var bt_position = button.offset();
		var bt_width = button.outerWidth();
		var bt_wp = $(".slider_control").data('bt_wp');
		var bt_wp_pos = $(".slider_control").data('bt_wp_pos');
		var bt_wp_width = $(".slider_control").data('bt_wp_width');
		var wp_width = $(".slider_control").data('wp_width');
				
		/* this_limit: distancia desde el 0 de los botones 
		 * hasta la mitad del ancho del boton apretado 
		 */
		this_limit = bt_position['left'] - bt_wp_pos['left'] + bt_width/2;
		this_percent = this_limit*100/bt_wp_width;
		wp_width_rel = wp_width*this_percent/100;

		/* dist difference btw control and content */
		dist_diff = this_limit-wp_width_rel;
		if (this_limit > wp_width/2) {

			move_diff = this_limit-(wp_width/2);

			if (move_diff > (bt_wp_width - wp_width)) {

				move_diff = bt_wp_width - wp_width;
			} 
									
		} else {
			move_diff = 0;
		}

		// move controls
		$(".slider_control").animate({ 
			left: -move_diff
		}, 600, 'swing', 
		function(){
			$(".slider_control").data('bt_wp_pos',bt_wp.offset()); 
		});
	}


	function showme () {

		/* fx: move element */
		if (opts['display'] == 'horizontal' || opts['display'] == 'vertical') {
			
			if (goto_n >= len) {
				goto_n = 0;
			}
			
			if (opts['display'] == 'vertical') {
				_top = opts['slide_dist']*-1*goto_n;
				_left = 0;
			} else {
				_top = 0;
				_left = opts['width']*-1*goto_n;
			}


				bt_active = $(".slider_control").data("active");
				$(".slider_control").find("#"+bt_active).removeClass("active");
				
				goto_n++;

				var button_active = $(".slider_control").find("#"+goto_n);
				button_active.addClass("active");
				$(".slider_control").data("active", goto_n);

				control_move (button_active);

			// move it
			slider.find('ul').animate({
				top: _top+'px',
				left: _left+'px'				
	  		}, opts['fx_delay'], 'swing', function() {
				// Animation complete.
			});

		} else {
		
			/* fx: fade_out -> fade_in => time/2 */
			var fx_delay =  opts['fx_delay']/2;

			slider.find(opts['elements']).unbind();			
			// hide current
			slider.find(opts['elements']+':eq('+current_show+')').fadeOut(fx_delay, function(){
				// bind!
				slider.find(opts['elements']+':eq('+next_show+')').bind({
						mouseenter: function(){
							pause();
							$(this).fadeTo('fast', opts['fade_over']);
						},
						mouseleave: function(){
							$(this).fadeTo('fast', opts['fade_to']);
							start();
						}
					})
					// show!
					.fadeTo(fx_delay, opts['fade_to'], function(){
					current_show = next_show;
					next_show++;
					if (next_show >= len) {
						next_show = 0;
						current_show = len-1;
					}
				});
			});
		}
	}

	function start () {
		if (opts['pause'] > 0) {
			slider.find("#controls .repro").hide();
			slider.find("#controls .pause").show();
	 		slider.everyTime(opts['pause'], function(){
	 			debug("start");
				clock();
				showme ();
			});
		} else {
			showme ();
		}
	}

	function pause () {
		slider.find("#controls .pause").hide();
		slider.find("#controls .repro").show();
		slider.find('.time').stopTime();
		slider.stopTime();
	}

	function clock () {
		var time_ = (opts['pause']/1000)-1;
		slider.find('.time').stopTime();
		debug("clock");
	 	slider.find('.time').everyTime(1000, function(){
			slider.find('.time').html(time_);
			debug(time_);
			time_--;
		});
	}


	start ();
}