PageSourceSearch

https://purposely.com/wp-content/plugins/ultimate-row-background/js/rowvcpt-imageclip.js?ver=2.0.1

js purposely.com collected 2026-10-02 15:04:17 UTC 19,435 bytes, 492 lines download raw bytes

1/**
2 * main.js
3 * http://www.codrops.com
4 *
5 * Licensed under the MIT license.
6 * http://www.opensource.org/licenses/mit-license.php
7 * 
8 * Copyright 2016, Codrops
9 * http://www.codrops.com
10 */
11;(function(window) {
12
13	'use strict';
14
15	// Helper vars and functions.
16	function extend( a, b ) {
17		for( var key in b ) { 
18			if( b.hasOwnProperty( key ) ) {
19				a[key] = b[key];
20			}
21		}
22		return a;
23	}
24	// From https://davidwalsh.name/javascript-debounce-function.
25	function debounce(func, wait, immediate) {
26		var timeout;
27		return function() {
28			var context = this, args = arguments;
29			var later = function() {
30				timeout = null;
31				if (!immediate) func.apply(context, args);
32			};
33			var callNow = immediate && !timeout;
34			clearTimeout(timeout);
35			timeout = setTimeout(later, wait);
36			if (callNow) func.apply(context, args);
37		};
38	};
39	// Creates a sorted array of random numbers between minVal and maxVal with a length = size.
40	function createRandIntOrderedArray(minVal, maxVal, size) {
41		var arr = [];
42		for(var i=0; i<size; ++i) {
43			arr.push(anime.random(minVal, maxVal));
44		}
45		arr.sort(function(a, b){ return a-b });
46		return arr;
47	}
48	// Checks if an object is empty.
49	function isObjEmpty(obj) {
50		return Object.getOwnPropertyNames(obj).length > 0;
51	}
52	// Concatenate JS objs.
53	// From http://stackoverflow.com/a/2454315.
54	function collect() {
55		var ret = {};
56		var len = arguments.length;
57		for (var i=0; i<len; i++) {
58			for (var p in arguments[i]) {
59				if (arguments[i].hasOwnProperty(p)) {
60					ret[p] = arguments[i][p];
61				}
62			}
63		}
64		return ret;
65	}
66	// Check if clip-path is supported. From http://stackoverflow.com/a/30041538.
67	function areClipPathShapesSupported() {
68		var base = 'clipPath',
69			prefixes = [ 'webkit', 'moz', 'ms', 'o' ],
70			properties = [ base ],
71			testElement = document.createElement( 'testelement' ),
72			attribute = 'polygon(50% 0%, 0% 100%, 100% 100%)';
73
74		// Push the prefixed properties into the array of properties.
75		for ( var i = 0, l = prefixes.length; i < l; i++ ) {
76			var prefixedProperty = prefixes[i] + base.charAt( 0 ).toUpperCase() + base.slice( 1 ); // remember to capitalize!
77			properties.push( prefixedProperty );
78		}
79
80		// Interate over the properties and see if they pass two tests.
81		for ( var i = 0, l = properties.length; i < l; i++ ) {
82			var property = properties[i];
83
84			// First, they need to even support clip-path (IE <= 11 does not)...
85			if ( testElement.style[property] === '' ) {
86
87				// Second, we need to see what happens when we try to create a CSS shape...
88				testElement.style[property] = attribute;
89				if ( testElement.style[property] !== '' ) {
90					return true;
91				}
92			}
93		}
94		return false;
95	};
96
97	/**
98	 * Segmenter obj.
99	 */
100	function Segmenter(el, options) {
101		this.el = el;
102		this.options = extend({}, this.options);
103		extend(this.options, options);
104		// Preload main image.
105		var self = this;
106		imagesLoaded(this.el, { background: true }, function() {
107			self._init();
108			self._initEvents();
109			self.options.onReady();
110		});
111	}
112
113	Segmenter.prototype.options = {
114		// Number of pieces.
115		pieces: 4, 
116		// Show pieces already styled.
117		renderOnLoad: false,
118		// Add an element for the shadow.
119		shadows: true,
120		// Animations for the shadow (valid properties: opacity, translateX, translateY).
121		shadowsAnimation: {
122			opacity: 0.5,
123			// translateX: 20,
124			// translateY: 20
125		},
126		// Parrallax effect for the pieces.
127		parallax: false,
128		// Movements for the parallax effect.
129		parallaxMovement: {min: 10, max: 40},
130		// Animation for the pieces (valid properties: duration, easing, delay, opacity, translate[XYZ]).
131		animation: {
132			duration: 1500,
133			easing: 'easeOutQuad',
134			delay: 0, // Delay increment per piece.
135			// opacity: 0.5,
136			translateZ: {min: 10, max: 65}, // We can also use an integer for a specific value.
137			// translateX: {min: -100, max: 100}, // We can also use an integer for a specific value.
138			// translateY: {min: -100, max: 100} // We can also use an integer for a specific value.
139		},
140		animated_effects : {
141			effects:[{'effect':'scale'},{'effect':'float'},{'effect':'rotate'},{'effect':'flash'}],
142			animatespeed: [{'duration':'1s'},{'duration':'2s'},{'duration':'1.1s'}
142,{'duration':'2.2s'}],
143		},
144		// Callbacks
145		onReady: function() { return false; },
146		onAnimationComplete: function() { return false; },
147		onAnimationStart: function() { return false; },
148		// The positions of the pieces in percentage values. 
149		// We can also use random values by setting options.positions to "random".
150		positions: [
151			{top: 80, left: 10, width: 30, height: 20},
152			{top: 2, left: 2, width: 40, height: 40},
153			{top: 30, left: 60, width: 30, height: 60},
154			{top: 10, left: 20, width: 50, height: 60}
155		]
156	};
157
158	/**
159	 * Init!
160	 */
161	Segmenter.prototype._init = function() {
162		// The dimensions of the main element.
163		this.dimensions = {
164			width: this.el.offsetWidth,
165			height: this.el.offsetHeight
166		};
167		
168		// The source of the main image.
169		var background = this.el.style.backgroundImage;
170		this.imgsrc = background.replace('url(','').replace(')','').replace(/\"/gi, "");;
171		
172		// Create the layout.
173		this._layout();
174
175		var self = this;
176		this.pieces = [].slice.call(this.el.querySelectorAll('.segmenter__piece-wrap'));
177		this.pieces.forEach(function(piece, pos) {
178			// Bugfix for Chrome. The translateZ needs an initial value otherwise the animation will not work. (this seems to be a anime.js bug - let´s wait for the next version..)
179			piece.style.WebkitTransform = piece.style.transform = 'translateZ(0.0001px)';
180
181			// If we want to render the different pieces on load then:
182			if( self.options.renderOnLoad ) {
183				self._renderPiece(piece);
184			}
185		});
186		// Flag to indicate the pieces are already rendered/styled either on load or after the animation.
187		if( this.options.renderOnLoad ) {
188			this.active = true;
189		}
190	};
191
192	/**
193	 * Creates the layout.
194	 */
195	Segmenter.prototype._layout = function() {
196		// clip-path support
197		var clipPath = areClipPathShapesSupported();
198
199		var segBgEl = document.createElement('div');
200		segBgEl.className = 'segmenter__background';
201		segBgEl.style.backgroundImage = 'url(' + this.imgsrc + ')';
202
203		var segPieces = document.createElement('div'),
204			segPiecesHTML = '',
205			positionsTotal = this.options.positions.length;
206
207		segPieces.className = 'segmenter__pieces';
208
209		for(var i = 0, len = this.options.pieces; i < len; ++i) {
210			if( this.options.parallax ) {
211				segPiecesHTML += '<div class="segmenter__piece-parallax">';
212			}
213
214var effect_css='';
215if( this.options.animated_effects.animatespeed!='undefined' && this.options.animated_effects.effects!='undefined') {
216var duration_speed = this.options.animated_effects.animatespeed[i].duration;
217var effect_anim=this.options.animated_effects.effects[i].effect;
218var rand_no= anime.random(10,100000);
219if(effect_anim=="scale"){
220 effect_css ="animation: piece-"+effect_anim+"-"+rand_no+" "+duration_speed+" cubic-bezier(0.785, 0.135, 0.15, 0.86) 0s infinite alternate none running";
221}
222if(effect_anim=="float"){
223effect_css ="animation: piece-"+effect_anim+"-"+rand_no+" "+duration_speed+" ease 0s infinite alternate none running";
224}
225if(effect_anim=="rotate"){
226effect_css ="animation: piece-"+effect_anim+"-"+rand_no+" "+duration_speed+" ease 0s infinite alternate none running"; 
227}
228if(effect_anim=="flash"){
229effect_css ="animation: piece-"+effect_anim+"-"+rand_no+" "+duration_speed+" ease 0s infinite normal none running"; 
230}
231
232if(effect_anim=="scale"){
233(function($) {
234'use strict';
235	$(document).ready(function() {
236$('head').append("<style type='text/css'>@keyframes piece-"+effect_anim+"-"+rand_no+"{from{transform: translate3d(0px, 0px, 10.000"+i+"px) scale(1)}to{transform: translate3d(0px, 0px, 10.000"+i+"px) scale(1.1)}}@-webkit-keyframes piece-"+effect_anim+"-"+rand_no+"{from{transform: translate3d(0px, 0px, 10.000"+i+"px) scale(1)}to{transform: translate3d(0px, 0px, 10.000"+i+"px) scale(1.1)}}</style>");
237});
238})(jQuery);
239}
240if(effect_anim=="float"){
241(function($) {
242'use strict';
243	$(document).ready(function() {
244$('head').append("<style type='text/css'>@keyframes piece-"+effect_anim+"-"+rand_no+"{from{transform: translate3d(0px,0px,10.000"+i+"px);}to{transform: translate3d(0px,-15px,10px);}}@-webkit-keyframes piece-"+effect_anim+"-"+rand_no+"{from{transform: translate3d(0px,0px,10px);}to{transform: translate3d(0px,-15px,10.000"+i+"px);}}</style>");
245});
246})(jQuery);
247}
248
249if(effect_anim=="rotate"){
250(function($) {
251'use strict';
252	$(document).ready(function() {
253$('head').append("<style type='text/css'>@keyframes piece-"+effect_anim+"-"+rand_no+"{from{transform: translate3d(0px, 0px, 10.000"+i+"px) rotateY(0deg)}to{transform: translate3d(0px, 0px, 10.000"+i+"px) rotateY(180deg)}}@-webkit-keyframes piece-"+effect_anim+"-"+rand_no+"{from{transform: translate3d(0px, 0px, 10.000"+i+"px) rotateY(0deg)}to{transform: translate3d(0px, 0px, 10.000"+i+"px) rotateY(180deg)}}</style>");
254});
255})(jQuery);
256}
257
258if(effect_anim=="flash"){
259(function($) {
260'use strict';
261	$(document).ready(function() {
262$('head').append("<style type='text/css'>@keyframes piece-"+effect_anim+"-"+rand_no+"{from, 50%, to{opacity: 1;}25%, 75%{opacity: 0;}}@-webkit-keyframes piece-"+effect_anim+"-"+rand_no+"{from, 50%, to{opacity: 1;}25%, 75%{opacity: 0;}}</style>");
263});
264})(jQuery);
265}
266
267}
268			segPiecesHTML += '<div class="segmenter__piece-wrap" style="'+ effect_css +'">';
269			
270			var top, left, width, height, clipTop, clipLeft, clipRight, clipBottom,
271				pos = i <= positionsTotal - 1 ? i : 0,
272				isRandom = this.options.positions === 'random';
273
274			top = isRandom ? anime.random(0,100) : this.options.positions[pos].top;
275			left = isRandom ? anime.random(0,100) : this.options.positions[pos].left;
276			width = isRandom ? anime.random(0,100) : this.options.positions[pos].width;
277			height = isRandom ? anime.random(0,100) : this.options.positions[pos].height;
278			
279			if( !clipPath ) {
280				clipTop = isRandom ? top/100 * this.dimensions.height : this.options.positions[pos].top/100 * this.dimensions.height;
281				clipLeft = isRandom ? left/100 * this.dimensions.width : this.options.positions[pos].left/100 * this.dimensions.width;
282				clipRight = isRandom ? width/100 * this.dimensions.width + clipLeft : this.options.positions[pos].width/100 * this.dimensions.width + clipLeft;
283				clipBottom = isRandom ? height/100 * this.dimensions.height + clipTop : this.options.positions[pos].height/100 * this.dimensions.height + clipTop;
284			}
285
286			if( this.options.shadows ) {
287				segPiecesHTML += '<div class="segmenter__shadow" style="top: ' + top + '%; left: ' + left + '%; width: ' + width + '%; height: ' + height + '%"></div>';		
288			}
289
290			segPiecesHTML += clipPath ?
291							'<div class="segmenter__piece" style="background-image: url(' + this.imgsrc + '); -webkit-clip-path: polygon(' + left + '% ' + top + '%, ' + (left + width) + '% ' + top + '%, ' + (left + width) + '% ' + (top + height) + '%, ' + left + '% ' + (top + height) + '%); clip-path: polygon(' + left + '% ' + top + '%, ' + (left + width) + '% ' + top + '%, ' + (left + width) + '% ' + (top + height) + '%, ' + left + '% ' + (top + height) + '%)"></div>' :
292							'<div class="segmenter__piece" style="background-image: url(' + this.imgsrc + '); clip: rect(' + clipTop + 'px,' + clipRight + 'px,' + clipBottom + 'px,' + clipLeft + 'px)"></div>';
293
294			segPiecesHTML += '</div>'
295			if( this.options.parallax ) {
296				segPiecesHTML += '</div>';
297			}
298		}
299
300		segPieces.innerHTML = segPiecesHTML;
301
302		this.el.innerHTML = '';
303		this.el.appendChild(segBgEl);
304		this.el.appendChild(segPieces);
305	};
306
307	/**
308	 * Renders/Styles a piece with the options that are passed in the initialization.
309	 */
310	Segmenter.prototype._renderPiece = function(piece) {
311		var idx = this.pieces.indexOf(piece);
312
313		if( self.options.animation.translateZ != undefined ) {
314			if( typeof self.options.animation.translateZ === 'object' ) {
315				var randArr = createRandIntOrderedArray(self.options.animation.translateZ.min, self.options.animation.translateZ.max, self.options.pieces);
316				piece.style.transform = piece.style.WebkitTransform = 'translateZ(' + randArr[idx] + 'px)';
317			}
318			else {
319				piece.style.transform = piece.style.WebkitTransform = 'translateZ(' + self.options.animation.translateZ + 'px)';
320			}
321		}
322		if( self.options.animation.translateY != undefined ) {
323			if( typeof self.options.animation.translateY === 'object' ) {
324				var randArr = createRandIntOrderedArray(self.options.animation.translateY.min, self.options.animation.translateY.max, self.options.pieces);
325				piece.style.transform = piece.style.WebkitTransform = 'translateY(' + randArr[idx] + 'px)';
326			}
327			else {
328				piece.style.transform = piece.style.WebkitTransform = 'translateY(' + self.options.animation.translateY + 'px)';
329			}
330		}
331		if( self.options.animation.translateX != undefined ) {
332			if( typeof self.options.animation.translateX === 'object' ) {
333				var randArr = createRandIntOrderedArray(self.options.animation.translateX.min, self.options.animation.translateX.max, self.options.pieces);
334				piece.style.transform = piece.style.WebkitTransform = 'translateX(' + randArr[idx] + 'px)';
335			}
336			else {
337				piece.style.transform = piece.style.WebkitTransform = 'translateX(' + self.options.animation.translateX + 'px)';
338			}
339		}
340		if( self.options.animation.opacity != undefined ) {
341			piece.style.opacity = self.options.animation.opacity;
342		}
343
344		if( self.options.shadows && isObjEmpty(self.options.shadowsAnimation) ) {
345			var shadowEl = piece.querySelector('.segmenter__shadow');
346			shadowEl.style.opacity = self.options.shadowsAnimation.opacity != undefined ? self.options.shadowsAnimation.opacity : 0;
347			shadowEl.style.transform = shadowEl.style.WebkitTransform = 'translateX(' + (self.options.shadowsAnimation.translateX != undefined ? self.options.shadowsAnimation.translateX : 0) + 'px) translateY(' + (self.options.shadowsAnimation.translateY != undefined ? self.options.shadowsAnimation.translateY : 0) + 'px)';
348		}
349	};
350
351	/**
352	 * Animates the pieces with the options passed (with anime.js).
353	 */
354	Segmenter.prototype.animate = function() {
355		if( this.active ) {
356			return false;
357		}
358		this.active = true;
359
360		var self = this,
361			animProps = {
362				targets: this.pieces,
363				duration: this.options.animation.duration,
364				delay: function(el, index) { return (self.options.pieces - index - 1) * self.options.animation.delay; },
365				easing: this.options.animation.easing,
366				begin: this.options.onAnimationStart,
367				complete: this.options.onAnimationComplete
368			};
369		
370		if( this.options.animation.translateZ != undefined ) {
371			var randArr = createRandIntOrderedArray(this.options.animation.translateZ.min, this.options.animation.translateZ.max, this.options.pieces);
372			animProps.translateZ = typeof this.options.animation.translateZ === 'object' ? function(el, index) {
373				return randArr[index];
374			} : this.options.animation.translateZ;
375		}
376		if( this.options.animation.translateX != undefined ) {
377			animProps.translateX = typeof this.options.animation.translateX === 'object' ? function(el, index) {
378				return anime.random(self.options.animation.translateX.min, self.options.animation.translateX.max);
379			} : this.options.animation.translateX;
380		}
381		if( this.options.animation.translateY != undefined ) {
382			animProps.translateY = typeof this.options.animation.translateY === 'object' ? function(el, index) {
383				return anime.random(self.options.animation.translateY.min, self.options.animation.translateY.max);
384			} : this.options.animation.translateY;
385		}
386		if( this.options.animation.opacity != undefined ) {
387			animProps.opacity = this.options.animation.opacity;
388		}
389
390		anime(animProps);
391
392		// Also animate the shadow element.
393		if( this.options.shadows && isObjEmpty(this.options.shadowsAnimation) ) {
394			anime(collect({
395				targets: this.el.querySelectorAll('.segmenter__shadow'),
396				duration: this.options.animation.duration,
397				delay: function(el, index) { return (self.options.pieces - index - 1) * self.options.animation.delay; },
398				easing: this.options.animation.easing
399			}, this.options.shadowsAnimation));
400		}
401	};
402
403	/**
404	 * Init/Bind events.
405	 */
406	Segmenter.prototype._initEvents = function() {
407		var self = this;
408		
409		// Window resize.
410		this.debounceResize = debounce(function(ev) {
411			var positionsTotal = self.options.positions.length;
412
413			// Recalculate dimensions.
414			self.dimensions = {
415				width: self.el.offsetWidth,
416				height: self.el.offsetHeight
417			};
418
419			// Recalculate clip values..
420			// todo: DRY
421			// todo: If random is true then save the initial values. Should not recalculate for this case.
422			self.pieces.forEach(function(piece, position) {
423				var clipTop, clipLeft, clipRight, clipBottom,
424					segmenterPiece = piece.querySelector('.segmenter__piece');
425
426				if( self.options.positions === 'random' ) {
427					var randT = anime.random(0,100), randL = anime.random(0,100), randW = anime.random(0,100), randH = anime.random(0,100);
428					clipTop = randT/100 * self.dimensions.height;
429					clipLeft = randL/100 * self.dimensions.width;
430					clipRight = randW/100 * self.dimensions.width + clipLeft;
431					clipBottom = randH/100 * self.dimensions.height + clipTop;
432				}
433				else {
434					var pos = position <= positionsTotal - 1 ? position : 0;
435					clipTop = self.options.positions[pos].top/100 * self.dimensions.height;
436					clipLeft = self.options.positions[pos].left/100 * self.dimensions.width;
437					clipRight = self.options.positions[pos].width/100 * self.dimensions.width + clipLeft;
438					clipBottom = self.options.positions[pos].height/100 * self.dimensions.height + clipTop;
439				}
440
441				segmenterPiece.style.clip = 'rect(' + clipTop + 'px,' + clipRight + 'px,' + clipBottom + 'px,' + clipLeft + 'px)';
442			});
443		}, 10);
444		window.addEventListener('resize', this.debounceResize);
445		
446		// Mousemove and Deviceorientation:
447		if( this.options.parallax ) {
448			var arrRand = createRandIntOrderedArray(this.options.parallaxMovement.min, this.options.parallaxMovement.max, this.options.pieces);
449			this.pieces.forEach(function(piece, pos) {
450				piece.setAttribute('data-parallax-translation', typeof self.options.parallaxMovement === 'object' ? arrRand[pos] : self.options.parallaxMovement );
451			});
452			this.mousemove = function(ev) {
453				if( !self.active ) {
454					return false;
455				}
456				requestAnimationFrame(function() {
457					self.pieces.forEach(function(piece) {
458						var t = piece.getAttribute('data-parallax-translation'),
459							transX = t/(self.dimensions.width)*ev.clientX - t/2,
460							transY = t/(self.dimensions.height)*ev.clientY - t/2;
461
462						piece.parentNode.style.transform = piece.parentNode.style.WebkitTransform = 'translate3d(' + transX + 'px,' + transY + 'px,0)';
463					});
464				});
465			};
466			window.addEventListener('mousemove', this.mousemove);
467
468			this.handleOrientation = function() {
469				if( !self.active ) {
470					return false;
471				}
472				var y = event.gamma;
473				// To make computation easier we shift the range of x and y to [0,180]
474				y += 90;
475				
476				requestAnimationFrame(function() {
477					self.pieces.forEach(function(piece) {
478						var t = piece.getAttribute('data-parallax-translation'),
479							transX = t/(self.dimensions.width)*y - t/2,
480							transY = t/(self.dimensions.height)*y - t/2;
481
482						piece.parentNode.style.transform = piece.parentNode.style.WebkitTransform = 'translate3d(' + transX + 'px,' + transY + 'px,0)';
483					});
484				});
485			}
486			window.addEventListener('deviceorientation', this.handleOrientation);
487		}
488	};
489
490	window.Segmenter = Segmenter;
491
492})(window);

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.