/* 08/24/2010
PikaChoose
Jquery plugin for photo galleries
Copyright (C) 2010 Jeremy Fry
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
(function($) {
/**
* Creates a slideshow for all matched elements.
*
* @example $("#pikame").PikaChoose();
* @input needed
- Caption
- Caption
*
* @method PikaChoose
* @return $
* @param o {Hash|String} A set of key/value pairs to set as configuration properties or a method name to call on a formerly created instance.
*/
var defaults = {
autoPlay: true,
speed:800,
text: { play: "", stop: "", previous: "Previous", next: "Next" },
transition:[0],
showCaption: true,
IESafe: true
};
$.fn.PikaChoose = function(o) {
return this.each(function() {
$(this).data('pikachoose', new $pc(this, o));
});
}
/**
* The PikaChoose object.
*
* @constructor
* @class pikachoose
* @param e {HTMLElement} The element to create the carousel for.
* @param o {Object} A set of key/value pairs to set as configuration properties.
* @cat Plugins/PikaChoose
*/
$.PikaChoose = function(e, o) {
this.options = $.extend({}, defaults, o || {});
this.list = null;
this.image = null;
this.anchor = null;
this.caption = null;
this.imgNav = null;
this.imgPlay = null;
this.imgPrev = null;
this.imgNext = null;
this.textNext = null;
this.textPrev = null;
this.previous = null;
this.next = null;
this.aniDiv = null;
this.thumbs = null;
this.transition= null;
this.active = null;
this.animating = false;
if (e.nodeName == 'UL' || e.nodeName == 'OL') {
this.list = $(e);
this.build();
this.bindEvents();
}else{
return;
}
var y = 0;
var x = 0;
for(var t = 0; t<25;t++)
{
var a = '';
this.aniDiv.append(a);
y++
if(y == 6)
{
x++;
y=0;
}
}
}//end PikaChoose function(e, o)
var $pc = $.PikaChoose;
$pc.fn = $pc.prototype = {
pikachoose: '4.0.3'
};
$pc.fn.extend = $pc.extend = $.extend;
$pc.fn.extend({
/**
* Builds the gallery structure.
*
* @method build
* @return undefined
*/
build: function() {
this.step = 0; //transition step count
//create the structure for pikachoose
this.wrap = $("").insertBefore(this.list);
this.image = $("").appendTo(this.wrap);
this.anchor = this.image.wrap("").parent();
this.imgNav = $("").insertAfter(this.anchor);
this.imgPlay = $("").appendTo(this.imgNav);
if(this.options.autoPlay){ this.imgPlay.addClass('pause'); }else{ this.imgPlay.addClass('play'); }
this.imgPrev = $("").insertAfter(this.imgPlay);
this.imgNext = $("").insertAfter(this.imgPrev);
this.caption = $("").insertAfter(this.imgNav);
if(!this.options.showCaption){ this.caption.hide(); }
this.aniDiv = $("").insertAfter(this.caption);
this.textNav = $("").insertAfter(this.aniDiv);
this.textPrev = $(""+this.options.text.previous+"").appendTo(this.textNav);
this.textNext = $(""+this.options.text.next+"").appendTo(this.textNav);
this.list.addClass('pika-thumbs');
this.list.children('li').wrapInner("");
this.thumbs = this.list.find('img');
this.active = this.thumbs.eq(0);
//fill in info for first image
this.finishAnimating({'source':this.active.attr('ref') || this.active.attr('src'),'caption':this.active.parents('li:first').find('span:first').html(), 'clickThrough':this.active.parent().attr('href') || ""});
//process all the thumbnails
this.thumbs.each(this.createThumb);
}, //end setup
/**
* proccesses thumbnails
*
* @method createThumb
* @return undefined
*/
createThumb: function() {
var self = $(this);
$(this).hide();
//store all the data with the image
$.data(this,'clickThrough',$(this).parent('a').attr('href') || "#");
if($(this).parent('a').length > 0){ $(this).unwrap(); }
$.data(this,'caption',$(this).next('span').html() || "");
$(this).next('span').remove();
$.data(this,'source',$(this).attr('ref') || $(this).attr('src'));
$.data(this,'order',$("ul li").index($(this).parents('li')));
//pass data so it can enter the load scope
var data = $.data(this);
$('').bind('load',{data:data},function(){
//in this scope self refers to the image
var img = $(this);
var w = img.width();
var h = img.height();
if(w===0){w = img.attr("width");}
if(h===0){h = img.attr("height");}
//grab a ratio for image to user defined settings
var rw = parseInt(self.parents('.clip').css('width').slice(0,-2))/w;
var rh = parseInt(self.parents('.clip').css('height').slice(0,-2))/h;
//determine which has the smallest ratio (thus needing
//to be the side we use to scale so our whole thumb is filled)
var ratio;
if(rw').bind('load', {self:self,data:data}, function()
{
//in this scope self referes to the PikaChoose object
self.aniDiv.css({height:self.image.height(),width:self.image.width()}).fadeIn('fast');
self.aniDiv.children('div').css({'width':'20%','height':'20%','float':'left'});
//decide our transition
var n = 0;
if(self.options.transition[0] == -1)
{ //random
n = Math.floor(Math.random()*6);
}else{
n = self.options.transition[self.step];
self.step++;
if(self.step >= self.options.transition.length){self.step=0;}
}
if(self.options.IESafe && $.browser.msie){ n = 0; }
self.doAnimation(n,data);
}).attr('src',$.data(this).source);//end image preload
},//end bindEvents
doAnimation: function(n,data)
{
var self = this; //self in this scope refers to PikaChoose object. Needed for callbacks on animations
var aWidth = self.aniDiv.children('div').eq(0).width();
var aHeight = self.aniDiv.children('div').eq(0).height();
self.aniDiv.children().each(function()
{
//position myself absolutely
var div = $(this);
var xOffset = Math.floor(div.parent().width()/5)*div.attr('col');
var yOffset = Math.floor(div.parent().height()/5)*div.attr('row');
div.css({
'background':'url('+data.source+') -'+xOffset+'px -'+yOffset+'px',
'width':'0px',
'height':'0px',
'position':'absolute',
'top':yOffset+'px',
'left':xOffset+'px',
'float':'none'
});
});//end ani_divs.children.each
switch(n)
{
case 0:
//full frame fade
self.aniDiv.height(self.image.height()).hide().css({'background':'url('+data.source+') top left no-repeat'});
self.aniDiv.children('div').hide();
self.aniDiv.fadeIn('slow',function(){
self.finishAnimating(data);
self.aniDiv.css({'background':'transparent'});
});
break;
case 1:
self.aniDiv.children().hide().each(function(index)
{
//animate out as blocks
var delay = index*30;
$(this).css({opacity: 0.1}).delay(delay).animate({opacity: 1,"width":aWidth,"height":aHeight},200,'linear',function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 2:
self.aniDiv.children().hide().each(function(index)
{
var delay = $(this).attr('row')*30;
$(this).css({opacity:0.1,"width":aWidth}).delay(delay).animate({opacity:1,"height":aHeight},500,'linear',function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 3:
self.aniDiv.children().hide().each(function(index)
{
var delay = $(this).attr('col')*10;
aHeight = self.gapper($(this), aHeight);
$(this).css({opacity:0.1,"height":aHeight}).delay(delay).animate({opacity:1,"width":aWidth},800,'linear',function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 4:
self.aniDiv.children().show().each(function(index)
{
var delay = index*Math.floor(Math.random()*6)*10;
aHeight = self.gapper($(this), aHeight);
if($(".animation div").index(this) == 24)
{
delay = 800;
}
$(this).css({"height":aHeight,"width":aWidth,"opacity":.01}).delay(delay).animate({"opacity":1},800,function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 5:
//full frame slide
self.aniDiv.height(self.image.height()).hide().css({'background':'url('+data.source+') top left no-repeat'});
self.aniDiv.children('div').hide();
self.aniDiv.css({width:0}).animate({width:self.image.width()},'slow',function(){
self.finishAnimating(data);
self.aniDiv.css({'background':'transparent'});
});
break;
case 6:
//fade out then in
self.aniDiv.hide();
self.image.fadeOut('slow',function(){
self.image.attr('src',data.source).fadeIn('slow',function()
{
self.finishAnimating(data);
});
});
break;
}
},//end doAnimation
finishAnimating: function(data)
{
this.animating = false;
this.image.attr('src',data.source);
this.aniDiv.hide();
this.anchor.attr('href',data.clickThrough);
if(this.options.showCaption)
{
this.caption.html(data.caption).fadeIn('slow');
}
if(this.options.autoPlay == true)
{
var self = this;
this.image.delay(this.options.speed).fadeIn(0,function(){ if(self.options.autoPlay){ self.nextClick(); } });
}
},//end finishedAnimating
gapper: function(ele, aHeight)
{
if(ele.attr('row') == 9 && ele.attr('col') == 0)
{
//last row, check the gap and fix it!
var gap = ani_divs.height()-(aHeight*9);
return gap;
}
return aHeight;
},
nextClick : function(e)
{
var how = "natural";
try{
var self = e.data.self;
}catch(err)
{
var self = this;
how = "auto";
}
var next = self.active.parents('li:first').next().find('img');
if(next.length == 0){next = self.list.find('img').eq(0);};
next.trigger('click',{how:how});
},
prevClick : function(e)
{
var self = e.data.self;
var prev = self.active.parents('li:first').prev().find('img');
if(prev.length == 0){prev = self.list.find('img:last');};
prev.trigger('click');
},
playClick: function(e)
{
var self = e.data.self;
self.options.autoPlay = !self.options.autoPlay;
self.imgPlay.toggleClass('play').toggleClass('pause');
if(self.options.autoPlay){ self.nextClick(); }
}
}); //end extend
})(jQuery);