1 /*! 2 * backgroundVideo v0.2.6 3 * https://github.com/linnett/backgroundVideo 4 * Use HTML5 video to create an effect like the CSS property, 'background-size: cover'. Includes parallax option. 5 * 6 * Copyright 2014 Sam Linnett 7 * @license http://www.opensource.org/licenses/mit-license.html MIT License 8 * @license http://www.gnu.org/licenses/gpl.html GPL2 License 9 * 10 */ 11 12;(function ( $, window, document, undefined ) { 13 "use strict"; 14 15 // Create the defaults once 16 var pluginName = "backgroundVideo", 17 defaults = { 18 $videoWrap: $('#video-wrap'), 19 $outerWrap: $(window), 20 $window: $(window), 21 minimumVideoWidth: 400, 22 preventContextMenu: false, 23 parallax: true, 24 parallaxOptions: { 25 effect: 1.5 26 }, 27 pauseVideoOnViewLoss: false 28 }; 29 30 // The actual plugin constructor 31 function Plugin( element, options ) { 32 var me = this; 33 this.element = element; 34 this.options = $.extend( {}, defaults, options ); 35 36 this._defaults = defaults; 37 this._name = pluginName; 38 this.options.$video = $(element); 39 40 this.detectBrowser(); 41 this.shimRequestAnimationFrame(); 42 this.options.has3d = this.detect3d(); 43 44 // Set wrap default styles 45 this.options.$videoWrap.css({ 46 'position': 'relative', 47 'overflow': 'hidden', 48 'z-index': '10' 49 }); 50 // Set object default styles 51 this.options.$video.css({ 52 'position': 'absolute', 53 'z-index': '1' 54 }); 55 56 this.options.$video.on('canplay canplaythrough', readyCallback); 57 // If video is cached, the video will already be ready 58 // so canplay/canplaythrough may not fire. 59 if (this.options.$video[0].readyState > 3) { 60 readyCallback(); 61 } 62 63 function readyCallback() { 64 me.options.originalVideoW = me.options.$video[0].videoWidth; 65 me.options.originalVideoH = me.options.$video[0].videoHeight; 66 if(me.initialised) { 67 return; 68 } 69 me.init(); 70 } 71 } 72 73 Plugin.prototype = { 74 75 init: function() { 76 var me = this; 77 78 this.initialised = true; 79 80 // Pause video when the video goes out of the browser view 81 if(this.options.pauseVideoOnViewLoss) { 82 this.playPauseVideo(); 83 } 84 85 // Prevent context menu on right click for object 86 if(this.options.preventContextMenu) { 87 this.options.$video.on('contextmenu', function() { return false; }); 88 } 89 90 me.update(); 91 }, 92 93 update: function () { 94 var me = this, 95 ticking = false; 96 97 var update = function() { 98 me.positionObject(); 99 ticking = false; 100 }; 101 102 var requestTick = function() { 103 if (!ticking) { 104 window.requestAnimationFrame(update); 105 ticking = true; 106 } 107 }; 108 109 if(this.options.parallax) { 110 this.options.$window.on('scroll.backgroundVideo', requestTick); 111 } 112 113 this.options.$window.on('resize.backgroundVideo', requestTick); 114 requestTick(); 115 }, 116 117 detect3d: function () { 118 var el = document.createElement('p'), t, has3d, 119 transforms = { 120 'WebkitTransform':'-webkit-transform', 121 'OTransform':'-o-transform', 122 'MSTransform':'-ms-transform', 123 'MozTransform':'-moz-transform', 124 'transform':'transform' 125 }; 126 127 document.body.insertBefore(el, document.body.lastChild); 128 129 for(t in transforms){ 130 if( el.style[t] !== undefined ){ 131 el.style[t] = 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)'; 132 has3d = window.getComputedStyle(el).getPropertyValue( transforms[t] ); 133 } 134 } 135 136 el.parentNode.removeChild(el); 137 138 if( has3d !== undefined ){ 139 return has3d !== 'none'; 140 } else { 141 return false;
142 } 143 }, 144 145 detectBrowser: function () { 146 var val = navigator.userAgent.toLowerCase(); 147 148 if( val.indexOf('chrome') > -1 || val.indexOf('safari') > -1 ) { 149 this.options.browser = 'webkit'; 150 this.options.browserPrexix = '-webkit-'; 151 } 152 else if( val.indexOf('firefox') > -1 ) { 153 this.options.browser = 'firefox'; 154 this.options.browserPrexix = '-moz-'; 155 } 156 else if (val.indexOf('MSIE') !== -1 || val.indexOf('Trident/') > 0) { 157 this.options.browser = 'ie'; 158 this.options.browserPrexix = '-ms-'; 159 } 160 else if( val.indexOf('Opera') > -1 ) { 161 this.options.browser = 'opera'; 162 this.options.browserPrexix = '-o-'; 163 } 164 }, 165 166 scaleObject: function() { 167 var me = this, heightScale, widthScale, scaleFactor; 168 169 // Set the video wrap to the outerWrap size (defaulted to window) 170 this.options.$videoWrap.width(this.options.$outerWrap.width()); 171 this.options.$videoWrap.height(this.options.$outerWrap.height()); 172 173 heightScale = this.options.$window.width() / this.options.originalVideoW; 174 widthScale = this.options.$window.height() / this.options.originalVideoH; 175 176 scaleFactor = heightScale > widthScale ? heightScale : widthScale; 177 178 if (scaleFactor * this.options.originalVideoW < this.options.minimumVideoWidth) { 179 scaleFactor = this.options.minimumVideoWidth / this.options.originalVideoW; 180 } 181 182 this.options.$video.width(scaleFactor * this.options.originalVideoW); 183 this.options.$video.height(scaleFactor * this.options.originalVideoH); 184 185 return { 186 // Return x and y axis values for positioning 187 xPos: -(parseInt(this.options.$video.width() - this.options.$window.width()) / 2), 188 yPos: parseInt(this.options.$video.height() - this.options.$window.height()) / 2 189 }; 190 191 }, 192 193 positionObject: function() { 194 var me = this, 195 scrollPos = window.pageYOffset, 196 scaleObject = this.scaleObject(this.options.$video, me.options.$videoWrap), 197 xPos = scaleObject.xPos, 198 yPos = scaleObject.yPos; 199 200 // Check for parallax 201 if(this.options.parallax) { 202 // Prevent parallax when scroll position is negative to the window 203 if(scrollPos >= 0) { 204 yPos = this.calculateYPos(yPos,scrollPos); 205 } else { 206 yPos = this.calculateYPos(yPos, 0); 207 } 208 } else { 209 yPos = -yPos; 210 } 211 212 // Check for 3dtransforms 213 if(me.options.has3d) { 214 this.options.$video.css(me.options.browserPrexix + 'transform', 'translate3d(-'+ xPos +'px, ' + yPos + 'px, 0)'); 215 this.options.$video.css('transform', 'translate3d('+ xPos +'px, ' + yPos + 'px, 0)'); 216 } else { 217 this.options.$video.css(me.options.browserPrexix + 'transform', 'translate(-'+ xPos +'px, ' + yPos + 'px)'); 218 this.options.$video.css('transform', 'translate('+ xPos +'px, ' + yPos + 'px)'); 219 } 220 }, 221 222 calculateYPos: function (yPos, scrollPos) { 223 var videoPosition, videoOffset; 224 225 videoPosition = parseInt(this.options.$videoWrap.offset().top); 226 videoOffset = videoPosition - scrollPos; 227 yPos = -((videoOffset / this.options.parallaxOptions.effect) + yPos); 228 229 return yPos; 230 }, 231 232 disableParallax: function () { 233 this.options.$window.unbind('.backgroundVideoParallax'); 234 }, 235 236 playPauseVideo: function () { 237 var me = this; 238 239 this.options.$window.on('scroll.backgroundVideoPlayPause', function () { 240 // Play/Pause video depending on where the user is in the browser 241 if(me.options.$window.scrollTop() < me.options.$videoWrap.height()) { 242 me.options.$video.get(0).play(); 243 } else { 244 me.options.$video.get(0).pause(); 245 } 246 }); 247 }, 248 249 shimRequestAnimationFrame: function () { 250 /* Paul Irish rAF.js: https://gist.github.com/paulirish/1579671 */ 251 252 var lastTime = 0; 253 var vendors = ['ms', 'moz', 'webkit', 'o']; 254 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 255 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 256 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 257 || window[vendors[x]+'CancelRequestAnimationFrame']; 258 } 259 260 if (!window.requestAnimationFrame) 261 window.requestAnimationFrame = function(callback, element) { 262 var currTime = new Date().getTime(); 263 var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 264 var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 265 timeToCall); 266 lastTime = currTime + timeToCall; 267 return id; 268 }; 269 270 if (!window.cancelAnimationFrame) 271 window.cancelAnimationFrame = function(id) { 272 clearTimeout(id); 273 }; 274 } 275 }; 276 277 // A really lightweight plugin wrapper around the constructor, 278 // preventing against multiple instantiations 279 $.fn[pluginName] = function ( options ) { 280 return this.each(function () { 281 if (!$.data(this, "plugin_" + pluginName)) { 282 $.data(this, "plugin_" + pluginName, 283 new Plugin( this, options )); 284 } 285 }); 286 }; 287 288})( jQuery, window, document );
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.