| 1 |
|
/** |
| 2 |
|
* jquery.scrollFollow.js |
| 3 |
|
* Copyright (c) 2008 Net Perspective (http://kitchen.net-perspective.com/) |
| 4 |
|
* Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php) |
| 5 |
|
* |
| 6 |
|
* @author R.A. Ray |
| 7 |
|
* |
| 8 |
|
* @projectDescription jQuery plugin for allowing an element to animate down as the user scrolls the page. |
| 9 |
|
* |
| 10 |
|
* @version 0.4.0 |
| 11 |
|
* |
| 12 |
|
* @requires jquery.js (tested with 1.2.6) |
| 13 |
|
* @requires ui.core.js (tested with 1.5.2) |
| 14 |
|
* |
| 15 |
|
* @optional jquery.cookie.js (http://www.stilbuero.de/2006/09/17/cookie-plugin-for-jquery/) |
| 16 |
|
* @optional jquery.easing.js (http://gsgd.co.uk/sandbox/jquery/easing/ - tested with 1.3) |
| 17 |
|
* |
| 18 |
|
* @param speed int - Duration of animation (in milliseconds) |
| 19 |
|
* default: 500 |
| 20 |
|
* @param offset int - Number of pixels box should remain from top of viewport |
| 21 |
|
* default: 0 |
| 22 |
|
* @param easing string - Any one of the easing options from the easing plugin - Requires jQuery Easing Plugin < http://gsgd.co.uk/sandbox/jquery/easing/ > |
| 23 |
|
* default: 'linear' |
| 24 |
|
* @param container string - ID of the containing div |
| 25 |
|
* default: box's immediate parent |
| 26 |
|
* @param killSwitch string - ID of the On/Off toggle element |
| 27 |
|
* default: 'killSwitch' |
| 28 |
|
* @param onText string - killSwitch text to be displayed if sliding is enabled |
| 29 |
|
* default: 'Turn Slide Off' |
| 30 |
|
* @param offText string - killSwitch text to be displayed if sliding is disabled |
| 31 |
|
* default: 'Turn Slide On' |
| 32 |
|
* @param relativeTo string - Scroll animation can be relative to either the 'top' or 'bottom' of the viewport |
| 33 |
|
* default: 'top' |
| 34 |
|
* @param delay int - Time between the end of the scroll and the beginning of the animation in milliseconds |
| 35 |
|
* default: 0 |
| 36 |
|
*/ |
| 37 |
|
|
| 38 |
|
( function( $ ) { |
| 39 |
|
|
| 40 |
|
$.scrollFollow = function ( box, options ) |
| 41 |
|
{ |
| 42 |
|
// Convert box into a jQuery object |
| 43 |
|
box = $( box ); |
| 44 |
|
|
| 45 |
|
// 'box' is the object to be animated |
| 46 |
|
var position = box.css( 'position' ); |
| 47 |
|
|
| 48 |
|
function ani() |
| 49 |
|
{ |
| 50 |
|
// The script runs on every scroll which really means many times during a scroll. |
| 51 |
|
// We don't want multiple slides to queue up. |
| 52 |
|
box.queue( [ ] ); |
| 53 |
|
|
| 54 |
|
// A bunch of values we need to determine where to animate to |
| 55 |
|
var viewportHeight = parseInt( $( window ).height() ); |
| 56 |
|
var pageScroll = parseInt( $( document ).scrollTop() ); |
| 57 |
|
var parentTop = parseInt( box.cont.offset().top ); |
| 58 |
|
var parentHeight = parseInt( box.cont.attr( 'offsetHeight' ) ); |
| 59 |
|
var boxHeight = parseInt( box.attr( 'offsetHeight' ) + ( parseInt( box.css( 'marginTop' ) ) || 0 ) + ( parseInt( box.css( 'marginBottom' ) ) || 0 ) ); |
| 60 |
|
var aniTop; |
| 61 |
|
|
| 62 |
|
// Make sure the user wants the animation to happen |
| 63 |
|
if ( isActive ) |
| 64 |
|
{ |
| 65 |
|
// If the box should animate relative to the top of the window |
| 66 |
|
if ( options.relativeTo == 'top' ) |
| 67 |
|
{ |
| 68 |
|
// Don't animate until the top of the window is close enough to the top of the box |
| 69 |
|
if ( box.initialOffsetTop >= ( pageScroll + options.offset ) ) |
| 70 |
|
{ |
| 71 |
|
aniTop = box.initialTop; |
| 72 |
|
} |
| 73 |
|
else |
| 74 |
|
{ |
| 75 |
|
aniTop = Math.min( ( Math.max( ( -parentTop ), ( pageScroll - box.initialOffsetTop + box.initialTop ) ) + options.offset ), ( parentHeight - boxHeight - box.paddingAdjustment ) ); |
| 76 |
|
} |
| 77 |
|
} |
| 78 |
|
// If the box should animate relative to the bottom of the window |
| 79 |
|
else if ( options.relativeTo == 'bottom' ) |
| 80 |
|
{ |
| 81 |
|
// Don't animate until the bottom of the window is close enough to the bottom of the box |
| 82 |
|
if ( ( box.initialOffsetTop + boxHeight ) >= ( pageScroll + options.offset + viewportHeight ) ) |
| 83 |
|
{ |
| 84 |
|
aniTop = box.initialTop; |
| 85 |
|
} |
| 86 |
|
else |
| 87 |
|
{ |
| 88 |
|
aniTop = Math.min( ( pageScroll + viewportHeight - boxHeight - options.offset ), ( parentHeight - boxHeight ) ); |
| 89 |
|
} |
| 90 |
|
} |
| 91 |
|
|
| 92 |
|
// Checks to see if the relevant scroll was the last one |
| 93 |
|
// "-20" is to account for inaccuracy in the timeout |
| 94 |
|
if ( ( new Date().getTime() - box.lastScroll ) >= ( options.delay - 20 ) ) |
| 95 |
|
{ |
| 96 |
|
box.animate( |
| 97 |
|
{ |
| 98 |
|
top: aniTop |
| 99 |
|
}, options.speed, options.easing |
| 100 |
|
); |
| 101 |
|
} |
| 102 |
|
} |
| 103 |
|
}; |
| 104 |
|
|
| 105 |
|
// For user-initiated stopping of the slide |
| 106 |
|
var isActive = true; |
| 107 |
|
|
| 108 |
|
if ( $.cookie != undefined ) |
| 109 |
|
{ |
| 110 |
|
if( $.cookie( 'scrollFollowSetting' + box.attr( 'id' ) ) == 'false' ) |
| 111 |
|
{ |
| 112 |
|
var isActive = false; |
| 113 |
|
|
| 114 |
|
$( '#' + options.killSwitch ).text( options.offText ) |
| 115 |
|
.toggle( |
| 116 |
|
function () |
| 117 |
|
{ |
| 118 |
|
isActive = true; |
| 119 |
|
|
| 120 |
|
$( this ).text( options.onText ); |
| 121 |
|
|
| 122 |
|
$.cookie( 'scrollFollowSetting' + box.attr( 'id' ), true, { expires: 365, path: '/'} ); |
| 123 |
|
|
| 124 |
|
ani(); |
| 125 |
|
}, |
| 126 |
|
function () |
| 127 |
|
{ |
| 128 |
|
isActive = false; |
| 129 |
|
|
| 130 |
|
$( this ).text( options.offText ); |
| 131 |
|
|
| 132 |
|
box.animate( |
| 133 |
|
{ |
| 134 |
|
top: box.initialTop |
| 135 |
|
}, options.speed, options.easing |
| 136 |
|
); |
| 137 |
|
|
| 138 |
|
$.cookie( 'scrollFollowSetting' + box.attr( 'id' ), false, { expires: 365, path: '/'} ); |
| 139 |
|
} |
| 140 |
|
); |
| 141 |
|
} |
| 142 |
|
else |
| 143 |
|
{ |
| 144 |
|
$( '#' + options.killSwitch ).text( options.onText ) |
| 145 |
|
.toggle( |
| 146 |
|
function () |
| 147 |
|
{ |
| 148 |
|
isActive = false; |
| 149 |
|
|
| 150 |
|
$( this ).text( options.offText ); |
| 151 |
|
|
| 152 |
|
box.animate( |
| 153 |
|
{ |
| 154 |
|
top: box.initialTop |
| 155 |
|
}, 0 |
| 156 |
|
); |
| 157 |
|
|
| 158 |
|
$.cookie( 'scrollFollowSetting' + box.attr( 'id' ), false, { expires: 365, path: '/'} ); |
| 159 |
|
}, |
| 160 |
|
function () |
| 161 |
|
{ |
| 162 |
|
isActive = true; |
| 163 |
|
|
| 164 |
|
$( this ).text( options.onText ); |
| 165 |
|
|
| 166 |
|
$.cookie( 'scrollFollowSetting' + box.attr( 'id' ), true, { expires: 365, path: '/'} ); |
| 167 |
|
|
| 168 |
|
ani(); |
| 169 |
|
} |
| 170 |
|
); |
| 171 |
|
} |
| 172 |
|
} |
| 173 |
|
|
| 174 |
|
// If no parent ID was specified, and the immediate parent does not have an ID |
| 175 |
|
// options.container will be undefined. So we need to figure out the parent element. |
| 176 |
|
if ( options.container == '') |
| 177 |
|
{ |
| 178 |
|
box.cont = box.parent(); |
| 179 |
|
} |
| 180 |
|
else |
| 181 |
|
{ |
| 182 |
|
box.cont = $( '#' + options.container ); |
| 183 |
|
} |
| 184 |
|
|
| 185 |
|
// Finds the default positioning of the box. |
| 186 |
|
box.initialOffsetTop = parseInt( box.offset().top ); |
| 187 |
|
box.initialTop = parseInt( box.css( 'top' ) ) || 0; |
| 188 |
|
|
| 189 |
|
// Hack to fix different treatment of boxes positioned 'absolute' and 'relative' |
| 190 |
|
if ( box.css( 'position' ) == 'relative' ) |
| 191 |
|
{ |
| 192 |
|
box.paddingAdjustment = parseInt( box.cont.css( 'paddingTop' ) ) + parseInt( box.cont.css( 'paddingBottom' ) ); |
| 193 |
|
} |
| 194 |
|
else |
| 195 |
|
{ |
| 196 |
|
box.paddingAdjustment = 0; |
| 197 |
|
} |
| 198 |
|
|
| 199 |
|
// Animate the box when the page is scrolled |
| 200 |
|
$( window ).scroll( function () |
| 201 |
|
{ |
| 202 |
|
// Sets up the delay of the animation |
| 203 |
|
$.fn.scrollFollow.interval = setTimeout( function(){ ani();} , options.delay ); |
| 204 |
|
|
| 205 |
|
// To check against right before setting the animation |
| 206 |
|
box.lastScroll = new Date().getTime(); |
| 207 |
|
} |
| 208 |
|
); |
| 209 |
|
|
| 210 |
|
// Animate the box when the page is resized |
| 211 |
|
$( window ).resize( function () |
| 212 |
|
{ |
| 213 |
|
// Sets up the delay of the animation |
| 214 |
|
$.fn.scrollFollow.interval = setTimeout( function(){ ani();} , options.delay ); |
| 215 |
|
|
| 216 |
|
// To check against right before setting the animation |
| 217 |
|
box.lastScroll = new Date().getTime(); |
| 218 |
|
} |
| 219 |
|
); |
| 220 |
|
|
| 221 |
|
// Run an initial animation on page load |
| 222 |
|
box.lastScroll = 0; |
| 223 |
|
|
| 224 |
|
ani(); |
| 225 |
|
}; |
| 226 |
|
|
| 227 |
|
$.fn.scrollFollow = function ( options ) |
| 228 |
|
{ |
| 229 |
|
options = options || {}; |
| 230 |
|
options.relativeTo = options.relativeTo || 'top'; |
| 231 |
|
options.speed = options.speed || 500; |
| 232 |
|
options.offset = options.offset || 0; |
| 233 |
|
options.easing = options.easing || 'swing'; |
| 234 |
|
options.container = options.container || this.parent().attr( 'id' ); |
| 235 |
|
options.killSwitch = options.killSwitch || 'killSwitch'; |
| 236 |
|
options.onText = options.onText || 'Turn Slide Off'; |
| 237 |
|
options.offText = options.offText || 'Turn Slide On'; |
| 238 |
|
options.delay = options.delay || 0; |
| 239 |
|
|
| 240 |
|
this.each( function() |
| 241 |
|
{ |
| 242 |
|
new $.scrollFollow( this, options ); |
| 243 |
|
} |
| 244 |
|
); |
| 245 |
|
|
| 246 |
|
return this; |
| 247 |
|
}; |
| 248 |
|
})( jQuery ); |
| 249 |
|
|
| 250 |
|
|
| 251 |
|
|