JAVASCRIPT   69

parallax.js

Guest on 6th August 2021 06:43:29 PM

  1. /*!
  2.  * parallax.js v1.4.2 (http://pixelcog.github.io/parallax.js/)
  3.  * @copyright 2016 PixelCog, Inc.
  4.  * @license MIT (https://github.com/pixelcog/parallax.js/blob/master/LICENSE)
  5.  */
  6.  
  7. ;(function ( $, window, document, undefined ) {
  8.  
  9.   // Polyfill for requestAnimationFrame
  10.   // via: https://gist.github.com/paulirish/1579671
  11.  
  12.   (function() {
  13.     var lastTime = 0;
  14.     var vendors = ['ms', 'moz', 'webkit', 'o'];
  15.     for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  16.       window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
  17.       window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
  18.         || window[vendors[x]+'CancelRequestAnimationFrame'];
  19.     }
  20.  
  21.     if (!window.requestAnimationFrame)
  22.       window.requestAnimationFrame = function(callback) {
  23.         var currTime = new Date().getTime();
  24.         var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  25.         var id = window.setTimeout(function() { callback(currTime + timeToCall); },
  26.           timeToCall);
  27.         lastTime = currTime + timeToCall;
  28.         return id;
  29.       };
  30.  
  31.     if (!window.cancelAnimationFrame)
  32.       window.cancelAnimationFrame = function(id) {
  33.         clearTimeout(id);
  34.       };
  35.   }());
  36.  
  37.  
  38.   // Parallax Constructor
  39.  
  40.   function Parallax(element, options) {
  41.     var self = this;
  42.  
  43.     if (typeof options == 'object') {
  44.       delete options.refresh;
  45.       delete options.render;
  46.       $.extend(this, options);
  47.     }
  48.  
  49.     this.$element = $(element);
  50.  
  51.     if (!this.imageSrc && this.$element.is('img')) {
  52.       this.imageSrc = this.$element.attr('src');
  53.     }
  54.  
  55.     var positions = (this.position + '').toLowerCase().match(/\S+/g) || [];
  56.  
  57.     if (positions.length < 1) {
  58.       positions.push('center');
  59.     }
  60.     if (positions.length == 1) {
  61.       positions.push(positions[0]);
  62.     }
  63.  
  64.     if (positions[0] == 'top' || positions[0] == 'bottom' || positions[1] == 'left' || positions[1] == 'right') {
  65.       positions = [positions[1], positions[0]];
  66.     }
  67.  
  68.     if (this.positionX != undefined) positions[0] = this.positionX.toLowerCase();
  69.     if (this.positionY != undefined) positions[1] = this.positionY.toLowerCase();
  70.  
  71.     self.positionX = positions[0];
  72.     self.positionY = positions[1];
  73.  
  74.     if (this.positionX != 'left' && this.positionX != 'right') {
  75.       if (isNaN(parseInt(this.positionX))) {
  76.         this.positionX = 'center';
  77.       } else {
  78.         this.positionX = parseInt(this.positionX);
  79.       }
  80.     }
  81.  
  82.     if (this.positionY != 'top' && this.positionY != 'bottom') {
  83.       if (isNaN(parseInt(this.positionY))) {
  84.         this.positionY = 'center';
  85.       } else {
  86.         this.positionY = parseInt(this.positionY);
  87.       }
  88.     }
  89.  
  90.     this.position =
  91.       this.positionX + (isNaN(this.positionX)? '' : 'px') + ' ' +
  92.       this.positionY + (isNaN(this.positionY)? '' : 'px');
  93.  
  94.     if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
  95.       if (this.imageSrc && this.iosFix && !this.$element.is('img')) {
  96.         this.$element.css({
  97.           backgroundImage: 'url(' + this.imageSrc + ')',
  98.           backgroundSize: 'cover',
  99.           backgroundPosition: this.position
  100.         });
  101.       }
  102.       return this;
  103.     }
  104.  
  105.     if (navigator.userAgent.match(/(Android)/)) {
  106.       if (this.imageSrc && this.androidFix && !this.$element.is('img')) {
  107.         this.$element.css({
  108.           backgroundImage: 'url(' + this.imageSrc + ')',
  109.           backgroundSize: 'cover',
  110.           backgroundPosition: this.position
  111.         });
  112.       }
  113.       return this;
  114.     }
  115.  
  116.     this.$mirror = $('<div />').prependTo('body');
  117.  
  118.     var slider = this.$element.find('>.parallax-slider');
  119.     var sliderExisted = false;
  120.  
  121.     if (slider.length == 0)
  122.       this.$slider = $('<img />').prependTo(this.$mirror);
  123.     else {
  124.       this.$slider = slider.prependTo(this.$mirror)
  125.       sliderExisted = true;
  126.     }
  127.  
  128.     this.$mirror.addClass('parallax-mirror').css({
  129.       visibility: 'hidden',
  130.       zIndex: this.zIndex,
  131.       position: 'fixed',
  132.       top: 0,
  133.       left: 0,
  134.       overflow: 'hidden'
  135.     });
  136.  
  137.     this.$slider.addClass('parallax-slider').one('load', function() {
  138.       if (!self.naturalHeight || !self.naturalWidth) {
  139.         self.naturalHeight = this.naturalHeight || this.height || 1;
  140.         self.naturalWidth  = this.naturalWidth  || this.width  || 1;
  141.       }
  142.       self.aspectRatio = self.naturalWidth / self.naturalHeight;
  143.  
  144.       Parallax.isSetup || Parallax.setup();
  145.       Parallax.sliders.push(self);
  146.       Parallax.isFresh = false;
  147.       Parallax.requestRender();
  148.     });
  149.  
  150.     if (!sliderExisted)
  151.       this.$slider[0].src = this.imageSrc;
  152.  
  153.     if (this.naturalHeight && this.naturalWidth || this.$slider[0].complete || slider.length > 0) {
  154.       this.$slider.trigger('load');
  155.     }
  156.  
  157.   };
  158.  
  159.  
  160.   // Parallax Instance Methods
  161.  
  162.   $.extend(Parallax.prototype, {
  163.     speed:    0.2,
  164.     bleed:    0,
  165.     zIndex:   -100,
  166.     iosFix:   true,
  167.     androidFix: true,
  168.     position: 'center',
  169.     overScrollFix: false,
  170.  
  171.     refresh: function() {
  172.       this.boxWidth        = this.$element.outerWidth();
  173.       this.boxHeight       = this.$element.outerHeight() + this.bleed * 2;
  174.       this.boxOffsetTop    = this.$element.offset().top - this.bleed;
  175.       this.boxOffsetLeft   = this.$element.offset().left;
  176.       this.boxOffsetBottom = this.boxOffsetTop + this.boxHeight;
  177.  
  178.       var winHeight = Parallax.winHeight;
  179.       var docHeight = Parallax.docHeight;
  180.       var maxOffset = Math.min(this.boxOffsetTop, docHeight - winHeight);
  181.       var minOffset = Math.max(this.boxOffsetTop + this.boxHeight - winHeight, 0);
  182.       var imageHeightMin = this.boxHeight + (maxOffset - minOffset) * (1 - this.speed) | 0;
  183.       var imageOffsetMin = (this.boxOffsetTop - maxOffset) * (1 - this.speed) | 0;
  184.  
  185.       if (imageHeightMin * this.aspectRatio >= this.boxWidth) {
  186.         this.imageWidth    = imageHeightMin * this.aspectRatio | 0;
  187.         this.imageHeight   = imageHeightMin;
  188.         this.offsetBaseTop = imageOffsetMin;
  189.  
  190.         var margin = this.imageWidth - this.boxWidth;
  191.  
  192.         if (this.positionX == 'left') {
  193.           this.offsetLeft = 0;
  194.         } else if (this.positionX == 'right') {
  195.           this.offsetLeft = - margin;
  196.         } else if (!isNaN(this.positionX)) {
  197.           this.offsetLeft = Math.max(this.positionX, - margin);
  198.         } else {
  199.           this.offsetLeft = - margin / 2 | 0;
  200.         }
  201.       } else {
  202.         this.imageWidth    = this.boxWidth;
  203.         this.imageHeight   = this.boxWidth / this.aspectRatio | 0;
  204.         this.offsetLeft    = 0;
  205.  
  206.         var margin = this.imageHeight - imageHeightMin;
  207.  
  208.         if (this.positionY == 'top') {
  209.           this.offsetBaseTop = imageOffsetMin;
  210.         } else if (this.positionY == 'bottom') {
  211.           this.offsetBaseTop = imageOffsetMin - margin;
  212.         } else if (!isNaN(this.positionY)) {
  213.           this.offsetBaseTop = imageOffsetMin + Math.max(this.positionY, - margin);
  214.         } else {
  215.           this.offsetBaseTop = imageOffsetMin - margin / 2 | 0;
  216.         }
  217.       }
  218.     },
  219.  
  220.     render: function() {
  221.       var scrollTop    = Parallax.scrollTop;
  222.       var scrollLeft   = Parallax.scrollLeft;
  223.       var overScroll   = this.overScrollFix ? Parallax.overScroll : 0;
  224.       var scrollBottom = scrollTop + Parallax.winHeight;
  225.  
  226.       if (this.boxOffsetBottom > scrollTop && this.boxOffsetTop <= scrollBottom) {
  227.         this.visibility = 'visible';
  228.         this.mirrorTop = this.boxOffsetTop  - scrollTop;
  229.         this.mirrorLeft = this.boxOffsetLeft - scrollLeft;
  230.         this.offsetTop = this.offsetBaseTop - this.mirrorTop * (1 - this.speed);
  231.       } else {
  232.         this.visibility = 'hidden';
  233.       }
  234.  
  235.       this.$mirror.css({
  236.         transform: 'translate3d(0px, 0px, 0px)',
  237.         visibility: this.visibility,
  238.         top: this.mirrorTop - overScroll,
  239.         left: this.mirrorLeft,
  240.         height: this.boxHeight,
  241.         width: this.boxWidth
  242.       });
  243.  
  244.       this.$slider.css({
  245.         transform: 'translate3d(0px, 0px, 0px)',
  246.         position: 'absolute',
  247.         top: this.offsetTop,
  248.         left: this.offsetLeft,
  249.         height: this.imageHeight,
  250.         width: this.imageWidth,
  251.         maxWidth: 'none'
  252.       });
  253.     }
  254.   });
  255.  
  256.  
  257.   // Parallax Static Methods
  258.  
  259.   $.extend(Parallax, {
  260.     scrollTop:    0,
  261.     scrollLeft:   0,
  262.     winHeight:    0,
  263.     winWidth:     0,
  264.     docHeight:    1 << 30,
  265.     docWidth:     1 << 30,
  266.     sliders:      [],
  267.     isReady:      false,
  268.     isFresh:      false,
  269.     isBusy:       false,
  270.  
  271.     setup: function() {
  272.       if (this.isReady) return;
  273.  
  274.       var $doc = $(document), $win = $(window);
  275.  
  276.       var loadDimensions = function() {
  277.         Parallax.winHeight = $win.height();
  278.         Parallax.winWidth  = $win.width();
  279.         Parallax.docHeight = $doc.height();
  280.         Parallax.docWidth  = $doc.width();
  281.       };
  282.  
  283.       var loadScrollPosition = function() {
  284.         var winScrollTop  = $win.scrollTop();
  285.         var scrollTopMax  = Parallax.docHeight - Parallax.winHeight;
  286.         var scrollLeftMax = Parallax.docWidth  - Parallax.winWidth;
  287.         Parallax.scrollTop  = Math.max(0, Math.min(scrollTopMax,  winScrollTop));
  288.         Parallax.scrollLeft = Math.max(0, Math.min(scrollLeftMax, $win.scrollLeft()));
  289.         Parallax.overScroll = Math.max(winScrollTop - scrollTopMax, Math.min(winScrollTop, 0));
  290.       };
  291.  
  292.       $win.on('resize.px.parallax load.px.parallax', function() {
  293.           loadDimensions();
  294.           Parallax.isFresh = false;
  295.           Parallax.requestRender();
  296.         })
  297.         .on('scroll.px.parallax load.px.parallax', function() {
  298.           loadScrollPosition();
  299.           Parallax.requestRender();
  300.         });
  301.  
  302.       loadDimensions();
  303.       loadScrollPosition();
  304.  
  305.       this.isReady = true;
  306.     },
  307.  
  308.     configure: function(options) {
  309.       if (typeof options == 'object') {
  310.         delete options.refresh;
  311.         delete options.render;
  312.         $.extend(this.prototype, options);
  313.       }
  314.     },
  315.  
  316.     refresh: function() {
  317.       $.each(this.sliders, function(){ this.refresh() });
  318.       this.isFresh = true;
  319.     },
  320.  
  321.     render: function() {
  322.       this.isFresh || this.refresh();
  323.       $.each(this.sliders, function(){ this.render() });
  324.     },
  325.  
  326.     requestRender: function() {
  327.       var self = this;
  328.  
  329.       if (!this.isBusy) {
  330.         this.isBusy = true;
  331.         window.requestAnimationFrame(function() {
  332.           self.render();
  333.           self.isBusy = false;
  334.         });
  335.       }
  336.     },
  337.     destroy: function(el){
  338.       var i,
  339.           parallaxElement = $(el).data('px.parallax');
  340.       parallaxElement.$mirror.remove();
  341.       for(i=0; i < this.sliders.length; i+=1){
  342.         if(this.sliders[i] == parallaxElement){
  343.           this.sliders.splice(i, 1);
  344.         }
  345.       }
  346.       $(el).data('px.parallax', false);
  347.       if(this.sliders.length === 0){
  348.         $(window).off('scroll.px.parallax resize.px.parallax load.px.parallax');
  349.         this.isReady = false;
  350.         Parallax.isSetup = false;
  351.       }
  352.     }
  353.   });
  354.  
  355.  
  356.   // Parallax Plugin Definition
  357.  
  358.   function Plugin(option) {
  359.     return this.each(function () {
  360.       var $this = $(this);
  361.       var options = typeof option == 'object' && option;
  362.  
  363.       if (this == window || this == document || $this.is('body')) {
  364.         Parallax.configure(options);
  365.       }
  366.       else if (!$this.data('px.parallax')) {
  367.         options = $.extend({}, $this.data(), options);
  368.         $this.data('px.parallax', new Parallax(this, options));
  369.       }
  370.       else if (typeof option == 'object')
  371.       {
  372.         $.extend($this.data('px.parallax'), options);
  373.       }
  374.       if (typeof option == 'string') {
  375.         if(option == 'destroy'){
  376.             Parallax['destroy'](this);
  377.         }else{
  378.           Parallax[option]();
  379.         }
  380.       }
  381.     })
  382.   };
  383.  
  384.   var old = $.fn.parallax;
  385.  
  386.   $.fn.parallax             = Plugin;
  387.   $.fn.parallax.Constructor = Parallax;
  388.  
  389.  
  390.   // Parallax No Conflict
  391.  
  392.   $.fn.parallax.noConflict = function () {
  393.     $.fn.parallax = old;
  394.     return this;
  395.   };
  396.  
  397.  
  398.   // Parallax Data-API
  399.  
  400.   $(document).on('ready.px.parallax.data-api', function () {
  401.     $('[data-parallax="scroll"]').parallax();
  402.   });
  403.  
  404. }(jQuery, window, document));

Raw Paste


Login or Register to edit or fork this paste. It's free.