/**
* jquery.froll-0.1.js - Fancy Image Roll
* ==========================================================
* (C) 2011 José Ramón Díaz - [email protected]
*
* http://3nibbles.blogspot.com/2011/07/plugin-jquery-sliding-buttons.html
* http://plugins.jquery.com/project/froll
*
* FRoll is a jQuery plugin to simplify the task of providing a simple and
* efficient way to expand the image information of a picture using a sequence
* of images.
*
* The direct use of this plugin is to provide a preview of a youtube video
* using the Google API. In that case it presents a sucession of three
* different moments of the video in a smooth sucession when mouse enters into
* the image.
*
* Everything is self-contained. No need of extra CSS or complex controls,
* just call the method over the image and you are ready.
*
* INSTANTIATION
* Just call the ".froll()" method over the images selector.
*
* $('.videoCaptionImg').froll( [ options_object ] );
*
* OPTIONS
* - transform $.froll.youtube Array that defines [0] as the regex to apply
* to src and [1] as the resulting string with
* {number} placeholder for the animation images.
* - frames [1, 2, 3], Array with the {number} of each frame of the animation
* - width null, Width of the animation frames. Null = automatic
* - height null, Height of the animation frames. Null = automatic
* - speed 750, Fade animation speed
* - time 1500, Time between frames
* - click function(taget) Click callback function. Defaults to trigger click
* event over the container <a> of the img.
*
* PUBLIC API
* - $.froll.stop() Stops current animation and hides the preview
*
* HELPER CONSTANTS
* $.froll.youtube Transform array that converts origin src stored in youtube
* (http://img.youtube.com/vi/<video_ID>/0.jpg) into youtube previews.
* $.froll.youtubeLocal Transform array that converts local stored captions with name the
* id of the video, into youtube previews.
* $.froll.local Transform array that converts local stored captions into local
* stored previews with the same name but ended with "_<number>"
* in the same directory than caption.
*
* CSS CLASSES
* - Container: #froll-overlay
* - Frames: .froll-frame
*
* Legal stuff
* You are free to use this code, but you must give credit and/or keep header intact.
* Please, tell me if you find it useful. An email will be enough.
* If you enhance this code or correct a bug, please, tell me.
*/
(function( $ ) {
///////////////////////////////////////////////////////////////////////////////
// Private members
///////////////////////////////////////////////////////////////////////////////
var busy = false,
overlay = null,
frames = [],
frame = -1,
lframe = 0,
options = {},
target = null,
src = "",
tickTimer = null,
imgPreloader = new Image(),
//isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
// ========================================================================
// Starts the animation
_start = function() {
_stop(); // Hides current animation (if any)
if( !target.attr('src') ) return; // No image src
// Gets the options and src transform
options = target.data('froll');
src = target.attr('src').replace( options.transform[0], options.transform[1] );
// Moves the overlay to the target position
var pos = _getPos(target);
overlay.css({
'position' : 'absolute',
'left' : pos.left,
'top' : pos.top,
'width' : pos.width,
'height' : pos.height,
'zIndex' : 9999,
'background': 'transparent'
//,'border': '1px solid red'
}).show();
// ========================================================================
// Starts the frames preload chain loading first frame
lframe = 0; // Frame being loaded
if(!imgPreloader) imgPreloader = new Image();
imgPreloader.onerror = function() { _error(); };
imgPreloader.onload = _preloadCompleted;
imgPreloader.src = src.replace( /\{number\}/, ""+options.frames[lframe] );
if(imgPreloader.complete) _preloadCompleted(); // Cached images don't fire onload events
},
// ========================================================================
// Gracefully stops the animation
_stop = function() {
clearInterval(tickTimer); // Disables the timer
imgPreloader.onerror = imgPreloader.onload = null;
if( target && overlay.is( ':visible' ) )
overlay.hide().empty(); // Hides the overlay and deletes the frames
frames = [];
frame = -1;
//target = options = null;
busy = false;
},
// ========================================================================
// Frame image load error
_error = function() {
alert( "Error loading image at " + src );
},
// ========================================================================
// Function called on animation click
_click = function(e) {
if( typeof options.click !== 'undefined' )
options.click(target);
},
// ========================================================================
// Image preload complete event
_preloadCompleted = function() {
// Gets default image dimensions
if( !options.width ) options.width = overlay.width(); //imgPreloader.width;
if( !options.height ) options.height = overlay.height(); //imgPreloader.height;
// Creates frame ima
$("<img />").attr({
'id' : 'froll-frame-' + lframe,
'class': 'froll-frame',
'src' : imgPreloader.src
}).css({
'position' : 'absolute',
'display' : 'block',
'left' : '0px',
'top' : '0px',
'width' : options.width+'px',
'height' : options.height+'px',
'zIndex' : lframe+1,
'opacity' : 0
//,'visibility': 'hidden'
}).appendTo( overlay );
// Shows first frame
if( lframe == 0 )
{
_tick();
tickTimer = setInterval( _tick, options.time );
}
// Preloads next frame
frames[ lframe++ ] = 1; // Marks frame as done
if( lframe < options.frames.length )
{
// Intermediate frame
imgPreloader.src = src.replace( /\{number\}/i, options.frames[lframe] );
if(imgPreloader.complete) _preloadCompleted(); // Cached images don't fire onload events
}
else
imgPreloader.onerror = imgPreloader.onload = null; // Last frame
},
// ========================================================================
// Shows next frame
_tick = function() {
var l = options.frames.length - 1;
var children = overlay.children();
// Animates next frame
if( frame == -1 )
{
// First run
children.eq( 0 ).css('opacity', 0).animate( { 'opacity': 1 }, options.speed );
frame = 0;
}
else if( frame == 0 )
{
// First frame (after a full run)
for(var i = 1; i < l; i++) children.eq( i ).css( 'opacity' , 0); // Hides all but first and last frames
children.eq( 0 ).css( 'opacity', 1 ).show(); // Shows first frame (bellow last frame)
children.eq( l ).animate( { 'opacity': 0 }, options.speed );
}
else if( frame <= l )
{
// Intermediate frame
var next = children.eq( frame );
if(next)
next.css('opacity', 0).animate( { 'opacity': 1 }, options.speed );
}
else
{
// The last frame. Resets animation to show first frame and hide the last one
children.eq( 0 ).css( 'opacity', 1 );
children.eq( l ).animate( { 'opacity': 0 }, options.speed );
}
frame = (frame+1) % (l+1);
},
// ========================================================================
// Helper function to get the exact obj position in the page
_getPos = function(obj) {
var pos = obj.offset();
pos.top += parseInt( obj.css( 'paddingTop' ) , 10 ) || 0;
pos.left += parseInt( obj.css( 'paddingLeft' ) , 10 ) || 0;
pos.top += parseInt( obj.css( 'border-top-width' ) , 10 ) || 0;
pos.left += parseInt( obj.css( 'border-left-width' ), 10 ) || 0;
pos.width = obj.width();
pos.height = obj.height();
return pos;
};
///////////////////////////////////////////////////////////////////////////////
// Public members
///////////////////////////////////////////////////////////////////////////////
// ========================================================================
// Instantiation. Called on every object of the supplied selector
$.fn.froll = function( obj ) {
if (!$(this).length) {
return this;
}
if( $(this).data( 'froll' ) )
{
// Object already initialized. Starts the animation over it simulating a click
if($(this).click) $(this).click();
}
else
{
// Object not initialized. Sets data and binds events
$(this)
.data( 'froll', $.extend( $.fn.froll.defaults, obj ) )
.unbind( 'mouseenter' )
.bind( 'mouseenter', function(e) {
var self = $(this);
e.preventDefault();
if (busy && self !== target) _stop(); // Stops current animation
busy = true;
//var rel = self.attr('rel') || '';
target = self;
_start(); // Starts the animation over target element
return;
});
}
return this;
};
// ========================================================================
// Container class for the public interface
$.froll = function(obj) { };
// ========================================================================
// Inits the components needed for the animation overlay
$.froll.init = function() {
if ( $( '#froll-overlay' ).length ) {
return;
}
// Components
$('body').append(
overlay = $( '<div id="froll-overlay"></div>' )
);
// Animation controls events
overlay.mouseleave( _stop );
overlay.click( _click );
return this;
};
// ========================================================================
// Stops current animation and hides overlay
$.froll.stop = function() { _stop(); };
// ========================================================================
// Sample transformation arrays
$.froll.youtube = [ /.*\/(.*)\/0\.(jpg|gif|png|bmp|jpeg)(.*)?/i, 'http://img.youtube.com/vi/$1/{number}.$2' ]; // Caption image is located in youtube (http://img.youtube.com/vi/<video_ID>/0.jpg)
$.froll.youtubeLocal = [ /.*\/(.*)\.(jpg|gif|png|bmp|jpeg)(.*)?/i , 'http://img.youtube.com/vi/$1/{number}.$2' ]; // Caption image is located elsewhere but caption image name is the youtube video_ID
$.froll.local = [ /(.*)\/(.*)\.(jpg|gif|png|bmp|jpeg)(.*)?/i , '$1/$2_{number}.$3$4' ]; // Caption image is located elsewhere and frames are in format "originalImage_<frame>.jpg" in the same directory
// ========================================================================
// Froll options defaults
$.fn.froll.defaults = {
transform : $.froll.youtube, // Array that defines [0] as the regex to apply to src and [1] as the resulting string with {number} placeholder for the animation images
frames : [1, 2, 3], // Array with the {number} of each frame of the animation
width : null, // Width of the animation frames. Null = automatic frame image width
height : null, // Height of the animation frames. Null = automatic frame image height
speed : 750, // Fade animation speed
time : 1500, // Time between frames
click : function(taget) { $(target).closest('a').click(); } // Click callback function
};
// ========================================================================
// Inits the animation overlay on DOM ready
$(document).ready(function() {
$.froll.init();
});
})( jQuery );
.froll-frame:hover {
cursor: pointer; cursor: hand;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>frollTest</title>
<meta name="description" content="jQuery FRoll plugin" />
<meta name="author" content="jrdiazweb" />
</head>
<body>
<div>
<h1>froll Test</h1>
<img id="demo" src="http://img.youtube.com/vi/vtIjA2d6ct4/0.jpg" width="130"/>
<br/>
<a href="http://www.youtube.com/watch?v=vtIjA2d6ct4">Original video</a>
</div>
<script>
$(document).ready(function() {
$('#demo').froll();
});
</script>
</body>
</html>