1 2;(function($, undefined) { 3 4 /** 5 * requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel 6 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 7 * http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating 8 * 9 * @link https://gist.github.com/lenville/9e13e63af075c145d662 10 */ 11 (function() { 12 var lastTime = 0; 13 var vendors = ['ms', 'moz', 'webkit', 'o']; 14 for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 15 window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 16 window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; 17 } 18 19 if (!window.requestAnimationFrame) { 20 window.requestAnimationFrame = function(callback, element) { 21 var currTime = new Date().getTime(); 22 var timeToCall = Math.max(0, 16 - Math.abs(currTime - lastTime)); 23 var id = window.setTimeout(function() { 24 callback(currTime + timeToCall); 25 }, timeToCall); 26 lastTime = currTime + timeToCall; 27 return id; 28 }; 29 } 30 31 if (!window.cancelAnimationFrame) { 32 window.cancelAnimationFrame = function(id) { 33 clearTimeout(id); 34 }; 35 } 36 }()); 37 38 // Change this to your plugin name. 39 var pluginName = 'flurry'; 40 41 /** 42 * Behaves the same as setInterval except uses requestAnimationFrame() where possible for better performance 43 * 44 * http://www.joelambert.co.uk 45 * Copyright 2011, Joe Lambert. 46 * Free to use under the MIT license. 47 * 48 * @link https://gist.github.com/joelambert/1002116 49 * @param {function} fn The callback function 50 * @param {int} delay The delay in milliseconds 51 */ 52 function requestInterval(fn, delay) { 53 54 /* jshint -W010 */ 55 var start = new Date().getTime(), 56 handle = new Object(); 57 58 function loop() { 59 var current = new Date().getTime(), 60 delta = current - start; 61 62 if(delta >= delay) { 63 fn.call(); 64 start = new Date().getTime(); 65 } 66 67 handle.value = window.requestAnimationFrame(loop); 68 } 69 70 handle.value = window.requestAnimationFrame(loop); 71 return handle; 72 } 73 74 /** 75 * Behaves the same as clearInterval except uses cancelRequestAnimationFrame() where possible for better performance 76 * 77 * http://www.joelambert.co.uk 78 * Copyright 2011, Joe Lambert. 79 * Free to use under the MIT license. 80 * 81 * @link https://gist.github.com/joelambert/1002116 82 * @param {int|object} fn The callback function 83 */ 84 function clearRequestInterval(handle) { 85 86 /* jshint -W030 */ 87 window.cancelAnimationFrame ? window.cancelAnimationFrame(handle.value) : 88 window.webkitCancelAnimationFrame ? window.webkitCancelAnimationFrame(handle.value) : 89 window.webkitCancelRequestAnimationFrame ? window.webkitCancelRequestAnimationFrame(handle.value) : /* Support for legacy API */ 90 window.mozCancelRequestAnimationFrame ? window.mozCancelRequestAnimationFrame(handle.value) : 91 window.oCancelRequestAnimationFrame ? window.oCancelRequestAnimationFrame(handle.value) : 92 window.msCancelRequestAnimationFrame ? window.msCancelRequestAnimationFrame(handle.value) : 93 clearInterval(handle); 94 } 95 96 /** 97 * Detects whether the browser supports CSS transitions (adapted from https://gist.github.com/jonraasch/373874) 98 * 99 * @return {boolean} True if CSS transitions are supported 100 */ 101 function supportsTransitions() { 102 var thisBody = document.body || document.documentElement, 103 thisStyle = thisBody.style, 104 support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined; 105 return support; 106 } 107 108 /** 109 * Generate a random integer within a range provided 110 * 111 * @param {number} min The lowest number of the range 112 * @param {number} max The highest number of the range 113 * @return {number} The random integer within the range 114 */ 115 function randomNumberInRange(min, max) { 116 return Math.floor(Math.random() * (max - min + 1) + min); 117 } 118 119 /** 120 * Creates a snowflake with randomized movement based on the options provided 121 * 122 * @param {object} options The options set for the plugin 123 * @param {object} $container The jQuery element to append each snowflake to. 124 */ 125 function createFlake(options, $container, containerWidth) { 126 127 // Set the character. If multiple characters are provided, randomly select one. 128 var character = options.character.length === 1 ? options.character : options.character.charAt(Math.round(randomNumberInRange(0, options.character.length - 1))); 129 130 // Set the flake's starting position to a random number between the container width, including additional space for the wind setting 131 var startX = randomNumberInRange(-Math.abs(options.wind), containerWidth + Math.abs(options.wind)); 132 133 // Set the flake's ending X translation to a random number based on the wind and windVariance options 134 var endX = startX + randomNumberInRange(options.wind - options.windVariance, options.wind + options.windVariance); 135 136 // Set the flake's font size to a random number between the small and large options 137 var fontSize = randomNumberInRange(options.small, options.large); 138 139 // Set the flake's speed to a random number based on the speed setting and the randomized fontSize 140 var speed = options.speed / ((randomNumberInRange(fontSize * 1.2, fontSize * 0.8) - options.small) / (options.large - options.small) + 0.5); 141 142 // Set the flake's ending Y translation based on the height setting and the randomized fontSize 143 var endY = options.height - fontSize; 144 145 // Set the flake's rotation to a random degree based on the rotation and rotationVariance options 146 var endRotation = randomNumberInRange(options.wind - options.windVariance, options.wind + options.windVariance); 147 148 // Create object to store final CSS properties for the flake 149 var endCSS = {
150 "transform": "translateX(" + endX + "px) translateY(" + endY + "px) rotate(" + endRotation + "deg)", 151 "opacity": 0 152 }; 153 154 // Create the flake, set the CSS for it, and animate it 155 var $flake = $('<span></span>'); 156 $flake.html(character).css({ 157 "color": options.blur && fontSize < (options.large + options.small) / 2 ? "transparent" : options.color, 158 "text-shadow": options.blur && fontSize < (options.large + options.small) / 2 ? "0 0 1px rgba(255,255,255,1)" : "none", 159 "display": "inline-block", 160 "line-height": 1, 161 "margin": 0, 162 "padding": "2px", 163 "pointer-events": "none", 164 "font-size": fontSize + "px", 165 "opacity": options.startTransparency, 166 "position": "absolute", 167 "top": "-" + (options.large * 1.2) + "px", 168 "transform": "translateX(" + startX + "px) translateY(0px)", 169 "transition": "transform " + (speed / 1000) + "s linear, opacity " + (speed / 1000) + "s " + options.opacityEasing, 170 "z-index": options.zIndex, 171 }).appendTo($container); 172 173 if (supportsTransitions) { 174 175 // Remove the flake element when it finishes transitioning 176 $flake.on('transitionend.flurry', function(event) { 177 $(event.target).remove(); 178 }); 179 180 // Set the endCSS to trigger the transition 181 window.requestAnimationFrame(function(){ 182 $flake.css(endCSS); 183 }); 184 } else { 185 186 // Use jQuery .animate() 187 $flake.animate(endCSS, speed, 'linear', function() { 188 $(this).remove(); 189 }); 190 } 191 } 192 193 /** 194 * Plugin object constructor. 195 * Implements the Revealing Module Pattern. 196 */ 197 function Plugin(element, options) { 198 199 // References to this plugin instance, DOM and jQuery versions of element. 200 var self = this; 201 var el = element; 202 var $el = $(element); 203 204 // Extend default options with those supplied by user. 205 options = $.extend({ 206 height: $el.height() > 200 ? 200 : $el.height(), // default to 200px or the height of the element, whichever is smaller 207 useRelative: $el.is('body') ? false : true, // default to false for the body element and true for all other elements 208 }, $.fn[pluginName].defaults, options); 209 210 // Ensure options that should be numbers are numbers 211 $.each(options, function(key, val) { 212 if (parseInt(val)) { 213 options[key] = parseInt(val); 214 } 215 }); 216 217 /** 218 * Initialize plugin. 219 */ 220 function init() { 221 222 // Add any initialization logic here... 223 224 // Set element position to relative if currently static 225 if (options.useRelative === true && $el.css('position') === 'static') { 226 $$el.css({ 227 'position': 'relative' 228 }); 229 } 230 231 // Create container element to hold snowflakes 232 var $container = $(document.createElement('div')).addClass('flurry-container').css({ 233 'margin': 0, 234 'padding': 0, 235 'position': 'absolute', 236 'top': 0, 237 'right': 0, 238 'left': 0, 239 'height': options.height, 240 'overflow': options.overflow, 241 'pointer-events': 'none' 242 }).prependTo($el); 243 244 // On window resize, recalculate the width used to generate flakes within 245 var containerWidth = $container.width(); 246 $(window).resize(function() { 247 containerWidth = $container.width(); 248 }); 249 250 // Generate flakes at the interval set by the frequency setting 251 self.flakeInterval = requestInterval(function() { 252 createFlake(options, $container, containerWidth); 253 }, options.frequency); 254 255 // Call onInit hook 256 hook('onInit'); 257 } 258 259 /** 260 * Get/set a plugin option. 261 * Get usage: $('#el').demoplugin('option', 'key'); 262 * Set usage: $('#el').demoplugin('option', 'key', value); 263 */ 264 function option (key, val) { 265 if (val) { 266 options[key] = parseInt(val) || val; 267 } else { 268 return options[key]; 269 } 270 } 271 272 /** 273 * Destroy plugin. 274 * Usage: $('#el').demoplugin('destroy'); 275 */ 276 function destroy() { 277 278 // Iterate over each matching element. 279 $el.each(function() { 280 var el = this; 281 var $el = $(this); 282 283 // Add code to restore the element to its original state... 284 285 // Cancel snowflake generation 286 clearRequestInterval(self.flakeInterval); 287
288 // Remove container 289 $el.find('.flurry-container').remove(); 290 291 // Call onDestroy hook 292 hook('onDestroy'); 293 294 // Remove Plugin instance from the element. 295 $el.removeData('plugin_' + pluginName); 296 }); 297 } 298 299 /** 300 * Callback hooks. 301 * Usage: In the defaults object specify a callback function: 302 * hookName: function() {} 303 * Then somewhere in the plugin trigger the callback: 304 * hook('hookName'); 305 */ 306 function hook(hookName) { 307 if (options[hookName] !== undefined) { 308 309 // Call the user defined function. 310 // Scope is set to the jQuery element we are operating on. 311 options[hookName].call(el); 312 } 313 } 314 315 // Initialize the plugin instance. 316 init(); 317 318 // Expose methods of Plugin we wish to be public. 319 return { 320 option: option, 321 destroy: destroy 322 }; 323 } 324 325 /** 326 * Plugin definition. 327 */ 328 $.fn[pluginName] = function(options) { 329 330 // If the first parameter is a string, treat this as a call to a public method. 331 if (typeof arguments[0] === 'string') { 332 var methodName = arguments[0]; 333 var args = Array.prototype.slice.call(arguments, 1); 334 var returnVal; 335 this.each(function() { 336 337 // Check that the element has a plugin instance, and that the requested public method exists. 338 if ($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') { 339 340 // Call the method of the Plugin instance, and Pass it the supplied arguments. 341 returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args); 342 } else { 343 throw new Error('Method ' + methodName + ' does not exist on jQuery.' + pluginName); 344 } 345 }); 346 if (returnVal !== undefined){ 347 348 // If the method returned a value, return the value. 349 return returnVal; 350 } else { 351 352 // Otherwise, returning 'this' preserves chainability. 353 return this; 354 } 355 356 // If the first parameter is an object (options), or was omitted, instantiate a new instance of the plugin. 357 } else if (typeof options === "object" || !options) { 358 return this.each(function() { 359 360 // Only allow the plugin to be instantiated once. 361 if (!$.data(this, 'plugin_' + pluginName)) { 362 363 // Pass options to Plugin constructor, and store Plugin instance in the elements jQuery data object. 364 $.data(this, 'plugin_' + pluginName, new Plugin(this, options)); 365 } 366 }); 367 } 368 }; 369 370 $.fn[pluginName].defaults = { 371 onInit: function() {}, 372 onDestroy: function() {}, 373 /* height: 200, */ 374 /* useRelative: false, */ 375 character: "â", 376 color: "white", 377 frequency: 100, 378 speed: 12000, 379 small: 8, 380 large: 23, 381 wind: 40, 382 windVariance: 20, 383 height: 750, 384 rotation: 90, 385 rotationVariance: 180, 386 startOpacity: 1, 387 endOpacity: 0, 388 opacityEasing: "cubic-bezier(1,.3,.6,.74)", 389 blur: true, 390 overflow: "hidden", 391 zIndex: 9999 392 }; 393 394})(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.