1// ---------------------------------------------------------------------------------------------------- 2// ScrollMe 3// A jQuery plugin for adding simple scrolling effects to web pages 4// http://scrollme.nckprsn.com 5// ---------------------------------------------------------------------------------------------------- 6 7var scrollme = ( function( $ ) 8{ 9 // ---------------------------------------------------------------------------------------------------- 10 // ScrollMe object 11 12 var _this = {}; 13 14 // ---------------------------------------------------------------------------------------------------- 15 // Properties 16 17 var $document = $( document ); 18 var $window = $( window ); 19 20 _this.body_height = 0; 21 22 _this.viewport_height = 0; 23 24 _this.viewport_top = 0; 25 _this.viewport_bottom = 0; 26 27 _this.viewport_top_previous = -1; 28 29 _this.elements = []; 30 _this.elements_in_view = []; 31 32 _this.property_defaults = 33 { 34 'opacity' : 1, 35 'translatex' : 0, 36 'translatey' : 0, 37 'translatez' : 0, 38 'rotatex' : 0, 39 'rotatey' : 0, 40 'rotatez' : 0, 41 'scale' : 1, 42 'scalex' : 1, 43 'scaley' : 1, 44 'scalez' : 1 45 }; 46 47 _this.scrollme_selector = '.scrollme'; 48 _this.animateme_selector = '.animateme'; 49 50 _this.update_interval = 10; 51 52 // Easing functions 53 54 _this.easing_functions = 55 { 56 'linear' : function( x ) 57 { 58 return x; 59 }, 60 61 'easeout' : function( x ) 62 { 63 return x * x * x; 64 }, 65 66 'easein' : function( x ) 67 { 68 x = 1 - x; 69 return 1 - ( x * x * x ); 70 }, 71 72 'easeinout' : function( x ) 73 { 74 if( x < 0.5 ) 75 { 76 return ( 4 * x * x * x ); 77 } 78 else 79 { 80 x = 1 - x; 81 return 1 - ( 4 * x * x * x ) ; 82 } 83 } 84 }; 85 86 // Document events to bind initialisation to 87 88 _this.init_events = 89 [ 90 'ready', 91 'page:load', // Turbolinks 92 'page:change' // Turbolinks 93 ]; 94 95 // ---------------------------------------------------------------------------------------------------- 96 // Initialisation conditions 97 98 _this.init_if = function() { return true; } 99 100 // ---------------------------------------------------------------------------------------------------- 101 // Initialisation 102 103 _this.init = function() 104 { 105 // Cancel if initialisation conditions not met 106 107 if( !_this.init_if() ) return false; 108 109 // Load all elements to animate 110 111 _this.init_elements(); 112 113 // Get element & viewport sizes 114 115 _this.on_resize(); 116 117 // Recalculate heights & positions on resize and rotate 118 119 $window.on( 'resize orientationchange' , function(){ _this.on_resize(); } ); 120 121 // Recalculate heights & positions when page is fully loaded + a bit just in case 122 123 // $window.load( function(){ setTimeout( function(){ _this.on_resize(); } , 100 ) }); 124 $(document).ready( function(){ setTimeout( function(){ _this.on_resize(); } , 100 ) }); 125 126 // Start animating 127 128 setInterval( _this.update , _this.update_interval ); 129 130 return true; 131 } 132 133 // ---------------------------------------------------------------------------------------------------- 134 // Get list and pre-load animated elements 135 136 _this.init_elements = function() 137 { 138 // For each reference element 139 140 $( _this.scrollme_selector ).each( function() 141 { 142 var element = {}; 143 144 element.element = $( this ); 145 146 var effects = []; 147 148 // For each animated element 149 150 $( this ).find( _this.animateme_selector ).addBack( _this.animateme_selector ).each( function() 151 { 152 // Get effect details 153 154 var effect = {}; 155 156 effect.element = $( this ); 157 158 effect.when = effect.element.data( 'when' ); 159 effect.from = effect.element.data( 'from' ); 160 effect.to = effect.element.data( 'to' ); 161 162 if( effect.element.is( '[data-crop]' ) ) 163 { 164 effect.crop = effect.element.data( 'crop' ); 165 } 166 else 167 { 168 effect.crop = true; 169 } 170 171 if( effect.element.is( '[data-easing]' ) ) 172 { 173 effect.easing = _this.easing_functions[ effect.element.data( 'easing' ) ] 174 } 175 else 176 { 177 effect.easing = _this.easing_functions[ 'easeout' ]; 178 } 179 180 // Get animated properties 181 182 var properties = {}; 183 184 if( effect.element.is( '[data-opacity]' ) ) properties.opacity = effect.element.data( 'opacity' ); 185 if( effect.element.is( '[data-translatex]' ) ) properties.translatex = effect.element.data( 'translatex' ); 186 if( effect.element.is( '[data-translatey]' ) ) properties.translatey = effect.element.data( 'translatey' ); 187 if( effect.element.is( '[data-translatez]' ) ) properties.translatez = effect.element.data( 'translatez' ); 188 if( effect.element.is( '[data-rotatex]' ) ) properties.rotatex = effect.element.data( 'rotatex' ); 189 if( effect.element.is( '[data-rotatey]' ) ) properties.rotatey = effect.element.data( 'rotatey' ); 190 if( effect.element.is( '[data-rotatez]' ) ) properties.rotatez = effect.element.data( 'rotatez' ); 191 if( effect.element.is( '[data-scale]' ) ) properties.scale = effect.element.data( 'scale' ); 192 if( effect.element.is( '[data-scalex]' ) ) properties.scalex = effect.element.data( 'scalex' ); 193 if( effect.element.is( '[data-scaley]' ) ) properties.scaley = effect.element.data( 'scaley' ); 194 if( effect.element.is( '[data-scalez]' ) ) properties.scalez = effect.element.data( 'scalez' ); 195 196 effect.properties = properties; 197 198 effects.push( effect ); 199 }); 200 201 element.effects = effects; 202 203 _this.elements.push( element ); 204 }); 205 } 206 207 // ---------------------------------------------------------------------------------------------------- 208 // Update elements 209 210 _this.update = function() 211 { 212 window.requestAnimationFrame( function() 213 { 214 _this.update_viewport_position(); 215 216 if( _this.viewport_top_previous != _this.viewport_top ) 217 { 218 _this.update_elements_in_view(); 219 _this.animate(); 220 } 221 222 _this.viewport_top_previous = _this.viewport_top; 223 }); 224 } 225 226 // ---------------------------------------------------------------------------------------------------- 227 // Animate stuff 228 229 _this.animate = function() 230 { 231 // For each element in viewport 232 233 var elements_in_view_length = _this.elements_in_view.length; 234 235 for( var i=0 ; i<elements_in_view_length ; i++ ) 236 { 237 var element = _this.elements_in_view[i]; 238 239 // For each effect 240 241 var effects_length = element.effects.length; 242 243 for( var e=0 ; e<effects_length ; e++ ) 244 { 245 var effect = element.effects[e]; 246 247 // Get effect animation boundaries 248 249 switch( effect.when ) 250 { 251 case 'view' : // Maintained for backwards compatibility 252 case 'span' : 253 var start = element.top - _this.viewport_height; 254 var end = element.bottom; 255 break; 256 257 case 'exit' : 258 var start = element.bottom - _this.viewport_height; 259 var end = element.bottom; 260 break; 261 262 default : 263 var start = element.top - _this.viewport_height; 264 var end = element.top; 265 break; 266 } 267 268 // Crop boundaries 269 270 if( effect.crop ) 271 { 272 if( start < 0 ) start = 0; 273 if( end > ( _this.body_height - _this.viewport_height ) ) end = _this.body_height - _this.viewport_height; 274 } 275 276 // Get scroll position of reference selector 277 278 var scroll = ( _this.viewport_top - start ) / ( end - start ); 279 280 // Get relative scroll position for effect 281 282 var from = effect[ 'from' ]; 283 var to = effect[ 'to' ]; 284 285 var length = to - from; 286 287 var scroll_relative = ( scroll - from ) / length; 288 289 // Apply easing 290 291 var scroll_eased = effect.easing( scroll_relative ); 292 293 // Get new value for each property 294 295 var opacity = _this.animate_value( scroll , scroll_eased , from , to , effect , 'opacity' ); 296 var translatey = _this.animate_value( scroll , scroll_eased , from , to , effect , 'translatey' ); 297 var translatex = _this.animate_value( scroll , scroll_eased , from , to , effect , 'translatex' ); 298 var translatez = _this.animate_value( scroll , scroll_eased , from , to , effect , 'translatez' ); 299 var rotatex = _this.animate_value( scroll , scroll_eased , from , to , effect , 'rotatex' ); 300 var rotatey = _this.animate_value( scroll , scroll_eased , from , to , effect , 'rotatey' ); 301 var rotatez = _this.animate_value( scroll , scroll_eased , from , to , effect , 'rotatez' ); 302 var scale = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scale' ); 303 var scalex = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scalex' ); 304 var scaley = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scaley' ); 305 var scalez = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scalez' ); 306 307 // Override scale values 308 309 if( 'scale' in effect.properties ) 310 { 311 scalex = scale; 312 scaley = scale; 313 scalez = scale; 314 } 315 316 // Update properties 317 318 effect.element.css( 319 { 320 'opacity' : opacity, 321 'transform' : 'translate3d( '+translatex+'px , '+translatey+'px , '+translatez+'px ) rotateX( '+rotatex+'deg ) rotateY( '+rotatey+'deg ) rotateZ( '+rotatez+'deg ) scale3d( '+scalex+' , '+scaley+' , '+scalez+' )' 322 } ); 323 } 324 } 325 } 326 327 // ---------------------------------------------------------------------------------------------------- 328 // Calculate property values 329 330 _this.animate_value = function( scroll , scroll_eased , from , to , effect , property ) 331 { 332 var value_default = _this.property_defaults[ property ]; 333 334 // Return default value if property is not animated 335 336 if( !( property in effect.properties ) ) return value_default; 337 338 var value_target = effect.properties[ property ]; 339 340 var forwards = ( to > from ) ? true : false;
341 342 // Return boundary value if outside effect boundaries 343 344 if( scroll < from && forwards ) { return value_default; } 345 if( scroll > to && forwards ) { return value_target; } 346 347 if( scroll > from && !forwards ) { return value_default; } 348 if( scroll < to && !forwards ) { return value_target; } 349 350 // Calculate new property value 351 352 var new_value = value_default + ( scroll_eased * ( value_target - value_default ) ); 353 354 // Round as required 355 356 switch( property ) 357 { 358 case 'opacity' : new_value = new_value.toFixed(2); break; 359 case 'translatex' : new_value = new_value.toFixed(0); break; 360 case 'translatey' : new_value = new_value.toFixed(0); break; 361 case 'translatez' : new_value = new_value.toFixed(0); break; 362 case 'rotatex' : new_value = new_value.toFixed(1); break; 363 case 'rotatey' : new_value = new_value.toFixed(1); break; 364 case 'rotatez' : new_value = new_value.toFixed(1); break; 365 case 'scale' : new_value = new_value.toFixed(3); break; 366 default : break; 367 } 368 369 // Done 370 371 return new_value; 372 } 373 374 // ---------------------------------------------------------------------------------------------------- 375 // Update viewport position 376 377 _this.update_viewport_position = function() 378 { 379 _this.viewport_top = $window.scrollTop(); 380 _this.viewport_bottom = _this.viewport_top + _this.viewport_height; 381 } 382 383 // ---------------------------------------------------------------------------------------------------- 384 // Update list of elements in view 385 386 _this.update_elements_in_view = function() 387 { 388 _this.elements_in_view = []; 389 390 var elements_length = _this.elements.length; 391 392 for( var i=0 ; i<elements_length ; i++ ) 393 { 394 if ( ( _this.elements[i].top < _this.viewport_bottom ) && ( _this.elements[i].bottom > _this.viewport_top ) ) 395 { 396 _this.elements_in_view.push( _this.elements[i] ); 397 } 398 } 399 } 400 401 // ---------------------------------------------------------------------------------------------------- 402 // Stuff to do on resize 403 404 _this.on_resize = function() 405 { 406 // Update viewport/element data 407 408 _this.update_viewport(); 409 _this.update_element_heights(); 410 411 // Update display 412 413 _this.update_viewport_position(); 414 _this.update_elements_in_view(); 415 _this.animate(); 416 } 417 418 // ---------------------------------------------------------------------------------------------------- 419 // Update viewport parameters 420 421 _this.update_viewport = function() 422 { 423 _this.body_height = $document.height(); 424 _this.viewport_height = $window.height(); 425 } 426 427 // ---------------------------------------------------------------------------------------------------- 428 // Update height of animated elements 429 430 _this.update_element_heights = function() 431 { 432 var elements_length = _this.elements.length; 433 434 for( var i=0 ; i<elements_length ; i++ ) 435 { 436 var element_height = _this.elements[i].element.outerHeight(); 437 var position = _this.elements[i].element.offset(); 438 439 _this.elements[i].height = element_height; 440 _this.elements[i].top = position.top; 441 _this.elements[i].bottom = position.top + element_height; 442 } 443 } 444 445 // ---------------------------------------------------------------------------------------------------- 446 // Bind initialisation 447 448 // $document.on( _this.init_events.join( ' ' ) , function(){ _this.init(); } ); 449 $('docuemnt').ready(function(){ _this.init(); }); 450 451 // ---------------------------------------------------------------------------------------------------- 452 453 return _this; 454 455 // ---------------------------------------------------------------------------------------------------- 456 457})( jQuery );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.