1/** 2 * A simple jQuery snow plugin. 3 * 4 * Available under GPL licence 5 * 6 * In order to compensate for not having a ratio mechanism built-in you can just add a proportionate number of copies to the elements array, see example. 7 * 8 * @version 2.0 (11/12/17) 9 * @author Vlad-Andrei Erculescu 10 * @requires jQuery 11 * 12 * @params minSize - min size of element (default: 20) 13 * @params maxSize - max size of element (default: 50) 14 * @param fallTimeMultiplier - flake fall time multiplier, the larger the number the longer *all* flakes will take to "land" (default: 20) 15 * @param fallTimeDifference - flake fall time difference, the larger the number the bigger the difference in fall time between flakes (default: 10000) 16 * @oaram direction - numeric value, 0 to 360, describing direction the icons move (270 -> top to bottom, 0 -> right to left) 17 * @params spawnInterval - interval (miliseconds) between new element spawns (default: 500) 18 * @params target - jQuery element to apply snow effect on (should work on any block element) (default: body) 19 * @params elements - elements to use in generating snow effect 20 * 21 * @return interval - returns the interval so that the snow effect can be "paused" 22 * 23 * Example usage in the README file 24 */ 25(function ($) { 26 27 $.fn.snow = function (userSettings) { 28 29 var defaults = { 30 minSize: 20, 31 maxSize: 50, 32 fallTimeMultiplier: 20, 33 fallTimeDifference: 10000, 34 spawnInterval: 500, 35 target: $('#myCarousel'), 36 direction: 270, 37 elements: [ 38 { 39 html: '<i class="fa fa-snowflake-o" aria-hidden="true"></i>', 40 color: '#ffffff' 41 } 42 ] 43 }, 44 settings = $.extend(defaults, userSettings), 45 spawnLineStarts = {}, 46 spawnLineEnds = {}, 47 endLineStarts = {}, 48 endLineEnds = {}, 49 originOffset = {}, 50 $element = $('<div class="flake" />').css({'position': 'absolute', 'top': '-50px'}).html('') 51 ; 52 53 var remapRange = function (val, r1s, r1e, r2s, r2e) { 54 return r2s + (val - r1s) * (r2e - r2s) / (r1e - r1s); 55 }; 56 57 var getPointOnRect = function (angle, w, h) { 58 // Calculate once and store, to make quicker and cleaner
59 var sine = Math.sin(angle), cosine = Math.cos(angle); 60 // Distance to top or bottom edge (from center) 61 var dy = sine > 0 ? h / 2 : h / -2; 62 // Distance to left or right edge (from center) 63 var dx = cosine > 0 ? w / 2 : w / -2; 64 // if: (distance to vertical line) < (distance to horizontal line) 65 if (Math.abs(dx * sine) < Math.abs(dy * cosine)) { 66 // calculate distance to vertical line 67 dy = (dx * sine) / cosine; 68 } 69 // else: (distance to top or bottom edge) < (distance to left or right edge) 70 else { 71 // move to top or bottom line 72 dx = (dy * cosine) / sine; 73 } 74 75 // Return point on rectangle edge 76 return {x: dx, y: dy}; 77 }; 78 79 var getPointOnLine = function (distance, p1, p2) { 80 // Create vector between 2 points 81 var dirV = { 82 x: p2.x - p1.x, 83 y: p2.y - p1.y 84 }; 85 86 // Calculate vector length 87 var dirVLength = Math.sqrt(Math.pow(dirV.x, 2) + Math.pow(dirV.y, 2)); 88 // Normalize vector 89 dirV = { 90 x: dirV.x / dirVLength, 91 y: dirV.y / dirVLength 92 }; 93 94 // Return point at given distance from P1 on P1P2 line 95 return { 96 x: dirV.x * distance + p1.x, 97 y: dirV.y * distance + p1.y 98 }; 99 }; 100 101 var getCircleIntersectionPoints = function (x1, y1, d1, x2, y2, d2) { 102 if(d1 < 0 || d2 < 0) return; 103 var a = d2; 104 var b = d1; 105 var c = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 106 var d = (b*b+c*c-a*a)/(2*c); 107 var h = Math.sqrt(b*b-d*d); 108 109 var x3 = (x2-x1)*d/c + (y2-y1)*h/c + x1; 110 var y3 = (y2-y1)*d/c - (x2-x1)*h/c + y1; 111 var x4 = (x2-x1)*d/c - (y2-y1)*h/c + x1; 112 var y4 = (y2-y1)*d/c + (x2-x1)*h/c + y1; 113 114 return [ 115 {x: x3, y: y3}, 116 {x: x4, y: y4} 117 ]; 118 }; 119 120 var degToRad = function (deg) { 121 return Math.PI / 180 * deg; 122 }; 123 124 var calculateLimitLines = function(width, height) { 125 originOffset = { 126 x: width/2, 127 y: height/2 128 }; 129 130 return calculateSpawnLine(width, height) && calculateEndLine(width, height); 131 }; 132 133 var calculateLimitLine = function(width, height, direction) {
134 // Get point on rect at given angle for given width & height 135 var rectPoint = getPointOnRect(degToRad(direction), width, height); 136 137 // Get line distance from origin of rect 138 var lineDistance = Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height / 2, 2)); 139 140 // Get line center point 141 var lineCenter = getPointOnLine( 142 lineDistance, 143 {x: 0, y: 0}, 144 rectPoint 145 ); 146 147 // Calculate length of line and half it 148 var lineRadius = (Math.max(width, height) - 100) / 2; 149 150 // Calculate distance from rect origin to spawn line end 151 var originToSpawnEndDistance = Math.sqrt(Math.pow(lineDistance, 2) + Math.pow(lineRadius, 2)); 152 return getCircleIntersectionPoints( 153 0, 0, originToSpawnEndDistance, 154 lineCenter.x, lineCenter.y, lineRadius 155 ); 156 }; 157 158 var calculateSpawnLine = function (width, height) { 159 spawnLineEnds = calculateLimitLine(width, height, settings.direction); 160 spawnLineStarts = spawnLineEnds[0]; 161 spawnLineEnds = spawnLineEnds[1]; 162 163 return true; 164 }; 165 166 var calculateEndLine = function (width, height) { 167 endLineEnds = calculateLimitLine(width, height, settings.direction + 180); 168 endLineStarts = endLineEnds[0]; 169 endLineEnds = endLineEnds[1]; 170 171 return true; 172 }; 173 174 return function () { 175 settings.target.css("overflow", "hidden"); 176 var targetHeight = settings.target.outerHeight(true); 177 var targetWidth = settings.target.outerWidth(true); 178 if (calculateLimitLines(targetWidth, targetHeight)) { 179 setInterval(function () { 180 var opacity = 0.5 + Math.random(), 181 zIndex = remapRange(opacity, 0.5, 1, -1000, -900), 182 sizeFlake = settings.minSize + Math.random() * settings.maxSize, 183 fallTime = targetHeight * settings.fallTimeMultiplier + Math.random() * settings.fallTimeDifference, 184 currentElement = settings.elements[Math.floor(Math.random() * settings.elements.length)]; 185 186 var spawnOffsetX = Math.random() * targetWidth; 187 188 var spawnPos = getPointOnLine(spawnOffsetX, spawnLineStarts, spawnLineEnds); 189 spawnPos = { 190 x: spawnPos.x + originOffset.x, 191 y: spawnPos.y + originOffset.y 192 }; 193 194 var endPos = getPointOnLine(targetWidth - spawnOffsetX, endLineStarts, endLineEnds); 195 endPos = { 196 x: endPos.x + originOffset.x, 197 y: endPos.y + originOffset.y 198 }; 199 200 $element 201 .clone() 202 .html(currentElement.html) 203 .appendTo(settings.target) 204 .css({ 205 'left': spawnPos.x, 206 'top': spawnPos.y, 207 'opacity': opacity, 208 'font-size': sizeFlake, 209 'width': sizeFlake, 210 'height': sizeFlake, 211 'color': currentElement.color, 212 'z-index': zIndex 213 }) 214 .animate( 215 { 216 top: endPos.y, 217 left: endPos.x, 218 opacity: 1 219 }, 220 fallTime, 221 'linear', 222 function () { 223 // Change this to handle fall end action 224 $(this).fadeOut('fast', function () { 225 $(this).remove(); 226 }) 227 } 228 ); 229 }, settings.spawnInterval); 230 } else { 231 console.error("Could not calculate spawn line!"); 232 } 233 }() 234 }; 235 236})(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.