PageRenderTime 38ms CodeModel.GetById 2ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/src/snowfall.jquery.js

http://jsnowfall.googlecode.com/
JavaScript | 300 lines | 177 code | 36 blank | 87 comment | 40 complexity | 683457f2f7772df44aa2dfe1785fe5f5 MD5 | raw file
  1/*  Snowfall jquery plugin
  2
  3====================================================================
  4LICENSE
  5====================================================================
  6Licensed under the Apache License, Version 2.0 (the "License");
  7you may not use this file except in compliance with the License.
  8You may obtain a copy of the License at
  9
 10   http://www.apache.org/licenses/LICENSE-2.0
 11
 12   Unless required by applicable law or agreed to in writing, software
 13   distributed under the License is distributed on an "AS IS" BASIS,
 14   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15   See the License for the specific language governing permissions and
 16   limitations under the License.
 17
 18
 19	Version 1.5 Oct 5th 2011
 20	Added collecting snow! Uses the canvas element to collect snow. In order to initialize snow collection use the following
 21	
 22	$(document).snowfall({collection : 'element'});
 23
 24    element = any valid jquery selector.
 25
 26	The plugin then creates a canvas above every element that matches the selector, and collects the snow. If there are a varrying amount of elements the 
 27	flakes get assigned a random one on start they will collide.
 28
 29	Version 1.4 Dec 8th 2010
 30	Fixed issues (I hope) with scroll bars flickering due to snow going over the edge of the screen. 
 31	Added round snowflakes via css, will not work for any version of IE. - Thanks to Luke Barker of http://www.infinite-eye.com/
 32	Added shadows as an option via css again will not work with IE. The idea behind shadows, is to show flakes on lighter colored web sites - Thanks Yutt
 33 
 34	Version 1.3.1 Nov 25th 2010
 35	Updated script that caused flakes not to show at all if plugin was initialized with no options, also added the fixes that Han Bongers suggested 
 36	
 37	Developed by Jason Brown for any bugs or questions email me at loktar69@hotmail
 38	info on the plugin is located on Somethinghitme.com
 39	
 40	values for snow options are
 41	
 42	flakeCount,
 43	flakeColor,
 44	flakeIndex,
 45	minSize,
 46	maxSize,
 47	minSpeed,
 48	maxSpeed,
 49	round, 		true or false, makes the snowflakes rounded if the browser supports it.
 50	shadow		true or false, gives the snowflakes a shadow if the browser supports it.
 51	
 52	Example Usage :
 53	$(document).snowfall({flakeCount : 100, maxSpeed : 10});
 54	
 55	-or-
 56	
 57	$('#element').snowfall({flakeCount : 800, maxSpeed : 5, maxSize : 5});
 58	
 59	-or with defaults-
 60	
 61	$(document).snowfall();
 62	
 63	- To clear -
 64	$('#element').snowfall('clear');
 65*/
 66
 67(function($){
 68	$.snowfall = function(element, options){
 69		var	defaults = {
 70				flakeCount : 35,
 71				flakeColor : '#ffffff',
 72				flakeIndex: 999999,
 73				minSize : 1,
 74				maxSize : 2,
 75				minSpeed : 1,
 76				maxSpeed : 5,
 77				round : false,
 78				shadow : false,
 79				collection : false,
 80				collectionHeight : 40
 81			},
 82			options = $.extend(defaults, options),
 83			random = function random(min, max){
 84				return Math.round(min + Math.random()*(max-min)); 
 85			};
 86
 87			$(element).data("snowfall", this);			
 88
 89			// Snow flake object
 90			function Flake(_x, _y, _size, _speed, _id)
 91			{
 92				// Flake properties
 93				this.id = _id; 
 94				this.x  = _x;
 95				this.y  = _y;
 96				this.size = _size;
 97				this.speed = _speed;
 98				this.step = 0;
 99				this.stepSize = random(1,10) / 100;
100
101				if(options.collection){
102					this.target = canvasCollection[random(0,canvasCollection.length-1)];
103				}
104
105				var flakeMarkup = $(document.createElement("div")).attr({'class': 'snowfall-flakes', 'id' : 'flake-' + this.id}).css({'width' : this.size, 'height' : this.size, 'background' : options.flakeColor, 'position' : 'absolute', 'top' : this.y, 'left' : this.x, 'fontSize' : 0, 'zIndex' : options.flakeIndex});
106
107				if($(element).get(0).tagName === $(document).get(0).tagName){
108					$('body').append(flakeMarkup);
109					element = $('body');
110				}else{
111					$(element).append(flakeMarkup);
112				}
113
114				this.element = document.getElementById('flake-' + this.id);
115
116				// Update function, used to update the snow flakes, and checks current snowflake against bounds
117				this.update = function(){
118					this.y += this.speed;
119
120					if(this.y > (elHeight) - (this.size  + 6)){
121						this.reset();
122					}
123
124					this.element.style.top = this.y + 'px';
125					this.element.style.left = this.x + 'px';
126
127					this.step += this.stepSize;
128					this.x += Math.cos(this.step);
129
130					// Pileup check
131					if(options.collection){
132						if(this.x > this.target.x && this.x < this.target.width + this.target.x && this.y > this.target.y && this.y < this.target.height + this.target.y){
133							var ctx = this.target.element.getContext("2d"),
134								curX = this.x - this.target.x,
135								curY = this.y - this.target.y,
136								colData = this.target.colData;
137
138								if(colData[parseInt(curX)][parseInt(curY+this.speed+this.size)] !== undefined || curY+this.speed+this.size > this.target.height){
139									if(curY+this.speed+this.size > this.target.height){
140										while(curY+this.speed+this.size > this.target.height && this.speed > 0){
141											this.speed *= .5;
142										}
143
144										ctx.fillStyle = "#fff";
145
146										if(colData[parseInt(curX)][parseInt(curY+this.speed+this.size)] == undefined){
147											colData[parseInt(curX)][parseInt(curY+this.speed+this.size)] = 1;
148											ctx.fillRect(curX, (curY)+this.speed+this.size, this.size, this.size);
149										}else{
150											colData[parseInt(curX)][parseInt(curY+this.speed)] = 1;
151											ctx.fillRect(curX, curY+this.speed, this.size, this.size);
152										}
153										this.reset();
154									}else{
155										// flow to the sides
156										this.speed = 1;
157										this.stepSize = 0;
158
159										if(parseInt(curX)+1 < this.target.width && colData[parseInt(curX)+1][parseInt(curY)+1] == undefined ){
160											// go left
161											this.x++;
162										}else if(parseInt(curX)-1 > 0 && colData[parseInt(curX)-1][parseInt(curY)+1] == undefined ){
163											// go right
164											this.x--;
165										}else{
166											//stop
167											ctx.fillStyle = "#fff";
168											ctx.fillRect(curX, curY, this.size, this.size);
169											colData[parseInt(curX)][parseInt(curY)] = 1;
170											this.reset();
171										}
172									}
173								}
174						}
175					}
176
177					if(this.x > (elWidth) - widthOffset || this.x < widthOffset){
178						this.reset();
179					}
180				}
181
182				// Resets the snowflake once it reaches one of the bounds set
183				this.reset = function(){
184					this.y = 0;
185					this.x = random(widthOffset, elWidth - widthOffset);
186					this.stepSize = random(1,10) / 100;
187					this.size = random((options.minSize * 100), (options.maxSize * 100)) / 100;
188					this.speed = random(options.minSpeed, options.maxSpeed);
189				}
190			}
191
192			// Private vars
193			var flakes = [],
194				flakeId = 0,
195				i = 0,
196				elHeight = $(element).height(),
197				elWidth = $(element).width(),
198				widthOffset = 0,
199				snowTimeout = 0;
200
201			// Collection Piece ******************************
202			if(options.collection !== false){
203				var testElem = document.createElement('canvas');
204				if(!!(testElem.getContext && testElem.getContext('2d'))){
205					var canvasCollection = [],
206						elements = $(options.collection),
207						collectionHeight = options.collectionHeight;
208
209					for(var i =0; i < elements.length; i++){
210							var bounds = elements[i].getBoundingClientRect(),
211								canvas = document.createElement('canvas'),
212								collisionData = [];
213
214							if(bounds.top-collectionHeight > 0){									
215								document.body.appendChild(canvas);
216								canvas.style.position = 'absolute';
217								canvas.height = collectionHeight;
218								canvas.width = bounds.width;
219								canvas.style.left = bounds.left;
220								canvas.style.top = bounds.top-collectionHeight;
221
222								for(var w = 0; w < bounds.width; w++){
223									collisionData[w] = [];
224								}
225
226								canvasCollection.push({element :canvas, x : bounds.left, y : bounds.top-collectionHeight, width : bounds.width, height: collectionHeight, colData : collisionData});
227							}
228					}
229				}else{
230					// Canvas element isnt supported
231					options.collection = false;
232				}
233			}
234			// ************************************************
235
236			// This will reduce the horizontal scroll bar from displaying, when the effect is applied to the whole page
237			if($(element).get(0).tagName === $(document).get(0).tagName){
238				widthOffset = 25;
239			}
240
241			// Bind the window resize event so we can get the innerHeight again
242			$(window).bind("resize", function(){  
243				elHeight = $(element).height();
244				elWidth = $(element).width();
245			}); 
246
247
248			// initialize the flakes
249			for(i = 0; i < options.flakeCount; i+=1){
250				flakeId = flakes.length;
251				flakes.push(new Flake(random(widthOffset,elWidth - widthOffset), random(0, elHeight), random((options.minSize * 100), (options.maxSize * 100)) / 100, random(options.minSpeed, options.maxSpeed), flakeId));
252			}
253
254			// This adds the style to make the snowflakes round via border radius property 
255			if(options.round){
256				$('.snowfall-flakes').css({'-moz-border-radius' : options.maxSize, '-webkit-border-radius' : options.maxSize, 'border-radius' : options.maxSize});
257			}
258
259			// This adds shadows just below the snowflake so they pop a bit on lighter colored web pages
260			if(options.shadow){
261				$('.snowfall-flakes').css({'-moz-box-shadow' : '1px 1px 1px #555', '-webkit-box-shadow' : '1px 1px 1px #555', 'box-shadow' : '1px 1px 1px #555'});
262			}
263
264			// this controls flow of the updating snow
265			function snow(){
266				for( i = 0; i < flakes.length; i += 1){
267					flakes[i].update();
268				}
269
270				snowTimeout = setTimeout(function(){snow()}, 30);
271			}
272
273			snow();
274
275		// Public Methods
276
277		// clears the snowflakes
278		this.clear = function(){
279						$(element).children('.snowfall-flakes').remove();
280						flakes = [];
281						clearTimeout(snowTimeout);
282					};
283	};
284
285	// Initialize the options and the plugin
286	$.fn.snowfall = function(options){
287		if(typeof(options) == "object" || options == undefined){		
288				 return this.each(function(i){
289					(new $.snowfall(this, options)); 
290				});	
291		}else if (typeof(options) == "string") {
292			return this.each(function(i){
293				var snow = $(this).data('snowfall');
294				if(snow){
295					snow.clear();
296				}
297			});
298		}
299	};
300})(jQuery);