PageSourceSearch

https://td-set.ru/js/jquery/jquery.snowflurry.js

js td-set.ru collected 2026-10-08 13:19:20 UTC 14,621 bytes, 418 lines download raw bytes

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