PageSourceSearch

https://www.woodlands.co.nz/edit/scripts/jquery.backgroundimage.js

js woodlands.co.nz collected 2026-10-09 00:38:21 UTC 18,986 bytes, 703 lines download raw bytes

1/**
2 * Background Image v2.0
3 *
4 * Plugin for controlling the display of background images
5 * with content over top.
6 *
7 * Example usage:
8 * $(".bgimg").backgroundimage();
9 *
10 * Html usage:
11 * <div class="bgimg">
12 * 	<img/>
13 * 	<div></div>
14 * </div>
15 *
16 * Copyright 2017 Josh Tere <[email protected]>
17 * Released under the MIT License
18 * http://www.joshtere.com
19 */
20 
21
22(function($, window, document, undefined) {
23	"use strict";
24
25	//
26	var pluginName = "backgroundimage";
27	
28	// Debug mode
29	var debugMode = false;
30	
31	//
32	function Plugin(element, options) {
33		
34		//
35		this.settings = $.extend(true,{},defaults,options);
36		
37		//
38		this.element  = $(element);
39		this.$elem    = $(this.element);
40
41		//
42		this.$window  = $(window);
43		
44		//
45		var $this = this;
46		
47		//
48		function animation_frame() {
49			//
50			if($this.settings.lastPosition === window.pageYOffset) {
51				   
52				// Avoid overcalculations
53				animateFrame(animation_frame);
54				return false;
55			} 
56			else {
57				$this.settings.lastPosition = window.pageYOffset;
58			}
59			
60			$this.move($this,false);
61			
62			animateFrame(animation_frame);
63			
64			//console.log("Animate");
65		}
66		
67		//	
68		function move_on_resize() {
69	
70			$this.settings.viewportWidth  = window.innerWidth;
71			$this.settings.viewportHeight = window.innerHeight;
72			$this.settings.scrollTop      = $(window).scrollTop();
73	
74			// Adjust background image sizes
75			$this.resize($this,false);
76
77			// Move background images
78			$this.move($this,false);
79			
80			//console.log("Resize");
81		}
82		
83		//	
84		function move_on_scroll() {
85	
86			$this.move($this,false);
87			
88			//console.log("Scroll");
89		}
90		
91		if($.throttle) {
92			// Run functions during resize
93			this.$window.resize($.throttle(250,move_on_resize));
94			
95			// Run functions during scroll
96			this.$window.scroll($.throttle(20,move_on_scroll));
97		}
98		else {
99			// Run functions during resize
100			this.$window.resize(move_on_resize);
101			
102			// Run functions during scroll
103			this.$window.scroll(move_on_scroll);
104		}
105		
106		// Start frame animation
107		animation_frame();
108		
109		//
110		this.init();
111	}
112	
113	// Animation frame
114	var animateFrame = window.requestAnimationFrame ||
115						window.webkitRequestAnimationFrame ||
116						window.mozRequestAnimationFrame ||
117						window.msRequestAnimationFrame ||
118						window.oRequestAnimationFrame ||
119						function(callback){setTimeout(callback,1000/60);};
120						
121	// Set transform property
122    var transformProp = window.transformProp || (function() {
123		var testEl = document.createElement('div');
124		if(testEl.style.transform === null) {
125			var vendors = ['Webkit', 'Moz', 'ms'];
126			for(var vendor in vendors) {
127				if(testEl.style[ vendors[vendor] + 'Transform' ] !== undefined) {
128					return vendors[vendor] + 'Transform';
129				}
130			}
131		}
132		return 'transform';
133	})();
134	
135	// Set item count
136	var itemCount = 0;
137	
138	// Default options
139	var defaults = {
140		
141		//
142		top : 0,
143		
144		//
145		height : 0,
146		
147		// Parallax scroll value
148		parallaxSpeed : 0.5,
149		
150		// Minumum effects width
151		effectsCutoff : 720,
152		
153		// Fade speed
154		fadeSpeed : 10,
155		
156		// Scale speed
157		scaleSpeed : 5,
158		
159		// Scroll interval
160		scrollInterval : 1,
161		
162		// Last scroll position
163		lastPosition : -1,
164		
165		// Viewport width and height
166		viewportWidth  : window.innerWidth,
167		viewportHeight : window.innerHeight,
168		
169		// Distance from top
170		scrollTop : $(window).scrollTop(),
171		
172		// Browser
173		browser : browser(),
174		
175		// Complete callback
176		complete : function() {
177			
178		},
179	};
180	
181	//
182	Plugin.prototype = {
183		
184		// Update backgrounds
185		update: function() {
186			
187			// Move background images
188			this.move(this,true);
189			
190			// Adjust background image sizes
191			this.resize(this,true);
192			
193			//console.log("Updated");
194		},
195		
196		// Move background
197		move : function(el,setup) {
198			
199			// No parallax on edge
200			if(!setup && (this.settings.browser === "IE" || this.settings.browser === "Edge")) {
201				return;
202			}
203			
204			// Check for element height
205			if(this.settings.height <= 0) {
206				//
207				this.settings.top    = this.$elem.offset().top;
208				this.settings.height = this.$elem.height();
209			}
210			
211			this.settings.scrollTop = this.$window.scrollTop();
212			
213			// Set visible flag to false
214			var visible = false;
215			
216			// Check container in viewport
217			if(this.settings.scrollTop+this.settings.viewportHeight+50 > this.settings.top && 
218				this.settings.scrollTop <= this.settings.top+this.settings.height) {
219					
220				//
221				visible = true;
222				//console.log("Visible");
223			}
224			
225			// If slide, check visible
226			if(this.slide && this.$elem.css('opacity') == 0) {
227				visible = false;
228			}
229			
230			// Run all on setup
231			if(setup) {visible = true;}
232			
233			// If container is visible
234			if(visible) {
235					
236				// Get container top
237				var containerTop = (this.settings.top-this.settings.scrollTop);
238				
239				/*var percentageY = (this.settings.scrollTop - this.settings.top / this.settings.viewportHeight)*(this.settings.height - this.settings.viewportHeight);
240				var valueX      = (this.settings.parallaxSpeed * (100 * (1 - percentageY)));
241				valueX          = Math.round(valueX * 100) / 100;
242				valueX          = Math.round((containerTop*this.settings.parallaxSpeed)*-1); // this.settings.parallaxSpeed*/
243						
244				// Move image
245				if(this.$image) {
246					
247					/*var yE = containerTop;
248					var hV = this.settings.viewportHeight;
249					var hE = this.settings.height;
250					var hB = this.$image.height();
251					
252					var yB = ((yE)/(hV))*(hE-hB);*/
253					//console.log(containerTop);
254					//valueX = yB;
255					
256					// Get effects
257					var effects = this.imageEffects;
258					effects = (effects === undefined) ? '' : effects;
259					
260					if(effects !== '') {
261						
262						// Set offset
263						var newOffset = (effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? Math.round((containerTop*this.settings.parallaxSpeed)*-1) : 0;
264						
265						// Set opacity
266						var opacity = (effects.indexOf('fade') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? 1-(((containerTop*(this.settings.fadeSpeed/100))/100)*-1) : 1;
267						opacity = (opacity > 1) ? 1 : opacity;
268						
269						// Set scale
270						var scale = (effects.indexOf('expand') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? 1+(((containerTop*(this.settings.scaleSpeed/100))/100)*-1) : 1;
271						scale = (scale < 1) ? 1 : scale;
272						
273						// Update image
274						this.$image.css(transformProp,"translate3d(0px,"+newOffset+"px,0px) scale("+scale+")");
275						this.$image.css("opacity",opacity);
276					}
277				}
278					
279				// Move content
280				if(this.$content) {
281					
282					// Get effects
283					var effects = this.contentEffects;
284					effects = (effects === undefined) ? '' : effects;
285					
286					if(effects !== '') {
287						// Set offset
288						var newOffset = (effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? Math.round((containerTop*this.settings.parallaxSpeed)*-1) : 0;
289						newOffset = (containerTop > 0) ? 0 : newOffset;
290						
291						// Set opacity
292						opacity = (effects.indexOf('fade') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) ? 1-(((containerTop*((this.settings.fadeSpeed+5)/100))/100)*-1) : 1;
293						opacity = (opacity > 1) ? 1 : opacity;
294							
295						// Update content
296						this.$content.css(transformProp,"translate3d(0px,"+newOffset+"px,0px)");
297						this.$content.css("opacity",opacity);
298					}
299				}
300				
301				if(debugMode) {
302					if(this.$content) {
303						$("#"+this.id+"-top-tag").css('top',this.settings.top+'px');
304						$("#"+this.id+"-bottom-tag").css('top',this.settings.top+this.settings.height+'px');
305					}
306					
307					if(this.$image) {
308						$("#"+this.id+"-image-top-tag").css('top',this.$image.offset().top+'px');
309						$("#"+this.id+"-image-bottom-tag").css('top',((this.$image.offset().top+this.$image.height()))+'px');
310					}
311				}
312			}
313			
314			//console.log("Move");
315		},
316		
317		// Adjust background image sizes
318		resize : function(setup) {
319			
320			// Check for element height
321			this.settings.top = this.$elem.offset().top;
322			this.settings.height = this.$elem.height();
323			
324			// Set width and height
325			{
326				// Set is contrained
327				var isConstrained = false;
328				
329				// Get effects
330				var effects = this.imageEffects;
331				effects = (effects === undefined) ? '' : effects;
332				
333				// If parallax then use full height/width
334				if(effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) {
335					
336					var fullWidth  = this.$elem.innerWidth();
337					var fullHeight = this.$elem.innerHeight()*(1+this.settings.parallaxSpeed);
338					
339					// Get site full width
340					var siteFullWidth  = (this.$elem.innerWidth() > this.settings.viewportWidth) ? this.$elem.innerWidth() : this.settings.viewportWidth;
341					var siteFullHeight = (this.$elem.innerHeight() > this.settings.viewportHeight) ? this.$elem.innerHeight() : this.settings.viewportHeight;
342				
343					// Overwrite width with full if needed
344					if(fullWidth+30 > siteFullWidth) {fullWidth = siteFullWidth;}
345					else {isConstrained = true;}
346					//if(fullHeight+30 > siteFullHeight) {fullHeight = siteFullHeight;}
347				}
348				
349				// Else use container height/width
350				else {
351					var fullWidth  = this.$elem.innerWidth();
352					var fullHeight = this.$elem.innerHeight();
353				}
354			}
355	
356			// Set dimensions
357			{
358				// Dimensions
359				var dimensions = this.$image.data("dimensions");
360				dimensions = (dimensions === undefined) ? [0,0] : dimensions.split("x");
361	
362				// New dimensions
363				var newWidth  = 0;
364				var newHeight = 0;
365	
366				// Try to resize by width
367				newWidth  = fullWidth;
368				newHeight = Math.ceil((newWidth/dimensions[0])*dimensions[1]);
369	
370				// If height to short then resize by height
371				if(newHeight < fullHeight) {
372					//
373					newHeight = fullHeight;
374					newWidth  = Math.ceil((newHeight/dimensions[1])*dimensions[0]);
375				}
376			}
377			
378	
379			// Set focal point
380			{
381				/*
382					Focal Point Difference
383					--
384					The focal point difference is the amount the image needs to 
385					move (left or right) before the focal point is centered. A positive
386					value should be aligned from the left and a negative value from
387					the right. An image should be moved to the right or left until
388					the focal point difference has been made up.
389	
390					var fpd = (((imageWidth/2)-(imageWidth*fp))*2)*-1;
391				*/
392	
393				// Focal points
394				var focalPoints = this.$image.data("focal-points");
395				focalPoints = (focalPoints === undefined) ? [0.5,0.5] : focalPoints.split(",");
396	
397				// New locations
398				var newTop    = false;
399				var newLeft   = false;
400				var newRight  = false;
401				var newBottom = false;
402	
403				// If width is greater than the viewport then set image focal point
404				if(newWidth > fullWidth) {
405	
406					// Get focal point difference
407					var focalPointDifference = Math.ceil((((newWidth/2)-(newWidth*parseFloat(focalPoints[0])))*2)*-1);
408	
409					// If focal point difference is greater than 0, move to left
410					if(focalPointDifference > 0) {
411	
412						// If focal point difference is greater than amount to move, then move left
413						if(Math.ceil(newWidth-fullWidth) <= focalPointDifference) {
414							// Set left
415							newLeft  = Math.ceil(newWidth-fullWidth)*-1;
416							newLeft  = newLeft+'px';
417						}
418						// If less than amount to move, then move left and center
419						else {
420							// Set left
421							newLeft  = focalPointDifference;
422							newLeft += Math.ceil((Math.ceil(newWidth-fullWidth)-focalPointDifference)/2);
423							newLeft  = newLeft*-1;
424							newLeft  = newLeft+'px';
425						}
426	
427						//
428						newRight = 'auto';
429					}
430					// If focal point difference is less than 0, move to right
431					else if(focalPointDifference < 0) {
432	
433						//
434						focalPointDifference = focalPointDifference*-1;
435	
436						// If focal point difference is greater than amount to move, then move right
437						if(Math.ceil(newWidth-fullWidth) <= focalPointDifference) {
438							// Set right
439							newRight = Math.ceil(newWidth-fullWidth)*-1;
440							newRight = newRight+'px';
441							newLeft  = 'auto';
442						}
443						// If less than amount to move, then move right and center
444						else {
445							// Set right
446							newRight  = focalPointDifference;
447							newRight += Math.ceil((Math.ceil(newWidth-fullWidth)-focalPointDifference)/2);
448							newRight  = newRight*-1;
449							newRight  = newRight+'px';
450							newLeft   = 'auto';
451						}
452					}
453					// If focal point difference is 0
454					else {
455						// Set left
456						newLeft  = Math.ceil((newWidth-fullWidth)/2);
457						newLeft  = newLeft*-1;
458						newLeft  = newLeft+'px';
459						newRight = 'auto';
460					}
461				}
462				else {
463					// Set left
464					newLeft  = 0;
465					newRight = 'auto';
466				}
467	
468	
469				// If height is greater than the viewport then set image focal point
470				if(newHeight > fullHeight) {
471	
472					// Get focal point difference
473					var focalPointDifference = Math.ceil((((newHeight/2)-(newHeight*parseFloat(focalPoints[1])))*2)*-1);
474				
475					// If focal point difference is greater than 0, move up
476					if(focalPointDifference > 0) {
477	
478						// If focal point difference is greater than amount to move, then move up
479						if(Math.ceil(newHeight-fullHeight) <= focalPointDifference) {
480							// Set top
481							newTop  = Math.ceil(newHeight-fullHeight)*-1;
482							newTop  = newTop+'px';
483						}
484						// If less than amount to move, then move up and center
485						else {
486							// Set left
487							newTop  = focalPointDifference;
488							newTop += Math.ceil((Math.ceil(newHeight-fullHeight)-focalPointDifference)/2);
489							newTop  = newTop*-1;
490							newTop  = newTop+'px';
491						}
492	
493						//
494						newBottom = 'auto';
495					}
496					// If focal point difference is less than 0, move down
497					else if(focalPointDifference < 0) {
498	
499						//
500						focalPointDifference = focalPointDifference*-1;
501	
502						// If focal point difference is greater than amount to move, then move down
503						if(Math.ceil(newHeight-fullHeight) <= focalPointDifference) {
504							// Set bottom
505							newBottom = Math.ceil(newHeight-fullHeight)*-1;
506							newBottom = newBottom+'px';
507							newTop    = 'auto';
508						}
509						// If less than amount to move, then move down and center
510						else {
511							// Set bottom
512							newBottom  = focalPointDifference;
513							newBottom += Math.ceil((Math.ceil(newHeight-fullHeight)-focalPointDifference)/2);
514							newBottom  = newBottom*-1;
515							newBottom  = newBottom+'px';
516							newTop     = 'auto';
517						}
518					}
519					// If focal point difference is 0
520					else {
521						// Set top
522						newTop    = Math.ceil((newHeight-fullHeight)/2);
523						newTop    = newTop*-1;
524						
525						// Hack for constrained parallax images
526						if(isConstrained && effects.indexOf('parallax') !== -1) {
527							newTop = newTop+50;
528						}
529						else if(effects.indexOf('parallax') !== -1 && this.settings.viewportWidth > this.settings.effectsCutoff) {
530							newTop = newTop+20;
531						}
532						
533						newTop    = newTop+'px';
534						newBottom = 'auto';
535					}
536				}
537				else {
538					// Set top
539					newTop    = 0;
540					newBottom = 'auto';
541				}
542			}
543	
544	
545			// Update image
546			{
547				this.$image.width(newWidth);
548				this.$image.height(newHeight);
549	
550				// If top is set
551				if(newTop !== false) {
552					this.$image.css("top",""+newTop+"");
553				}
554	
555				// If left is set
556				if(newLeft !== false) {
557					this.$image.css("left",""+newLeft+"");
558				}
559	
560				// If right is set
561				if(newRight !== false) {
562					this.$image.css("right",""+newRight+"");
563				}
564	
565				// If bottom is set
566				if(newBottom !== false) {
567					this.$image.css("bottom",""+newBottom+"");
568				}
569			}
570			
571			//console.log("Resize");
572		},
573		
574		init: function() {
575			
576			// Add to item count
577			itemCount = itemCount+1;
578			
579			//
580			var $this = this;
581			
582			// Set item id
583			this.id = 'bgi-item-'+itemCount;
584			
585			// Add background image classes to elements
586			this.$image   = this.$elem.children("picture,img").first();
587			this.$content = this.$elem.children("div").first();
588			
589			// Check if element is part of unslider
590			if(this.$elem.hasClass("sliderimg")) {
591				//
592				this.slide = true;
593			}
594			
595			// Add class to container
596			this.$elem.addClass('backgroundimage-container');
597			
598			// Effects
599			this.imageEffects   = this.$image.data("effect");
600			this.contentEffects = this.$content.data("effect");
601			
602			if(this.settings.browser === "IE" || this.settings.browser === "Edge") {
603				
604				this.imageEffects = "";
605				this.contentEffects = "";
606			}
607			
608			// Wrap image
609			this.$image.css('display','block');
610			this.$image.wrap('<div class="backgroundimage-image"></div>');
611			
612			// Add class to content
613			this.$content.addClass('backgroundimage-content');
614			
615			// Background image parameters
616			this.settings.top = this.$elem.offset().top;
617			this.settings.height = this.$elem.height();
618			
619			setTimeout(function() {
620				//
621				$this.settings.top = $this.$elem.offset().top;
622				$this.settings.height = $this.$elem.height();
623				
624				// Move background images
625				$this.move($this,true);
626				
627				if(debugMode) {
628					$("html").append('<div id="'+$this.id+'-top-tag" class="top-tag" style="top:'+$this.settings.top+'px;"></div>');
629					$("html").append('<div id="'+$this.id+'-bottom-tag" class="bottom-tag" style="top:'+($this.settings.top+$this.settings.height)+'px;"></div>');
630					//
631					$("html").append('<div id="'+$this.id+'-image-top-tag" class="image-top-tag" style="top:'+$this.$image.offset().top+'px;"></div>');
632					$("html").append('<div id="'+$this.id+'-image-bottom-tag" class="image-bottom-tag" style="top:'+($this.$image.offset().top+$this.$image.height())+'px;"></div>');
633				}
634			},400);
635			
636			//console.log(this.settings.top);
637
638			// Move background images
639			this.move(this,true);
640			
641			// Adjust background image sizes
642			this.resize(this,true);
643			
644			// Return element on complete
645			if($.isFunction(this.settings.complete)) {
646				//
647				this.settings.complete.call(this.$elem);
648			}
649			
650			//console.log("Initialise");
651		}
652	};
653	
654	//
655	$.fn[pluginName] = function(options) {
656		return this.each(function() {
657			
658			// Check if there is an existing instance related to element
659			var instance = $.data(this, pluginName);
660			
661			if(instance) {
662				if(typeof options === "string" && typeof instance[options] === "function") {
663					instance[options].apply(instance);
664				}
665				else if(options !== undefined) {
666					console.log('Method ' + options + ' does not exist on Plugin');
667				}
668			} 
669			else {
670				// Create the plugin
671				var plugin = new Plugin(this,options);
672	
673				// Store the plugin instance on the element
674				$.data(this,pluginName,plugin);
675			}
676		});
677	};
678	
679	// Basic browser detection
680	function browser() {
681		//
682		var browser = 'Other';
683		var ua      = window.navigator.userAgent;
684		var msie    = ua.indexOf('MSIE ');
685		var trident = ua.indexOf('Trident/');
686		var edge    = ua.indexOf('Edge/');
687		
688		// IE
689		if(parseInt(msie) > 0 || parseInt(trident) > 0) {
690			//
691			browser = 'IE';
692		}
693		// Edge
694		else if(parseInt(edge) > 0) {
695			//
696			browser = 'Edge';
697		}
698		
699		//
700		return browser;
701	}
702		
703}(jQuery, window, document));

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.