Last active
August 4, 2016 06:28
-
-
Save razwan/4a6db4f564255f1d92133088ef264192 to your computer and use it in GitHub Desktop.
jQuery Parallax Plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// the semi-colon before the function invocation is a safety | |
// net against concatenated scripts and/or other plugins | |
// that are not closed properly. | |
;(function ($, window, document, undefined) { | |
var windowHeight = $(window).height(), | |
lastKnownScrollY; | |
$(window).on('resize', function(e) { | |
windowHeight = $(window).height(); | |
}); | |
$(window).on('load scroll', function(e) { | |
lastKnownScrollY = $(e.target).scrollTop(); | |
}); | |
// constructor | |
function PluginName(element, options) { | |
this.element = element; | |
// jQuery has an extend method that merges the | |
// contents of two or more objects, storing the | |
// result in the first object. The first object | |
// is generally empty because we don't want to alter | |
// the default options for future instances of the plugin | |
this.options = $.extend({}, $.fn.pluginName.defaults, options); | |
// save this into another variable ie. self | |
// so we can acces it scoped functions like event handlers | |
var self = this, | |
$el = $(this.element), | |
myAmount; | |
// override plugin options at element level via data-attirbutes | |
myAmount = $el.data('parallaxamount'); | |
this.isContainer = $el.is(self.options.containerSelector); | |
this.$parent = $el.parent().closest(self.options.containerSelector); | |
this.options.amount = myAmount != undefined ? parseFloat(myAmount) : this.options.amount; | |
// if (this.options.amount == 0) return; | |
$(window).on('load resize', function(e) { | |
self._reloadElement(); | |
self._updatePosition(); | |
}); | |
$(window).on('load scroll', function(e) { | |
// this should apply only to background elements | |
// if (self._isInViewport()) { | |
self._updatePosition(); | |
// } | |
}); | |
} | |
$.extend(PluginName.prototype, { | |
constructor: PluginName, | |
_reloadElement: function() { | |
var self = this, | |
$el = $(this.element).removeAttr('style'); | |
if ( self.$parent ) { | |
self.$parent.css('position', 'static'); | |
// } else { | |
// $el.css('position', ''); | |
} | |
self.width = $el.width(); | |
self.height = $el.height(); | |
self.offset = $el.offset(); | |
if ( self.isContainer ) { | |
self.width += 2 * self.options.gutter; | |
self.height += 2 * self.options.gutter; | |
self.offset.left -= self.options.gutter; | |
self.offset.top -= self.options.gutter; | |
} | |
if ( self.$parent ) { | |
self.$parent.css({ | |
position: 'fixed', | |
overflow: 'hidden', | |
zIndex: -1 | |
}); | |
} | |
$el.css({ | |
position: 'fixed', | |
top: self.offset.top, | |
left: self.offset.left, | |
width: self.width, | |
height: self.height, | |
marginTop: 0, | |
marginLeft: 0 | |
}); | |
}, | |
_isInViewport: function() { | |
return lastKnownScrollY > this.offset.top - windowHeight && lastKnownScrollY < this.offset.top + this.height | |
}, | |
_updatePosition: function() { | |
var self = this, | |
progress = (lastKnownScrollY - this.offset.top + windowHeight) / (windowHeight + this.height), | |
move = (windowHeight + this.height) * (progress - 0.5); | |
// if element is in viewport | |
if (lastKnownScrollY > this.offset.top - windowHeight + move && lastKnownScrollY < this.offset.top + this.height + move) { | |
if ( !self.$parent.length && !self.isVisible ) { | |
$(self.element).show(); | |
self.isVisible = true; | |
} | |
requestAnimationFrame(function() { | |
if (self.isContainer) { | |
$(self.element).css('transform', 'translate3d(0,' + (-lastKnownScrollY) + 'px,0)'); | |
$(self.element).find('[data-parallaxtarget]').css('top', lastKnownScrollY * self.options.amount); | |
} else { | |
$(self.element).css('transform', 'translate3d(0,' + (move * self.options.amount - lastKnownScrollY) + 'px,0)'); | |
} | |
}); | |
} else { | |
if ( !self.$parent.length && self.isVisible ) { | |
$(self.element).hide(); | |
self.isVisible = false; | |
} | |
} | |
} | |
}); | |
$.fn.pluginName = function ( options ) { | |
return this.each(function () { | |
if ( ! $.data(this, "plugin_" + PluginName) ) { | |
$.data(this, "plugin_" + PluginName, new PluginName( this, options )); | |
} | |
}); | |
} | |
$.fn.pluginName.defaults = { | |
amount: 0.5, | |
gutter: 10, | |
containerSelector: '[data-parallaxcontainer]' | |
}; | |
})( jQuery, window, document ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment