PageSourceSearch

https://solnustec.com/wp-content/plugins/makro-core/inc/parallax/assets/js/parallax.move.js?ver=1.0.0

js solnustec.com collected 2026-10-02 15:47:17 UTC 17,537 bytes, 521 lines download raw bytes

1/**
2 * jQuery || Zepto Parallax Plugin
3 * @author Matthew Wagerfield - @wagerfield
4 * @description Creates a parallax effect between an array of layers,
5 *              driving the motion from the gyroscope output of a smartdevice.
6 *              If no gyroscope is available, the cursor position is used.
7 */
8 ;(function($, window, document, undefined) {
9
10    // Strict Mode
11    'use strict';
12  
13    // Constants
14    var NAME = 'parallax';
15    var MAGIC_NUMBER = 30;
16    var DEFAULTS = {
17      relativeInput: false,
18      clipRelativeInput: false,
19      calibrationThreshold: 100,
20      calibrationDelay: 500,
21      supportDelay: 500,
22      calibrateX: false,
23      calibrateY: true,
24      invertX: true,
25      invertY: true,
26      limitX: false,
27      limitY: false,
28      scalarX: 10.0,
29      scalarY: 10.0,
30      frictionX: 0.1,
31      frictionY: 0.1,
32      originX: 0.5,
33      originY: 0.5,
34      pointerEvents: true,
35      precision: 1
36    };
37  
38    function Plugin(element, options) {
39  
40      // DOM Context
41      this.element = element;
42  
43      // Selections
44      this.$context = $(element).data('api', this);
45      this.$layers = this.$context.find('.layer');
46  
47      // Data Extraction
48      var data = {
49        calibrateX: this.$context.data('calibrate-x') || null,
50        calibrateY: this.$context.data('calibrate-y') || null,
51        invertX: this.$context.data('invert-x') || null,
52        invertY: this.$context.data('invert-y') || null,
53        limitX: parseFloat(this.$context.data('limit-x')) || null,
54        limitY: parseFloat(this.$context.data('limit-y')) || null,
55        scalarX: parseFloat(this.$context.data('scalar-x')) || null,
56        scalarY: parseFloat(this.$context.data('scalar-y')) || null,
57        frictionX: parseFloat(this.$context.data('friction-x')) || null,
58        frictionY: parseFloat(this.$context.data('friction-y')) || null,
59        originX: parseFloat(this.$context.data('origin-x')) || null,
60        originY: parseFloat(this.$context.data('origin-y')) || null,
61        pointerEvents: this.$context.data('pointer-events') || true,
62        precision: parseFloat(this.$context.data('precision')) || 1
63      };
64  
65      // Delete Null Data Values
66      for (var key in data) {
67        if (data[key] === null) delete data[key];
68      }
69  
70      // Compose Settings Object
71      $.extend(this, DEFAULTS, options, data);
72  
73      // States
74      this.calibrationTimer = null;
75      this.calibrationFlag = true;
76      this.enabled = false;
77      this.depthsX = [];
78      this.depthsY = [];
79      this.raf = null;
80  
81      // Element Bounds
82      this.bounds = null;
83      this.ex = 0;
84      this.ey = 0;
85      this.ew = 0;
86      this.eh = 0;
87  
88      // Element Center
89      this.ecx = 0;
90      this.ecy = 0;
91  
92      // Element Range
93      this.erx = 0;
94      this.ery = 0;
95  
96      // Calibration
97      this.cx = 0;
98      this.cy = 0;
99  
100      // Input
101      this.ix = 0;
102      this.iy = 0;
103  
104      // Motion
105      this.mx = 0;
106      this.my = 0;
107  
108      // Velocity
109      this.vx = 0;
110      this.vy = 0;
111  
112      // Callbacks
113      this.onMouseMove = this.onMouseMove.bind(this);
114      this.onDeviceOrientation = this.onDeviceOrientation.bind(this);
115      this.onOrientationTimer = this.onOrientationTimer.bind(this);
116      this.onCalibrationTimer = this.onCalibrationTimer.bind(this);
117      this.onAnimationFrame = this.onAnimationFrame.bind(this);
118      this.onWindowResize = this.onWindowResize.bind(this);
119  
120      // Initialise
121      this.initialise();
122    }
123  
124    Plugin.prototype.transformSupport = function(value) {
125      var element = document.createElement('div');
126      var propertySupport = false;
127      var propertyValue = null;
128      var featureSupport = false;
129      var cssProperty = null;
130      var jsProperty = null;
131      for (var i = 0, l = this.vendors.length; i < l; i++) {
132        if (this.vendors[i] !== null) {
133          cssProperty = this.vendors[i][0] + 'transform';
134          jsProperty = this.vendors[i][1] + 'Transform';
135        } else {
136          cssProperty = 'transform';
137          jsProperty = 'transform';
138        }
139        if (element.style[jsProperty] !== undefined) {
140          propertySupport = true;
141          break;
142        }
143      }
144      switch(value) {
145        case '2D':
146          featureSupport = propertySupport;
147          break;
148        case '3D':
149          if (propertySupport) {
150            var body = document.body || document.createElement('body');
151            var documentElement = document.documentElement;
152            var documentOverflow = documentElement.style.overflow;
153            var isCreatedBody = false;
154            if (!document.body) {
155              isCreatedBody = true;
156              documentElement.style.overflow = 'hidden';
157              documentElement.appendChild(body);
158              body.style.overflow = 'hidden';
159              body.style.background = '';
160            }
161            body.appendChild(element);
162            element.style[jsProperty] = 'translate3d(1px,1px,1px)';
163            propertyValue = window.getComputedStyle(element).getPropertyValue(cssProperty);
164            featureSupport = propertyValue !== undefined && propertyValue.length >
164 0 && propertyValue !== "none";
165            documentElement.style.overflow = documentOverflow;
166            body.removeChild(element);
167            if ( isCreatedBody ) {
168              body.removeAttribute('style');
169              body.parentNode.removeChild(body);
170            }
171          }
172          break;
173      }
174      return featureSupport;
175    };
176  
177    Plugin.prototype.ww = null;
178    Plugin.prototype.wh = null;
179    Plugin.prototype.wcx = null;
180    Plugin.prototype.wcy = null;
181    Plugin.prototype.wrx = null;
182    Plugin.prototype.wry = null;
183    Plugin.prototype.portrait = null;
184    Plugin.prototype.desktop = !navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i);
185    Plugin.prototype.vendors = [null,['-webkit-','webkit'],['-moz-','Moz'],['-o-','O'],['-ms-','ms']];
186    Plugin.prototype.motionSupport = !!window.DeviceMotionEvent;
187    Plugin.prototype.orientationSupport = !!window.DeviceOrientationEvent;
188    Plugin.prototype.orientationStatus = 0;
189    Plugin.prototype.transform2DSupport = Plugin.prototype.transformSupport('2D');
190    Plugin.prototype.transform3DSupport = Plugin.prototype.transformSupport('3D');
191    Plugin.prototype.propertyCache = {};
192  
193    Plugin.prototype.initialise = function() {
194  
195      // Configure Styles
196      if (this.$context.css('position') === 'static') {
197        this.$context.css({
198          position:'relative'
199        });
200      }
201  
202      // Pointer events
203      if(!this.pointerEvents){
204        this.$context.css({
205          pointerEvents: 'none'
206        });
207      }
208  
209      // Hardware Accelerate Context
210      this.accelerate(this.$context);
211  
212      // Setup
213      this.updateLayers();
214      this.updateDimensions();
215      this.enable();
216      this.queueCalibration(this.calibrationDelay);
217    };
218  
219    Plugin.prototype.updateLayers = function() {
220  
221      // Cache Layer Elements
222      this.$layers = this.$context.find('.layer');
223      this.depthsX = [];
224      this.depthsY = [];
225  
226      // Configure Layer Styles
227      this.$layers.css({
228        position:'absolute',
229        display:'block',
230        left: 0,
231        top: 0
232      });
233      this.$layers.first().css({
234        position:'relative'
235      });
236  
237      // Hardware Accelerate Layers
238      this.accelerate(this.$layers);
239  
240      // Cache Depths
241      this.$layers.each($.proxy(function(index, element) {
242        //Graceful fallback on depth if depth-x or depth-y is absent
243        var depth = $(element).data('depth') || 0;
244        this.depthsX.push($(element).data('depth-x') || depth);
245        this.depthsY.push($(element).data('depth-y') || depth);
246      }, this));
247    };
248  
249    Plugin.prototype.updateDimensions = function() {
250      this.ww = window.innerWidth;
251      this.wh = window.innerHeight;
252      this.wcx = this.ww * this.originX;
253      this.wcy = this.wh * this.originY;
254      this.wrx = Math.max(this.wcx, this.ww - this.wcx);
255      this.wry = Math.max(this.wcy, this.wh - this.wcy);
256    };
257  
258    Plugin.prototype.updateBounds = function() {
259      this.bounds = this.element.getBoundingClientRect();
260      this.ex = this.bounds.left;
261      this.ey = this.bounds.top;
262      this.ew = this.bounds.width;
263      this.eh = this.bounds.height;
264      this.ecx = this.ew * this.originX;
265      this.ecy = this.eh * this.originY;
266      this.erx = Math.max(this.ecx, this.ew - this.ecx);
267      this.ery = Math.max(this.ecy, this.eh - this.ecy);
268    };
269  
270    Plugin.prototype.queueCalibration = function(delay) {
271      clearTimeout(this.calibrationTimer);
272      this.calibrationTimer = setTimeout(this.onCalibrationTimer, delay);
273    };
274  
275    Plugin.prototype.enable = function() {
276      if (!this.enabled) {
277        this.enabled = true;
278        if (this.orientationSupport) {
279          this.portrait = null;
280          window.addEventListener('deviceorientation', this.onDeviceOrientation);
281          setTimeout(this.onOrientationTimer, this.supportDelay);
282        } else {
283          this.cx = 0;
284          this.cy = 0;
285          this.portrait = false;
286          window.addEventListener('mousemove', this.onMouseMove);
287        }
288        window.addEventListener('resize', this.onWindowResize);
289        this.raf = requestAnimationFrame(this.onAnimationFrame);
290      }
291    };
292  
293    Plugin.prototype.disable = function() {
294      if (this.enabled) {
295        this.enabled = false;
296        if (this.orientationSupport) {
297          window.removeEventListener('deviceorientation', this.onDeviceOrientation);
298        } else {
299          window.removeEventListener('mousemove', this.onMouseMove);
300        }
301        window.removeEventListener('resize', this.onWindowResize);
302        cancelAnimationFrame(this.raf);
303      }
304    };
305  
306    Plugin.prototype.calibrate = function(x, y) {
307      this.calibrateX = x === undefined ? this.calibrateX : x;
308      this.calibrateY = y === undefined ? this.calibrateY : y;
309    };
310  
311    Plugin.prototype.invert = function(x, y) {
312      this.invertX = x === undefined ? this.invertX : x;
313      this.invertY = y === undefined ? this.invertY : y;
314    };
315  
316    Plugin.prototype.friction = function(x, y) {
317      this.frictionX = x === undefined ? this.frictionX : x;
318      this.frictionY = y === undefined ? this.frictionY : y;
319    };
320  
321    Plugin.prototype.scalar = function(x, y) {
322      this.scalarX = x === undefined ? this.scalarX : x;
323      this.scalarY = y === undefined ? this.scalarY : y;
324    };
325  
326    Plugin.prototype.limit = function(x, y) {
327      this.limitX = x === undefined ? this.limitX : x;
328      this.limitY = y === undefined ? this.limitY : y;
329    };
330  
331    Plugin.prototype.origin = function(x, y) {
332      this.originX = x === undefined ? this.originX : x;
333      this.originY = y === undefined ? this.originY : y;
334    };
335  
336    Plugin.prototype.clamp = function(value, min, max) {
337      value = Math.max(value, min);
338      value = Math.min(value, max);
339      return value;
340    };
341  
342    Plugin.prototype.css = function(element, property, value) {
343      var jsProperty = this.propertyCache[property];
344      if (!jsProperty) {
345        for (var i = 0, l = this.vendors.length; i < l; i++) {
346          if (this.vendors[i] !== null) {
347            jsProperty = $.camelCase(this.vendors[i][1] + '-' + property);
348          } else {
349            jsProperty = property;
350          }
351          if (element.style[jsProperty] !== undefined) {
352            this.propertyCache[property] = jsProperty;
353            break;
354          }
355        }
356      }
357      element.style[jsProperty] = value;
358    };
359  
360    Plugin.prototype.accelerate = function($element) {
361      for (var i = 0, l = $element.length; i < l; i++) {
362        var element = $element[i];
363        this.css(element, 'transform', 'translate3d(0,0,0)');
364        this.css(element, 'transform-style', 'preserve-3d');
365        this.css(element, 'backface-visibility', 'hidden');
366      }
367    };
368  
369    Plugin.prototype.setPosition = function(element, x, y) {
370      x += 'px';
371      y += 'px';
372      if (this.transform3DSupport) {
373        this.css(element, 'transform', 'translate3d('+x+','+y+',0)');
374      } else if (this.transform2DSupport) {
375        this.css(element, 'transform', 'translate('+x+','+y+')');
376      } else {
377        element.style.left = x;
378        element.style.top = y;
379      }
380    };
381  
382    Plugin.prototype.onOrientationTimer = function(event) {
383      if (this.orientationSupport && this.orientationStatus === 0) {
384        this.disable();
385        this.orientationSupport = false;
386        this.enable();
387      }
388    };
389  
390    Plugin.prototype.onCalibrationTimer = function(event) {
391      this.calibrationFlag = true;
392    };
393  
394    Plugin.prototype.onWindowResize = function(event) {
395      this.updateDimensions();
396    };
397  
398    Plugin.prototype.onAnimationFrame = function() {
399      this.updateBounds();
400      var dx = this.ix - this.cx;
401      var dy = this.iy - this.cy;
402      if ((Math.abs(dx) > this.calibrationThreshold) || (Math.abs(dy) > this.calibrationThreshold)) {
403        this.queueCalibration(0);
404      }
405      if (this.portrait) {
406        this.mx = this.calibrateX ? dy : this.iy;
407        this.my = this.calibrateY ? dx : this.ix;
408      } else {
409        this.mx = this.calibrateX ? dx : this.ix;
410        this.my = this.calibrateY ? dy : this.iy;
411      }
412      this.mx *= this.ew * (this.scalarX / 100);
413      this.my *= this.eh * (this.scalarY / 100);
414      if (!isNaN(parseFloat(this.limitX))) {
415        this.mx = this.clamp(this.mx, -this.limitX, this.limitX);
416      }
417      if (!isNaN(parseFloat(this.limitY))) {
418        this.my = this.clamp(this.my, -this.limitY, this.limitY);
419      }
420      this.vx += (this.mx - this.vx) * this.frictionX;
421      this.vy += (this.my - this.vy) * this.frictionY;
422      for (var i = 0, l = this.$layers.length; i < l; i++) {
423        var depthX = this.depthsX[i];
424        var depthY = this.depthsY[i];
425        var layer = this.$layers[i];
426        var xOffset = this.vx * (depthX * (this.invertX ? -1 : 1));
427        var yOffset = this.vy * (depthY * (this.invertY ? -1 : 1));
428        this.setPosition(layer, xOffset, yOffset);
429      }
430      this.raf = requestAnimationFrame(this.onAnimationFrame);
431    };
432  
433    Plugin.prototype.onDeviceOrientation = function(event) {
434  
435      // Validate environment and event properties.
436      if (!this.desktop && event.beta !== null && event.gamma !== null) {
437  
438        // Set orientation status.
439        this.orientationStatus = 1;
440  
441        // Extract Rotation
442        var x = (event.beta  || 0) / MAGIC_NUMBER; //  -90 :: 90
443        var y = (event.gamma || 0) / MAGIC_NUMBER; // -180 :: 180
444  
445        // Detect Orientation Change
446        var portrait = window.innerHeight > window.innerWidth;
447        if (this.portrait !== portrait) {
448          this.portrait = portrait;
449          this.calibrationFlag = true;
450        }
451  
452        // Set Calibration
453        if (this.calibrationFlag) {
454          this.calibrationFlag = false;
455          this.cx = x;
456          this.cy = y;
457        }
458  
459        // Set Input
460        this.ix = x;
461        this.iy = y;
462      }
463    };
464  
465    Plugin.prototype.onMouseMove = function(event) {
466  
467      // Cache mouse coordinates.
468      var clientX = event.clientX;
469      var clientY = event.clientY;
470  
471      // Calculate Mouse Input
472      if (!this.orientationSupport && this.relativeInput) {
473  
474        // Clip mouse coordinates inside element bounds.
475        if (this.clipRelativeInput) {
476          clientX = Math.max(clientX, this.ex);
477          clientX = Math.min(clientX, this.ex + this.ew);
478          clientY = Math.max(clientY, this.ey);
479          clientY = Math.min(clientY, this.ey + this.eh);
480        }
481  
482        // Calculate input relative to the element.
483        this.ix = (clientX - this.ex - this.ecx) / this.erx;
484        this.iy = (clientY - this.ey - this.ecy) / this.ery;
485  
486      } else {
487  
488        // Calculate input relative to the window.
489        this.ix = (clientX - this.wcx) / this.wrx;
490        this.iy = (clientY - this.wcy) / this.wry;
491      }
492    };
493  
494    var API = {
495      enable: Plugin.prototype.enable,
496      disable: Plugin.prototype.disable,
497      updateLayers: Plugin.prototype.updateLayers,
498      calibrate: Plugin.prototype.calibrate,
499      friction: Plugin.prototype.friction,
500      invert: Plugin.prototype.invert,
501      scalar: Plugin.prototype.scalar,
502      limit: Plugin.prototype.limit,
503      origin: Plugin.prototype.origin
504    };
505  
506    $.fn[NAME] = function (value) {
507      var args = arguments;
508      return this.each(function () {
509        var $this = $(this);
510        var plugin = $this.data(NAME);
511        if (!plugin) {
512          plugin = new Plugin(this, value);
513          $this.data(NAME, plugin);
514        }
515        if (API[value]) {
516          plugin[value].apply(plugin, Array.prototype.slice.call(args, 1));
517        }
518      });
519    };
520  
521  })(window.jQuery || window.Zepto, 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.