Natedesigns





TinyCarousel Extension – Vertical and Horizontal

If you haven’t come across TinyCarousel it’s a great lightweight plugin for carousel functionality. http://baijs.nl/tinycarousel/

I’ve used it for a number of projects, but with this specific project I needed to have dynamic title text. From what I know of TinyCarousel, each ‘box’ or li should be the same height as the .viewport is set in css and not worked out dynamically.

I tried altering the code base to allow the .viewport to be set dynamically; which I managed but then you need to set the amount forward/backward it needs to move. It just started to get really complex and the timeframe didn’t allow for re-write of the entire base – if i could have, plus I wanted a tried and tested base.

Therefor I built upon it by allow the user to only see the category/tag of what the article is. on hover the user gets the entire title. The title can be any length due to the code pushing the article below down, or extending the height of the container.

I used a shuffle function from css tricks, expanded upon by ‘Jesse’ http://css-tricks.com/snippets/jquery/shuffle-dom-elements/#li-comment-441140 to randomise the content as per our specification.

Note: code on demo differs slightly to below as the code below assumes the setting of certain server side variables. Also, as we are on a cms using jquery 1.2 I needed to alter the tinycarousel code slightly.

The code:

$(function($){

	//Empty function so that we don't have to get rid of console.log for IE
	function emptyFunction(a) { }
		window.console = window.console || {
			log: emptyFunction,
			info: emptyFunction,
			warn: emptyFunction,
			error: emptyFunction
		}
	
	//Instanciating tinyCarousel
   $('#thumb_slide1').tinycarousel({ 
	   pager: false, 
	   //interval: true, 
	   display: 5,
	   axis: 'y',
	   callback: function(){
		   
	   }
	});

     $('#thumb_slide2').tinycarousel({ 
	   pager: false, 
	   //interval: true, 
	   display: 4,
	   axis: 'x',
	   callback: function(){
		   
	   }
	});
	

	//randomise the li's so that each page load is different.
	//http://css-tricks.com/snippets/jquery/shuffle-dom-elements/#li-comment-441140
	$.fn.shuffle = function() {

	  var elements = this.get()
	  var copy = [].concat(elements)
	  var shuffled = []
	  var placeholders = []

	  // Shuffle the element array
	  while (copy.length) {
	    var rand = Math.floor(Math.random() * copy.length)
	    var element = copy.splice(rand,1)[0]
	    shuffled.push(element)
	  }

	  // replace all elements with a placeholder
	  for (var i = 0; i < elements.length; i++) {
	    var placeholder = document.createTextNode('')
	    findAndReplace(elements[i], placeholder)
	    placeholders.push(placeholder)
	  }

	  // replace the placeholders with the shuffled elements
	  for (var i = 0; i < elements.length; i++) {
	    findAndReplace(placeholders[i], shuffled[i])
	  }
	  return $(shuffled)
	}

	function findAndReplace(find, replace) {
	  find.parentNode.replaceChild(replace, find)
	}
	
	
    //Global Variable
	var fifthElement = $('.vertical .overview li:nth-child(5n)');
	console.log(fifthElement);
	var positionOfFirstFifthElement = fifthElement.position().top;
	console.log(positionOfFirstFifthElement);
    var liHeight = 103;
	var viewportHeight = 0;
	var thisViewport = '';
	var readmoreHeight = 0;
    var isHorizontal = false;
	
	
	//Hover function for the li and it's containing nodes.
   $('.overview li').hover(function(event){	  

   	thisViewport = $(this).parents('.viewport');
    isAnimating = $(thisViewport).is(':animated');
    if(!isAnimating){
        console.log('NOT ANIMATING');
        viewportHeight = $(thisViewport).height();
    }else {
        console.log('STILL ANIMATING');
    }
	
    liHeight = $(this).height();
   
    //We need to check the elements position relative to it's container
	//So we take it's position and subtract from the container which is static
	//this returns it's poisiton relative to .viewport, not .overview.
  		var isFifthElement = $(this).offset().top - $(".vertical .viewport").offset().top;//$(this).offset().top;		
		var extendViewport = false;
		
		//check if it's the 5th one at the bottom, if so set a checker true
		console.log('5th ' + isFifthElement + 'pos1st5th ' + positionOfFirstFifthElement);
		
		if(isFifthElement == positionOfFirstFifthElement){
			extendViewport = true;
		}	
			
		//transfer jQuery this to variable - not sure why but doesn't work if you just use $(this)
		el = $(this);
		currentTitle = null;
		image = null;
		liContainer = null;
		var target = $(event.target);
		
		if(target.is('img') ){
			console.log('IMAGE');
			currentTitle = target.parent().parent('li').children().find("h3.title");
			image = target;
			liContainer = target.parent().parent('li');
		} else if(target.is('a.thumb')){
			console.log('A THUMB');
			currentTitle = target.parent().parent('li').children().find("h3.title");
			image = target;
			liContainer = target.parent().parent('li');
		} else if (target.is('h3') ){
			console.log('H3');
			currentTitle = target;
			image = event.target.parentNode.parentNode.children[0];
			liContainer = event.target.parentNode.parentNode.parentNode;
		} else if (target.is('div.info_wrap')){
			console.log('DIV INFO WRAP');
			currentTitle = target.parent('li').children().find("h3.title");
			image = event.target.parentNode.children[0];
			liContainer = target.parent('li');
		} else if(target.is('li')){
			console.log('LI');
			currentTitle = target.children().find("h3.title");
			image = event.target.children[0].childNode;
			liContainer = target;
		} else if(target.is('a.read-more')){
			console.log('A READ MORE');
			currentTitle = target.parent().children().find("h3.title");
			image = event.target.parentNode.parentNode.children[0];
			liContainer = target.parent().parent('li');
		} else if(target.is('a.title')){
			console.log('A.TITLE');
			currentTitle = event.target.children[0];
			image = event.target.parentNode.parentNode.children[0].children[0];
			liContainer = event.target.parentNode.parentNode;	
		}
		
		console.log(liContainer);
	
		//for some reason - all but a.title use currentTitle[0], but a.title returns not defined. This makes it work.
		if(typeof currentTitle[0] == 'undefined'){ currentTitle = currentTitle} else{ currentTitle = currentTitle[0]}
	
		//statically set image height - we want to control this here so they are all the same.
		var curScrollHeight = currentTitle.scrollHeight;
		var extraMargin = Math.abs(curScrollHeight - liHeight);
        console.log('SCROLL HEIGHT: ' + curScrollHeight + ' LI HEIGHT: '+ liHeight + ' EXTRA MARGIN: ' + extraMargin);
		readmoreHeight = $(liContainer).find('a.read-more').outerHeight(true)+5;

		isHorizontal = false;
		//if($('#thumb_slide_container.horizontal').length >= 1){
		if($(this).parents('#thumb_slide_container.horizontal').length >= 1){
				console.log('IS HORIZONTAL!!!!!!!');
				isHorizontal = true;
                extraMargin = extraMargin - 10;
		}
		
		el.data('timeout', setTimeout( function () {
		//Set the function to start after 500 miliseconds
			if( currentTitle.offsetHeight < curScrollHeight && curScrollHeight > liHeight){ //
				console.log('1');
                // your element have overflow
                $(liContainer).animate({'marginBottom':extraMargin+40+'px'}, 500);
                $(currentTitle).animate({'height': curScrollHeight+'px'},500);
				
                //Just for the horizontal version
                if(isHorizontal == true){
                    $(thisViewport).animate({'height': liHeight+extraMargin+40+'px'}, 500)
                }
				
                if(liHeight>curScrollHeight){
                    console.log('fired as big image');
                    extraMargin = liHeight - curScrollHeight+readmoreHeight;
                }

				
			}else{
				console.log('3');
				//your element doesn't have overflow
				$(currentTitle).animate({'height': '72px'},500);
			}
			
			/* 
			Every 5th Element 
			- if it's titleScrollHeight is greater than image we need to increase viewport height by X 
			*/
			if(isHorizontal == false){
				if(extendViewport == true && curScrollHeight > liHeight){
					console.log('EXTENDING');
					$(thisViewport).animate({'height': viewportHeight+readmoreHeight+extraMargin+'px'}, 500);
					extendViewport = false;
				}
			}
		}, 300));
		event.stopPropagation();
	},function(event){
		//stop any prior animations - we don't want to keep animating if we have hovered off.
		$(currentTitle).stop();
		$(liContainer).stop();
		//$('.horizontal #thumb_slide .viewport').stop();
		//$('.vertical #thumb_slide .viewport').stop();
		$(thisViewport).stop();
		
		
		clearTimeout(el.data('timeout'));
		//animate back to the current state.
		$(currentTitle).animate({'height':'16px'},500);
		$(liContainer).animate({'marginBottom':'10px'}, 500);
		//$('.horizontal #thumb_slide .viewport').animate({'height': imageHeight+'px'}, 500);
		//$('.vertical #thumb_slide .viewport').animate({'height': viewportHeight+'px'}, 500);
		if(isHorizontal == true){
            $(thisViewport).animate({'height': liHeight+'px'},500);
        }else {
            $(thisViewport).animate({'height': viewportHeight+'px'},500);
        }
   });
	//Call the shuffle function on the list
	$('.viewport .overview li').shuffle();
});