PageSourceSearch

https://ifva.com/lib/js/jquery.parallax.js?lang=2&cache=20260924170943&isCCCMS=

js ifva.com collected 2026-09-24 10:00:15 UTC 12,450 bytes, 520 lines download raw bytes

1// jquery.parallax.js
2// 2.0
3// Stephen Band
4//
5// Project and documentation site:
6// webdev.stephband.info/jparallax/
7//
8// Repository:
9// github.com/stephband/jparallax
10
11(function(jQuery, undefined) {
12	// VAR
13	var debug = true,
14	    
15	    options = {
16	    	mouseport:     'body',  // jQuery object or selector of DOM node to use as mouseport
17	    	xparallax:     true,    // boolean | 0-1 | 'npx' | 'n%'
18	    	yparallax:     true,    //
19	    	xorigin:       0.5,     // 0-1 - Sets default alignment. Only has effect when parallax values are something other than 1 (or true, or '100%')
20	    	yorigin:       0.5,     //
21	    	decay:         0.66,    // 0-1 (0 instant, 1 forever) - Sets rate of decay curve for catching up with target mouse position
22	    	frameDuration: 30,      // Int (milliseconds)
23	    	freezeClass:   'freeze' // String - Class added to layer when frozen
24	    },
25	
26	    value = {
27	    	left: 0,
28	    	top: 0,
29	    	middle: 0.5,
30	    	center: 0.5,
31	    	right: 1,
32	    	bottom: 1
33	    },
34	
35	    rpx = /^\d+\s?px$/,
36	    rpercent = /^\d+\s?%$/,
37	    
38	    win = jQuery(window),
39	    doc = jQuery(document),
40	    mouse = [0, 0];
41	
42	var Timer = (function(){
43		var debug = false;
44		
45		// Shim for requestAnimationFrame, falling back to timer. See:
46		// see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
47		var requestFrame = (function(){
48		    	return (
49		    		window.requestAnimationFrame ||
50		    		window.webkitRequestAnimationFrame ||
51		    		window.mozRequestAnimationFrame ||
52		    		window.oRequestAnimationFrame ||
53		    		window.msRequestAnimationFrame ||
54		    		function(fn, node){
55		    			return window.setTimeout(function(){
56		    				fn();
57		    			}, 25);
58		    		}
59		    	);
60		    })();
61		
62		function Timer() {
63			var callbacks = [],
64				nextFrame;
65			
66			function noop() {}
67			
68			function frame(){
69				var cbs = callbacks.slice(0),
70				    l = cbs.length,
71				    i = -1;
72				
73				if (debug) { console.log('timer frame()', l); }
74				
75				while(++i < l) { cbs[i].call(this); }
76				requestFrame(nextFrame);
77			}
78			
79			function start() {
80				if (debug) { console.log('timer start()'); }
81				this.start = noop;
82				this.stop = stop;
83				nextFrame = frame;
84				requestFrame(nextFrame);
85			}
86			
87			function stop() {
88				if (debug) { console.log('timer stop()'); }
89				this.start = start;
90				this.stop = noop;
91				nextFrame = noop;
92			}
93			
94			this.callbacks = callbacks;
95			this.start = start;
96			this.stop = stop;
97		}
98
99		Timer.prototype = {
100			add: function(fn) {
101				var callbacks = this.callbacks,
102				    l = callbacks.length;
103				
104				// Check to see if this callback is already in the list.
105				// Don't add it twice.
106				while (l--) {
107					if (callbacks[l] === fn) { return; }
108				}
109				
110				this.callbacks.push(fn);
111				if (debug) { console.log('timer add()', this.callbacks.length); }
112			},
113		
114			remove: function(fn) {
115				var callbacks = this.callbacks,
116				    l = callbacks.length;
117				
118				// Remove all instances of this callback.
119				while (l--) {
120					if (callbacks[l] === fn) { callbacks.splice(l, 1); }
121				}
122				
123				if (debug) { console.log('timer remove()', this.callbacks.length); }
124				
125				if (callbacks.length === 0) { this.stop(); }
126			}
127		};
128		
129		return Timer;
130	})();
131	
132	function parseCoord(x) {
133		return (rpercent.exec(x)) ? parseFloat(x)/100 : x;
134	}
135	
136	function parseBool(x) {
137		return typeof x === "boolean" ? x : !!( parseFloat(x) ) ;
138	}
139	
140	function portData(port) {
141		var events = {
142		    	'mouseenter.parallax': mouseenter,
143		    	'mouseleave.parallax': mouseleave
144		    },
145		    winEvents = {
146		    	'resize.parallax': resize
147		    },
148		    data = {
149		    	elem: port,
150		    	events: events,
151		    	winEvents: winEvents,
152		    	timer: new Timer()
153		    },
154		    layers, size, offset;
155		
156		function updatePointer() {
157			data.pointer = getPointer(mouse, [true, true], offset, size);
158		}
159		
160		function resize() {
161			size = getSize(port);
162			offset = getOffset(port);
163			data.threshold = getThreshold(size);
164		}
165		
166		function mouseenter() {
167			data.timer.add(updatePointer);
168		}
169		
170		function mouseleave(e) {
171			data.timer.remove(updatePointer);
172			data.pointer = getPointer([e.pageX, e.pageY], [true, true], offset, size);
173		}
174
175		win.on(winEvents);
176		port.on(events);
177		
178		resize();
179		
180		return data;
181	}
182	
183	function getData(elem, name, fn) {
184		var data = elem.data(name);
185		
186		if (!data) {
187			data = fn ? fn(elem) : {} ;
188			elem.data(name, data);
189		}
190		
191		return data;
192	}
193	
194	function getPointer(mouse, parallax, offset, size){
195		var pointer = [],
196		    x = 2;
197		
198		while (x--) {
199			pointer[x] = (mouse[x] - offset[x]) / size[x] ;
200			pointer[x] = pointer[x] < 0 ? 0 : pointer[x] > 1 ? 1 : pointer[x] ;
201		}
202		
203		return pointer;
204	}
205	
206	function getSize(elem) {
207		return [elem.width(), elem.height()];
208	}
209	
210	function getOffset(elem) {
211		var offset = elem.offset() || {left: 0, top: 0},
212			borderLeft = elem.css('borderLeftStyle') === 'none' ? 0 : parseInt(elem.css('borderLeftWidth'), 10),
213			borderTop = elem.css('borderTopStyle') === 'none' ? 0 : parseInt(elem.css('borderTopWidth'), 10),
214			paddingLeft = parseInt(elem.css('paddingLeft'), 10),
215			paddingTop = parseInt(elem.css('paddingTop'), 10);
216		
217		return [offset.left + borderLeft + paddingLeft, offset.top + borderTop + paddingTop];
218	}
219	
220	function getThreshold(size) {
221		return [1/size[0], 1/size[1]];
222	}
223	
224	function layerSize(elem, x, y) {
225		return [x || elem.outerWidth(), y || elem.outerHeight()];
226	}
227	
228	function layerOrigin(xo, yo) {
229		var o = [xo, yo],
230			i = 2,
231			origin = [];
232		
233		while (i--) {
234			origin[i] = typeof o[i] === 'string' ?
235				o[i] === undefined ?
236					1 :
237					value[origin[i]] || parseCoord(origin[i]) :
238				o[i] ;
239		}
240		
241		return origin;
242	}
243	
244	function layerPx(xp, yp) {
245		return [rpx.test(xp), rpx.test(yp)];
246	}
247	
248	function layerParallax(xp, yp, px) {
249		var p = [xp, yp],
250		    i = 2,
251		    parallax = [];
252		
253		while (i--) {
254			parallax[i] = px[i] ?
255				parseInt(p[i], 10) :
256				parallax[i] = p[i] === true ? 1 : parseCoord(p[i]) ;
257		}
258		
259		return parallax;
260	}
261	
262	function layerOffset(parallax, px, origin, size) {
263		var i = 2,
264		    offset = [];
265		
266		while (i--) {
267			offset[i] = px[i] ?
268				origin[i] * (size[i] - parallax[i]) :
269				parallax[i] ? origin[i] * ( 1 - parallax[i] ) : 0 ;
270		}
271		
272		return offset;
273	}
274	
275	function layerPosition(px, origin) {
276		var i = 2,
277		    position = [];
278		
279		while (i--) {
280			if (px[i]) {
281				// Set css position constant
282				position[i] = origin[i] * 100 + '%';
283			}
284			else {
285			
286			}
287		}
288		
289		return position;
290	}
291	
292	function layerPointer(elem, parallax, px, offset, size) {
293		var viewport = elem.offsetParent(),
294			pos = elem.position(),
295			position = [],
296			pointer = [],
297			i = 2;
298		
299		// Reverse calculate ratio from elem's current position
300		while (i--) {
301			position[i] = px[i] ?
302				// TODO: reverse calculation for pixel case
303				0 :
304				pos[i === 0 ? 'left' : 'top'] / (viewport[i === 0 ? 'outerWidth' : 'outerHeight']() - size[i]) ;
305			
306			pointer[i] = (position[i] - offset[i]) / parallax[i] ;
307		}
308		
309		return pointer;
310	}
311	
312	function layerCss(parallax, px, offset, size, position, pointer) {
313		var pos = [],
314		    cssPosition,
315		    cssMargin,
316		    x = 2,
317		    css = {};
318		
319		while (x--) {
320			if (parallax[x]) {
321				pos[x] = parallax[x] * pointer[x] + offset[x];
322				
323				// We're working in pixels
324				if (px[x]) {
325					cssPosition = position[x];
326					cssMargin = pos[x] * -1;
327				}
328				// We're working by ratio
329				else {
330					cssPosition = pos[x] * 100 + '%';
331					cssMargin = pos[x] * size[x] * -1;
332				}
333				
334				// Fill in css object
335				if (x === 0) {
336					css.left = cssPosition;
337					css.marginLeft = cssMargin;
338				}
339				else {
340					css.top = cssPosition;
341					css.marginTop = cssMargin;
342				}
343			}
344		}
345		
346		return css;
347	}
348	
349	function pointerOffTarget(targetPointer, prevPointer, threshold, decay, parallax, targetFn, updateFn) {
350		var pointer, x;
351		
352		if ((!parallax[0] || Math.abs(targetPointer[0] - prevPointer[0]) < threshold[0]) &&
353		    (!parallax[1] || Math.abs(targetPointer[1] - prevPointer[1]) < threshold[1])) {
354		    // Pointer has hit the target
355		    if (targetFn) { targetFn(); }
356		    return updateFn(targetPointer);
357		}
358		
359		// Pointer is nowhere near the target
360		pointer = [];
361		x = 2;
362		
363		while (x--) {
364			if (parallax[x]) {
365				pointer[x] = targetPointer[x] + decay * (prevPointer[x] - targetPointer[x]);
366			}
367		}
368			
369		return updateFn(pointer);
370	}
371	
372	function pointerOnTarget(targetPointer, prevPointer, threshold, decay, parallax, targetFn, updateFn) {
373		// Don't bother updating if the pointer hasn't changed.
374		if (targetPointer[0] === prevPointer[0] && targetPointer[1] === prevPointer[1]) {
375			return;
376		}
377		
378		return updateFn(targetPointer);
379	}
380	
381	function unport(elem, events, winEvents) {
382		elem.off(events).removeData('parallax_port');
383		win.off(winEvents);
384	}
385	
386	function unparallax(node, port, events) {
387		port.elem.off(events);
388		
389		// Remove this node from layers
390		port.layers = port.layers.not(node);
391		
392		// If port.layers is empty, destroy the port
393		if (port.layers.length === 0) {
394			unport(port.elem, port.events, port.winEvents);
395		}
396	}
397	
398	function unstyle(parallax) {
399		var css = {};
400		
401		if (parallax[0]) {
402			css.left = '';
403			css.marginLeft = '';
404		}
405		
406		if (parallax[1]) {
407			css.top = '';
408			css.marginTop = '';
409		}
410		
411		elem.css(css);
412	}
413	
414	jQuery.fn.parallax = function(o){
415	    console.log(2);
416		var options = jQuery.extend({}, jQuery.fn.parallax.options, o),
417		    args = arguments,
418		    elem = options.mouseport instanceof jQuery ?
419		    	options.mouseport :
420		    	jQuery(options.mouseport) ,
421		    port = getData(elem, 'parallax_port', portData),
422		    timer = port.timer;
423		
424		return this.each(function(i) {
425			var node      = this,
426			    elem      = jQuery(this),
427			    opts      = args[i + 1] ? jQuery.extend({}, options, args[i + 1]) : options,
428			    decay     = opts.decay,
429			    size      = layerSize(elem, opts.width, opts.height),
430			    origin    = layerOrigin(opts.xorigin, opts.yorigin),
431			    px        = layerPx(opts.xparallax, opts.yparallax),
432			    parallax  = layerParallax(opts.xparallax, opts.yparallax, px),
433			    offset    = layerOffset(parallax, px, origin, size),
434			    position  = layerPosition(px, origin),
435			    pointer   = layerPointer(elem, parallax, px, offset, size),
436			    pointerFn = pointerOffTarget,
437			    targetFn  = targetInside,
438			    events = {
439			    	'mouseenter.parallax': function mouseenter(e) {
440			    		pointerFn = pointerOffTarget;
441			    		targetFn = targetInside;
442			    		timer.add(frame);
443			    		timer.start();
444			    	},
445			    	'mouseleave.parallax': function mouseleave(e) {
446			    		// Make the layer come to rest at it's limit with inertia
447			    		pointerFn = pointerOffTarget;
448			    		// Stop the timer when the the pointer hits target
449			    		targetFn = targetOutside;
450			    	}
451			    };
452			
453			function updateCss(newPointer) {
454				var css = layerCss(parallax, px, offset, size, position, newPointer);
455				elem.css(css);
456				pointer = newPointer;
457			}
458			
459			function frame() {
460				pointerFn(port.pointer, pointer, port.threshold, decay, parallax, targetFn, updateCss);
461			}
462			
463			function targetInside() {
464				// Pointer hits the target pointer inside the port
465				pointerFn = pointerOnTarget;
466			}
467			
468			function targetOutside() {
469				// Pointer hits the target pointer outside the port
470				timer.remove(frame);
471			}
472			
473			
474			if (jQuery.data(node, 'parallax')) {
475				elem.unparallax();
476			}
477			
478			jQuery.data(node, 'parallax', {
479				port: port,
480				events: events,
481				parallax: parallax
482			});
483			
484			port.elem.on(events);
485			port.layers = port.layers? port.layers.add(node): jQuery(node);
486			
487			/*function freeze() {
488				freeze = true;
489			}
490			
491			function unfreeze() {
492				freeze = false;
493			}*/
494			
495			/*jQuery.event.add(this, 'freeze.parallax', freeze);
496			jQuery.event.add(this, 'unfreeze.parallax', unfreeze);*/
497		});
498	};
499	
500	jQuery.fn.unparallax = function(bool) {
501		return this.each(function() {
502			var data = jQuery.data(this, 'parallax');
503			
504			// This elem is not parallaxed
505			if (!data) { return; }
506			
507			jQuery.removeData(this, 'parallax');
508			unparallax(this, data.port, data.events);
509			if (bool) { unstyle(data.parallax); }
510		});
511	};
512	
513	jQuery.fn.parallax.options = options;
514	
515	// Pick up and store mouse position on document: IE does not register
516	// mousemove on window.
517	doc.on('mousemove.parallax', function(e){
518		mouse = [e.pageX, e.pageY];
519	});
520}(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.