1/* 2 scrollorama - The jQuery plugin for doing cool scrolly stuff 3 by John Polacek (@johnpolacek) 4 5 Dual licensed under MIT and GPL. 6*/ 7 8 9(function($) { 10 $.scrollorama = function(options) { 11 var scrollorama = {}, 12 blocks = [], 13 browserPrefix = '', 14 ieVersion = '', 15 onBlockChange = function() {}, 16 latestKnownScrollY = 0, 17 ticking = false, 18 requestAnimFrame = window.requestAnimationFrame || 19 window.webkitRequestAnimationFrame || 20 window.mozRequestAnimationFrame || 21 window.oRequestAnimationFrame || 22 window.msRequestAnimationFrame || 23 function( callback ){ 24 window.setTimeout(callback, 1000 / 60); 25 }, 26 defaults = {offset:0, enablePin: true}; 27 28 scrollorama.settings = $.extend({}, defaults, options); 29 scrollorama.blockIndex = 0; 30 31 if (options.blocks === undefined) { alert('ERROR: Must assign blocks class selector to scrollorama plugin'); } 32 33 // PRIVATE FUNCTIONS 34 function init() { 35 var i, block, didScroll, marginTop = false; 36 if (typeof scrollorama.settings.blocks === 'string') { scrollorama.settings.blocks = $(scrollorama.settings.blocks); } 37 38 // set browser prefix (using getBrowser based on jQueryâs $.browser) 39 var browser = getBrowser(); 40 if (browser.mozilla) { browserPrefix = '-moz-'; } 41 if (browser.webkit) { browserPrefix = '-webkit-'; } 42 if (browser.opera) { browserPrefix = '-o-'; } 43 if (browser.msie) { 44 browserPrefix = '-ms-'; 45 ieVersion = parseInt(browser.version, 10); 46 } 47 48 // create blocks array to contain animation props 49 $('body').css('position','relative'); 50 for (i=0; i<scrollorama.settings.blocks.length; i++) { 51 block = scrollorama.settings.blocks.eq(i); 52 marginTop = block.css('margin-top'); 53 blocks.push({ 54 block: block, 55 top: block.offset().top - (!Boolean(marginTop) ? parseInt(marginTop, 10) : 0), 56 pin: 0, 57 animations:[] 58 }); 59 } 60 61 // convert block elements to absolute position 62 if (scrollorama.settings.enablePin.toString() === 'true') { 63 for (i=0; i<blocks.length; i++) { 64 blocks[i].block 65 .css('position', 'absolute') 66 .css('top', blocks[i].top); 67 } 68 } 69 70 // create scroll-wrap div only once 71 if ($("#scroll-wrap").length === 0) { 72 $('body').prepend('<div id="scroll-wrap"></div>'); 73 } 74 75 latestKnownScrollY = 0; 76 ticking = false; 77 $(window).on( 'scroll.scrollorama', onScroll ); 78 } 79 80 function onScroll() { 81 latestKnownScrollY = window.scrollY; 82 requestTick(); 83 } 84 85 function requestTick() { 86 if(!ticking) { 87 requestAnimFrame(function(){ 88 onScrollorama(); 89 update(); 90 }); 91 } 92 ticking = true; 93 } 94 95 function update() { 96 // reset the tick so we can 97 // capture the next onScroll 98 ticking = false; 99 } 100 101 function onScrollorama() { 102 var scrollTop = $(window).scrollTop(), 103 currBlockIndex = getCurrBlockIndex(scrollTop), 104 i, j, anim, startAnimPos, endAnimPos, animPercent, animVal; 105 106 // update all animations 107 for (i=0; i<blocks.length; i++) { 108 109 // go through the animations for each block 110 if (blocks[i].animations.length) { 111 for (j=0; j<blocks[i].animations.length; j++) { 112 anim = blocks[i].animations[j]; 113 114 // if above current block, settings should be at start value 115 if (i > currBlockIndex) { 116 if (currBlockIndex !== i-1 && anim.baseline !== 'bottom') { 117 setProperty(anim, anim.startVal); 118 } 119 if (blocks[i].pin) { 120 blocks[i].block 121 .css('position', 'absolute') 122 .css('top', blocks[i].top); 123 } 124 } 125 126 // if below current block, settings should be at end value 127 // unless on an element that gets animated when it hits the bottom of the viewport 128 else if (i < currBlockIndex) { 129 setProperty(anim, anim.endVal); 130 if (blocks[i].pin) { 131 blocks[i].block 132 .css('position', 'absolute') 133 .css('top', (blocks[i].top + blocks[i].pin)); 134 } 135 } 136 137 // otherwise, set values per scroll position 138 if (i === currBlockIndex || (currBlockIndex === i-1 && anim.baseline === 'bottom')) { 139 // if block gets pinned, set position fixed 140 if (blocks[i].pin && currBlockIndex === i) { 141 blocks[i].block 142 .css('position', 'fixed') 143 .css('top', 0); 144 } 145 146 // set start and end animation positions 147 startAnimPos = blocks[i].top + anim.delay; 148 if (anim.baseline === 'bottom') { startAnimPos -= $(window).height(); } 149 endAnimPos = startAnimPos + anim.duration; 150 151 // if scroll is before start of animation, set to start value 152 if (scrollTop < startAnimPos) { 153 setProperty(anim, anim.startVal); 154 } 155 156 // if scroll is after end of animation, set to end value 157 else if (scrollTop > endAnimPos) { 158 setProperty(anim, anim.endVal); 159 if (blocks[i].pin) { 160 blocks[i].block 161 .css('position', 'absolute') 162 .css('top', (blocks[i].top + blocks[i].pin)); 163 } 164 } 165 166 // otherwise, set value based on scroll 167 else { 168 // calculate percent to animate 169 animPercent = (scrollTop - startAnimPos) / anim.duration; 170 // account for easing if there is any 171 if ( anim.easing && $.isFunction( $.easing[anim.easing] ) ) { 172 animPercent = $.easing[anim.easing]( animPercent, animPercent*1000, 0, 1, 1000 ); 173 } 174 // then multiply the percent by the value range and calculate the new value 175 animVal = anim.startVal + (animPercent * (anim.endVal - anim.startVal)); 176 setProperty(anim, animVal); 177 } 178 } 179 } 180 } 181 } 182 183 // update blockIndex and trigger event if changed 184 if (scrollorama.blockIndex !== currBlockIndex) { 185 scrollorama.blockIndex = currBlockIndex; 186 onBlockChange(); 187 } 188 } 189 190 function getCurrBlockIndex(scrollTop) { 191 var currBlockIndex = 0, i; 192 for (i=0; i<blocks.length; i++) { 193 // check if block is in view 194 if (blocks[i].top <= scrollTop - scrollorama.settings.offset) { currBlockIndex = i; } 195 } 196 return currBlockIndex; 197 } 198 199 function setProperty(anim, val) { 200 var target = anim.element; 201 var prop = anim.property; 202 var scaleCSS, currentPosition; 203 if (prop === 'rotate' || prop === 'zoom' || prop === 'scale') { 204 if (prop === 'rotate') { 205 target.css(browserPrefix+'transform', 'rotate('+val+'deg)'); 206 } else if (prop === 'zoom' || prop === 'scale') { 207 scaleCSS = 'scale('+val+')'; 208 if (browserPrefix !== '-ms-') { 209 target.css(browserPrefix+'transform', scaleCSS); 210 } else { 211 if (jQuery().scale) $(target.selector).scale(val); 212 target.css('zoom', val); 213 } 214 } 215 } 216 else if(prop === 'background-position-x' || prop === 'background-position-y' ) { 217 currentPosition = target.css('background-position').split(' '); 218 if(prop === 'background-position-x') { 219 target.css('background-position',val+'px '+currentPosition[1]); 220 } 221 if(prop === 'background-position-y') { 222 target.css('background-position', currentPosition[0]+' '+val+'px'); 223 } 224 } 225 else if(prop === 'text-shadow' ) { 226 target.css(prop,'0px 0px '+val+'px #ffffff'); 227 } else { 228 if (anim.suffix) { 229 target.css(prop, val + anim.suffix); 230 } else { 231 target.css(prop, val); 232 } 233 } 234 } 235 236 237 // PUBLIC FUNCTIONS 238 scrollorama.animate = function(target) { 239 var targetIndex, 240 targetBlock, 241 anim, 242 offset, 243 suffix, 244 i, j; 245 /* 246 target = animation target 247 arguments = array of animation parameters 248 anim = object that contains all animation params (created from arguments) 249 offset = positioning helper for pinning 250 251 animation parameters: 252 delay = amount of scrolling (in pixels) before animation starts 253 duration = amount of scrolling (in pixels) over which the animation occurs 254 property = css property being animated 255 start = start value of the property 256 end = end value of the property 257 pin = pin block during animation duration (applies to all animations within block) 258 baseline = top (default, when block reaches top of viewport) or bottom (when block first comies into view) 259 easing = just like jquery's easing functions 260 */ 261 262 // if string, convert to DOM object 263 if (typeof target === 'string') { target = $(target); } 264 265 // find block of target 266 for (i=0; i<blocks.length; i++) { 267 if (blocks[i].block.has(target).length) { 268 targetBlock = blocks[i]; 269 targetIndex = i; 270 } 271 } 272 273 // add each animation to the blocks animations array from function arguments 274 for (i=1; i<arguments.length; i++) { 275 276 anim = arguments[i]; 277 278 // for top/left/right/bottom, set relative positioning if static 279 if (anim.property === 'top' || anim.property === 'left' || anim.property === 'bottom' || anim.property === 'right' ) { 280 if (target.css('position') === 'static') { target.css('position','relative'); } 281 // set anim.start, anim.end defaults 282 cssValue = parseInt(target.css(anim.property),10); 283 if (anim.start === undefined) { 284 anim.start = isNaN(cssValue) ? 0 : cssValue; 285 } else if (anim.end === undefined) { 286 anim.end = isNaN(cssValue) ? 0 : cssValue; 287 } 288 } 289 290 // set anim.start/anim.end defaults for rotate, zoom/scale, letter-spacing 291 if (anim.property === 'rotate') { 292 if (anim.start === undefined) { anim.start = 0; } 293 if (anim.end === undefined) { anim.end = 0; } 294 } else if (anim.property === 'zoom' || anim.property === 'scale' ) { 295 if (anim.start === undefined) { anim.start = 1; } 296 if (anim.end === undefined) { anim.end = 1; } 297 } else if (anim.property === 'letter-spacing' && target.css(anim.property)) { 298 if (anim.start === undefined) { anim.start = 1; } 299 if (anim.end === undefined) { anim.end = 1; } 300 } 301 302 // convert background-position property for use on IE8 and lower 303 if (ieVersion && ieVersion < 9 && (anim.property == 'background-position-x' || anim.property == 'background-position-y')) { 304 if (anim.property === 'background-position-x') { 305 anim.property = 'backgroundPositionX'; 306 } 307 else { 308 anim.property = 'backgroundPositionY'; 309 } 310 } 311 312 if (anim.baseline === undefined) { 313 if (anim.pin || targetBlock.pin || targetIndex === 0) { 314 anim.baseline = 'top'; 315 } else { 316 anim.baseline = 'bottom'; 317 } 318 } 319 320 if (anim.delay === undefined) { anim.delay = 0; } 321 322 startVal = anim.start !== undefined ? typeof(anim.start) == 'function' ? anim.start() : anim.start : parseInt(target.css(anim.property),10); // if undefined, use current css value 323 endVal = anim.end !== undefined ? typeof(anim.end) == 'function' ? anim.end() : anim.end : parseInt(target.css(anim.property),10); // if undefined, use current css value 324 suffix = startVal.toString().match(/\D+$/) || endVal.toString().match(/\D+$/); 325 if (suffix) { 326 suffix = suffix[0]; 327 startVal = parseInt(startVal,10); // remove the unit so calculations work correctly 328 endVal = parseInt(endVal,10); 329 } 330 331 targetBlock.animations.push({ 332 element: target, 333 delay: anim.delay, 334 duration: anim.duration, 335 property: anim.property, 336 startVal: startVal, 337 endVal: endVal, 338 suffix: suffix,
339 baseline: anim.baseline !== undefined ? anim.baseline : 'bottom', 340 easing: anim.easing 341 }); 342 343 if (anim.pin) { 344 if (targetBlock.pin < anim.duration + anim.delay) { 345 offset = anim.duration + anim.delay - targetBlock.pin; 346 targetBlock.pin += offset; 347 348 // adjust positions of blocks below target block 349 for (j=targetIndex+1; j<blocks.length; j++) { 350 blocks[j].top += offset; 351 blocks[j].block.css('top', blocks[j].top); 352 } 353 } 354 } 355 } 356 357 onScrollorama(); 358 359 return scrollorama; 360 }; 361 362 // function for passing blockChange event callback 363 scrollorama.onBlockChange = function(f) { 364 onBlockChange = f; 365 }; 366 367 // function for getting an array of scrollpoints 368 // (top of each animation block and animation element scroll start point) 369 scrollorama.getScrollpoints = function() { 370 var scrollpoints = [],i,j,anim; 371 for (i=0; i<blocks.length; i++) { 372 scrollpoints.push(blocks[i].top); 373 // go through the animations for each block 374 if (blocks[i].animations.length && blocks[i].pin > 0) { 375 for (j=0; j<blocks[i].animations.length; j++) { 376 anim = blocks[i].animations[j]; 377 scrollpoints.push(blocks[i].top + anim.delay + anim.duration); 378 } 379 } 380 } 381 // make sure scrollpoints are in numeric order 382 scrollpoints.sort(function(a,b) {return a - b;}); 383 return scrollpoints; 384 }; 385 386 // Remove scrollorama 387 scrollorama.destroy = function () { 388 // Remove animations 389 for (i=0; i<blocks.length; i++) { 390 // Remove CSS rules 391 blocks[i].block.css({ 392 top: '', 393 position: '' 394 }); 395 396 // Remove scrolloroma-specific attributes 397 delete blocks[i].animations; 398 delete blocks[i].top; 399 delete blocks[i].pin; 400 } 401 402 // Unbind the window scroll event 403 $(window).off('scroll.scrollorama'); 404 $('#scroll-wrap').remove(); 405 406 // Remove the scrolloroma object 407 delete scrollorama; 408 }; 409 410 init(); 411 412 return scrollorama; 413 }; 414 415 // Easing functions from jQuery UI 416 $.extend($.easing, { 417 def: 'easeOutQuad', 418 swing: function (x, t, b, c, d) { 419 //alert($.easing.default); 420 return $.easing[$.easing.def](x, t, b, c, d); 421 }, 422 easeInQuad: function (x, t, b, c, d) { 423 return c*(t/=d)*t + b; 424 }, 425 easeOutQuad: function (x, t, b, c, d) { 426 return -c *(t/=d)*(t-2) + b; 427 }, 428 easeInOutQuad: function (x, t, b, c, d) { 429 if ((t/=d/2) < 1) { return c/2*t*t + b; } 430 return -c/2 * ((--t)*(t-2) - 1) + b; 431 }, 432 easeInCubic: function (x, t, b, c, d) { 433 return c*(t/=d)*t*t + b; 434 }, 435 easeOutCubic: function (x, t, b, c, d) { 436 return c*((t=t/d-1)*t*t + 1) + b; 437 }, 438 easeInOutCubic: function (x, t, b, c, d) { 439 if ((t/=d/2) < 1) { return c/2*t*t*t + b; } 440 return c/2*((t-=2)*t*t + 2) + b; 441 }, 442 easeInQuart: function (x, t, b, c, d) { 443 return c*(t/=d)*t*t*t + b; 444 }, 445 easeOutQuart: function (x, t, b, c, d) { 446 return -c * ((t=t/d-1)*t*t*t - 1) + b; 447 }, 448 easeInOutQuart: function (x, t, b, c, d) { 449 if ((t/=d/2) < 1) { return c/2*t*t*t*t + b; } 450 return -c/2 * ((t-=2)*t*t*t - 2) + b; 451 }, 452 easeInQuint: function (x, t, b, c, d) { 453 return c*(t/=d)*t*t*t*t + b; 454 }, 455 easeOutQuint: function (x, t, b, c, d) { 456 return c*((t=t/d-1)*t*t*t*t + 1) + b; 457 }, 458 easeInOutQuint: function (x, t, b, c, d) { 459 if ((t/=d/2) < 1) { return c/2*t*t*t*t*t + b; } 460 return c/2*((t-=2)*t*t*t*t + 2) + b; 461 }, 462 easeInSine: function (x, t, b, c, d) { 463 return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 464 }, 465 easeOutSine: function (x, t, b, c, d) { 466 return c * Math.sin(t/d * (Math.PI/2)) + b; 467 }, 468 easeInOutSine: function (x, t, b, c, d) { 469 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 470 }, 471 easeInExpo: function (x, t, b, c, d) { 472 return (t===0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 473 }, 474 easeOutExpo: function (x, t, b, c, d) { 475 return (t===d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 476 }, 477 easeInOutExpo: function (x, t, b, c, d) { 478 if (t===0) { return b; } 479 if (t===d) { return b+c; } 480 if ((t/=d/2) < 1) { return c/2 * Math.pow(2, 10 * (t - 1)) + b; } 481 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 482 }, 483 easeInCirc: function (x, t, b, c, d) { 484 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 485 }, 486 easeOutCirc: function (x, t, b, c, d) { 487 return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 488 }, 489 easeInOutCirc: function (x, t, b, c, d) {
490 if ((t/=d/2) < 1) { return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; } 491 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 492 }, 493 easeInElastic: function (x, t, b, c, d) { 494 var s=1.70158,p=0,a=c; 495 if (t===0) { return b; } 496 if ((t/=d)===1) { return b+c; } 497 if (!p) { p=d*0.3; } 498 if (a < Math.abs(c)) { a=c; s=p/4; } 499 else{ s = p/(2*Math.PI) * Math.asin (c/a); } 500 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 501 }, 502 easeOutElastic: function (x, t, b, c, d) { 503 var s=1.70158,p=0,a=c; 504 if (t===0) { return b; } 505 if ((t/=d)===1) { return b+c; } 506 if (!p) { p=d*0.3; } 507 if (a < Math.abs(c)) { a=c; s=p/4; } 508 else { s = p/(2*Math.PI) * Math.asin (c/a); } 509 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 510 }, 511 easeInOutElastic: function (x, t, b, c, d) { 512 var s=1.70158,p=0,a=c; 513 if (t===0) { return b; } 514 if ((t/=d/2)===2) { return b+c; } 515 if (!p) { p=d*(0.3*1.5); } 516 if (a < Math.abs(c)) { a=c; s=p/4; } 517 else { s = p/(2*Math.PI) * Math.asin (c/a); } 518 if (t < 1) { return -0.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; } 519 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b; 520 }, 521 easeInBack: function (x, t, b, c, d, s) { 522 if (s === undefined) { s = 1.70158; } 523 return c*(t/=d)*t*((s+1)*t - s) + b; 524 }, 525 easeOutBack: function (x, t, b, c, d, s) { 526 if (s === undefined) { s = 1.70158; } 527 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 528 }, 529 easeInOutBack: function (x, t, b, c, d, s) { 530 if (s === undefined) { s = 1.70158; } 531 if ((t/=d/2) < 1) { return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; } 532 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 533 }, 534 easeInBounce: function (x, t, b, c, d) { 535 return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b; 536 }, 537 easeOutBounce: function (x, t, b, c, d) { 538 if ((t/=d) < (1/2.75)) { 539 return c*(7.5625*t*t) + b; 540 } else if (t < (2/2.75)) { 541 return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b; 542 } else if (t < (2.5/2.75)) { 543 return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b; 544 } else { 545 return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b; 546 } 547 }, 548 easeInOutBounce: function (x, t, b, c, d) { 549 if (t < d/2) { return $.easing.easeInBounce (x, t*2, 0, c, d) * 0.5 + b; } 550 return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * 0.5 + c*0.5 + b; 551 } 552 }); 553 554})(jQuery); 555 556/*! 557 * Modified from: jQuery Migrate - v1.1.0 - 2013-01-31 558 * https://github.com/jquery/jquery-migrate 559 * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT 560 */ 561function getBrowser() { 562 var matched = uaMatch( navigator.userAgent ); 563 var browser = {}; 564 if ( matched.browser ) { 565 browser[ matched.browser ] = true; 566 browser.version = matched.version; 567 } 568 // Chrome is Webkit, but Webkit is also Safari. 569 if ( browser.chrome ) { 570 browser.webkit = true; 571 } else if ( browser.webkit ) { 572 browser.safari = true; 573 } 574 return browser; 575} 576 577function uaMatch(ua) { 578 ua = ua.toLowerCase(); 579 580 var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || 581 /(webkit)[ \/]([\w.]+)/.exec( ua ) || 582 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || 583 /(msie) ([\w.]+)/.exec( ua ) || 584 ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || 585 []; 586 587 return { 588 browser: match[ 1 ] || "", 589 version: match[ 2 ] || "0" 590 }; 591}
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.