├── README.md ├── bower.json ├── jquery.scrollme.js ├── jquery.scrollme.min.js └── scrollme.jquery.json /README.md: -------------------------------------------------------------------------------- 1 | **This project may be archived in the not too distant future** 2 | 3 | scrollme 4 | ======== 5 | 6 | A jQuery plugin for adding simple scrolling effects to web pages. 7 | 8 | Demo and usage guide: http://scrollme.nckprsn.com. 9 | 10 | Play with it on CodePen: http://codepen.io/nckprsn/pen/IGpmc 11 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrollme", 3 | "description": "A jQuery plugin for adding simple scrolling effects to web pages.", 4 | "version": "1.1.0", 5 | "main": "jquery.scrollme.min.js", 6 | "ignore": 7 | [ 8 | "scrollme.jquery.json" 9 | ], 10 | "keywords": 11 | [ 12 | "animation", 13 | "scrolling" 14 | ], 15 | "authors": 16 | [ 17 | { 18 | "name": "Nick Pearson", 19 | "url": "http://nckprsn.com" 20 | } 21 | ], 22 | "license": 23 | [ 24 | { 25 | "type": "GPLv3", 26 | "url": "http://www.gnu.org/licenses/gpl-3.0.html" 27 | } 28 | ], 29 | "homepage": "http://scrollme.nckprsn.com/", 30 | "repository": { 31 | "type": "git", 32 | "url": "git://github.com/nckprsn/scrollme" 33 | }, 34 | "dependencies": 35 | { 36 | "jquery": ">=1.8" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jquery.scrollme.js: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------------------------------------- 2 | // ScrollMe 3 | // A jQuery plugin for adding simple scrolling effects to web pages 4 | // http://scrollme.nckprsn.com 5 | // ---------------------------------------------------------------------------------------------------- 6 | 7 | var 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 | 125 | // Start animating 126 | 127 | setInterval( _this.update , _this.update_interval ); 128 | 129 | return true; 130 | } 131 | 132 | // ---------------------------------------------------------------------------------------------------- 133 | // Get list and pre-load animated elements 134 | 135 | _this.init_elements = function() 136 | { 137 | // For each reference element 138 | 139 | $( _this.scrollme_selector ).each( function() 140 | { 141 | var element = {}; 142 | 143 | element.element = $( this ); 144 | 145 | var effects = []; 146 | 147 | // For each animated element 148 | 149 | $( this ).find( _this.animateme_selector ).addBack( _this.animateme_selector ).each( function() 150 | { 151 | // Get effect details 152 | 153 | var effect = {}; 154 | 155 | effect.element = $( this ); 156 | 157 | effect.when = effect.element.data( 'when' ); 158 | effect.from = effect.element.data( 'from' ); 159 | effect.to = effect.element.data( 'to' ); 160 | 161 | if( effect.element.is( '[data-crop]' ) ) 162 | { 163 | effect.crop = effect.element.data( 'crop' ); 164 | } 165 | else 166 | { 167 | effect.crop = true; 168 | } 169 | 170 | if( effect.element.is( '[data-easing]' ) ) 171 | { 172 | effect.easing = _this.easing_functions[ effect.element.data( 'easing' ) ] 173 | } 174 | else 175 | { 176 | effect.easing = _this.easing_functions[ 'easeout' ]; 177 | } 178 | 179 | // Get animated properties 180 | 181 | var properties = {}; 182 | 183 | if( effect.element.is( '[data-opacity]' ) ) properties.opacity = effect.element.data( 'opacity' ); 184 | if( effect.element.is( '[data-translatex]' ) ) properties.translatex = effect.element.data( 'translatex' ); 185 | if( effect.element.is( '[data-translatey]' ) ) properties.translatey = effect.element.data( 'translatey' ); 186 | if( effect.element.is( '[data-translatez]' ) ) properties.translatez = effect.element.data( 'translatez' ); 187 | if( effect.element.is( '[data-rotatex]' ) ) properties.rotatex = effect.element.data( 'rotatex' ); 188 | if( effect.element.is( '[data-rotatey]' ) ) properties.rotatey = effect.element.data( 'rotatey' ); 189 | if( effect.element.is( '[data-rotatez]' ) ) properties.rotatez = effect.element.data( 'rotatez' ); 190 | if( effect.element.is( '[data-scale]' ) ) properties.scale = effect.element.data( 'scale' ); 191 | if( effect.element.is( '[data-scalex]' ) ) properties.scalex = effect.element.data( 'scalex' ); 192 | if( effect.element.is( '[data-scaley]' ) ) properties.scaley = effect.element.data( 'scaley' ); 193 | if( effect.element.is( '[data-scalez]' ) ) properties.scalez = effect.element.data( 'scalez' ); 194 | 195 | effect.properties = properties; 196 | 197 | effects.push( effect ); 198 | }); 199 | 200 | element.effects = effects; 201 | 202 | _this.elements.push( element ); 203 | }); 204 | } 205 | 206 | // ---------------------------------------------------------------------------------------------------- 207 | // Update elements 208 | 209 | _this.update = function() 210 | { 211 | window.requestAnimationFrame( function() 212 | { 213 | _this.update_viewport_position(); 214 | 215 | if( _this.viewport_top_previous != _this.viewport_top ) 216 | { 217 | _this.update_elements_in_view(); 218 | _this.animate(); 219 | } 220 | 221 | _this.viewport_top_previous = _this.viewport_top; 222 | }); 223 | } 224 | 225 | // ---------------------------------------------------------------------------------------------------- 226 | // Animate stuff 227 | 228 | _this.animate = function() 229 | { 230 | // For each element in viewport 231 | 232 | var elements_in_view_length = _this.elements_in_view.length; 233 | 234 | for( var i=0 ; i ( _this.body_height - _this.viewport_height ) ) end = _this.body_height - _this.viewport_height; 273 | } 274 | 275 | // Get scroll position of reference selector 276 | 277 | var scroll = ( _this.viewport_top - start ) / ( end - start ); 278 | 279 | // Get relative scroll position for effect 280 | 281 | var from = effect[ 'from' ]; 282 | var to = effect[ 'to' ]; 283 | 284 | var length = to - from; 285 | 286 | var scroll_relative = ( scroll - from ) / length; 287 | 288 | // Apply easing 289 | 290 | var scroll_eased = effect.easing( scroll_relative ); 291 | 292 | // Get new value for each property 293 | 294 | var opacity = _this.animate_value( scroll , scroll_eased , from , to , effect , 'opacity' ); 295 | var translatey = _this.animate_value( scroll , scroll_eased , from , to , effect , 'translatey' ); 296 | var translatex = _this.animate_value( scroll , scroll_eased , from , to , effect , 'translatex' ); 297 | var translatez = _this.animate_value( scroll , scroll_eased , from , to , effect , 'translatez' ); 298 | var rotatex = _this.animate_value( scroll , scroll_eased , from , to , effect , 'rotatex' ); 299 | var rotatey = _this.animate_value( scroll , scroll_eased , from , to , effect , 'rotatey' ); 300 | var rotatez = _this.animate_value( scroll , scroll_eased , from , to , effect , 'rotatez' ); 301 | var scale = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scale' ); 302 | var scalex = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scalex' ); 303 | var scaley = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scaley' ); 304 | var scalez = _this.animate_value( scroll , scroll_eased , from , to , effect , 'scalez' ); 305 | 306 | // Override scale values 307 | 308 | if( 'scale' in effect.properties ) 309 | { 310 | scalex = scale; 311 | scaley = scale; 312 | scalez = scale; 313 | } 314 | 315 | // Update properties 316 | 317 | effect.element.css( 318 | { 319 | 'opacity' : opacity, 320 | 'transform' : 'translate3d( '+translatex+'px , '+translatey+'px , '+translatez+'px ) rotateX( '+rotatex+'deg ) rotateY( '+rotatey+'deg ) rotateZ( '+rotatez+'deg ) scale3d( '+scalex+' , '+scaley+' , '+scalez+' )' 321 | } ); 322 | } 323 | } 324 | } 325 | 326 | // ---------------------------------------------------------------------------------------------------- 327 | // Calculate property values 328 | 329 | _this.animate_value = function( scroll , scroll_eased , from , to , effect , property ) 330 | { 331 | var value_default = _this.property_defaults[ property ]; 332 | 333 | // Return default value if property is not animated 334 | 335 | if( !( property in effect.properties ) ) return value_default; 336 | 337 | var value_target = effect.properties[ property ]; 338 | 339 | var forwards = ( to > from ) ? true : false; 340 | 341 | // Return boundary value if outside effect boundaries 342 | 343 | if( scroll < from && forwards ) { return value_default; } 344 | if( scroll > to && forwards ) { return value_target; } 345 | 346 | if( scroll > from && !forwards ) { return value_default; } 347 | if( scroll < to && !forwards ) { return value_target; } 348 | 349 | // Calculate new property value 350 | 351 | var new_value = value_default + ( scroll_eased * ( value_target - value_default ) ); 352 | 353 | // Round as required 354 | 355 | switch( property ) 356 | { 357 | case 'opacity' : new_value = new_value.toFixed(2); break; 358 | case 'translatex' : new_value = new_value.toFixed(0); break; 359 | case 'translatey' : new_value = new_value.toFixed(0); break; 360 | case 'translatez' : new_value = new_value.toFixed(0); break; 361 | case 'rotatex' : new_value = new_value.toFixed(1); break; 362 | case 'rotatey' : new_value = new_value.toFixed(1); break; 363 | case 'rotatez' : new_value = new_value.toFixed(1); break; 364 | case 'scale' : new_value = new_value.toFixed(3); break; 365 | default : break; 366 | } 367 | 368 | // Done 369 | 370 | return new_value; 371 | } 372 | 373 | // ---------------------------------------------------------------------------------------------------- 374 | // Update viewport position 375 | 376 | _this.update_viewport_position = function() 377 | { 378 | _this.viewport_top = $window.scrollTop(); 379 | _this.viewport_bottom = _this.viewport_top + _this.viewport_height; 380 | } 381 | 382 | // ---------------------------------------------------------------------------------------------------- 383 | // Update list of elements in view 384 | 385 | _this.update_elements_in_view = function() 386 | { 387 | _this.elements_in_view = []; 388 | 389 | var elements_length = _this.elements.length; 390 | 391 | for( var i=0 ; i _this.viewport_top ) ) 394 | { 395 | _this.elements_in_view.push( _this.elements[i] ); 396 | } 397 | } 398 | } 399 | 400 | // ---------------------------------------------------------------------------------------------------- 401 | // Stuff to do on resize 402 | 403 | _this.on_resize = function() 404 | { 405 | // Update viewport/element data 406 | 407 | _this.update_viewport(); 408 | _this.update_element_heights(); 409 | 410 | // Update display 411 | 412 | _this.update_viewport_position(); 413 | _this.update_elements_in_view(); 414 | _this.animate(); 415 | } 416 | 417 | // ---------------------------------------------------------------------------------------------------- 418 | // Update viewport parameters 419 | 420 | _this.update_viewport = function() 421 | { 422 | _this.body_height = $document.height(); 423 | _this.viewport_height = $window.height(); 424 | } 425 | 426 | // ---------------------------------------------------------------------------------------------------- 427 | // Update height of animated elements 428 | 429 | _this.update_element_heights = function() 430 | { 431 | var elements_length = _this.elements.length; 432 | 433 | for( var i=0 ; i(d.body_height-d.viewport_height)){n=d.body_height-d.viewport_height}}var g=(d.viewport_top-r)/(n-r);var x=w.from;var j=w.to;var o=j-x;var k=(g-x)/o;var v=w.easing(k);var l=d.animate_value(g,v,x,j,w,"opacity");var t=d.animate_value(g,v,x,j,w,"translatey");var u=d.animate_value(g,v,x,j,w,"translatex");var s=d.animate_value(g,v,x,j,w,"translatez");var B=d.animate_value(g,v,x,j,w,"rotatex");var z=d.animate_value(g,v,x,j,w,"rotatey");var y=d.animate_value(g,v,x,j,w,"rotatez");var E=d.animate_value(g,v,x,j,w,"scale");var q=d.animate_value(g,v,x,j,w,"scalex");var p=d.animate_value(g,v,x,j,w,"scaley");var m=d.animate_value(g,v,x,j,w,"scalez");if("scale" in w.properties){q=E;p=E;m=E}w.element.css({opacity:l,transform:"translate3d( "+u+"px , "+t+"px , "+s+"px ) rotateX( "+B+"deg ) rotateY( "+z+"deg ) rotateZ( "+y+"deg ) scale3d( "+q+" , "+p+" , "+m+" )"})}}};d.animate_value=function(i,h,j,k,n,m){var g=d.property_defaults[m];if(!(m in n.properties)){return g}var e=n.properties[m];var f=(k>j)?true:false;if(ik&&f){return e}if(i>j&&!f){return g}if(id.viewport_top)){d.elements_in_view.push(d.elements[e])}}};d.on_resize=function(){d.update_viewport();d.update_element_heights();d.update_viewport_position();d.update_elements_in_view();d.animate()};d.update_viewport=function(){d.body_height=c.height();d.viewport_height=b.height()};d.update_element_heights=function(){var g=d.elements.length;for(var f=0;f=1.8" 31 | } 32 | } 33 | --------------------------------------------------------------------------------