|
(function () { |
|
var $ = this.jQuery || require('jquery'); |
|
var _ = this._ || require('underscore'); |
|
|
|
var $html = $('html'); |
|
var $window = $(window); |
|
var TRANSFORMPROP = ["transform", "webkitTransform", "MozTransform", "msTransform"].filter(function (prop) { |
|
return prop in document.documentElement.style; |
|
})[0]; |
|
|
|
// |
|
// https://www.html5rocks.com/en/tutorials/speed/animations/?redirect_from_locale=fr#debouncing-scroll-events |
|
// |
|
|
|
var lastScrollY = window.pageYOffset; |
|
function onScroll() { |
|
requestTick(); |
|
|
|
lastScrollY = window.pageYOffset; |
|
} |
|
|
|
var ticking = false; |
|
function requestTick() { |
|
if (!ticking) { |
|
ticking = true; |
|
requestAnimationFrame(update); |
|
} |
|
} |
|
function update() { |
|
var l = instances.length; |
|
|
|
var instance; |
|
while (l--) { |
|
instance = instances[l]; |
|
|
|
var percent = instance.percent(lastScrollY); |
|
instance.draw(percent); |
|
} |
|
|
|
// allow further rAFs to be called |
|
ticking = false; |
|
} |
|
window.addEventListener('scroll', onScroll, false); |
|
|
|
// |
|
// |
|
// |
|
|
|
var instances = []; |
|
|
|
function Parallax(el, options) { |
|
options || (options = {}); |
|
|
|
this.constructor.insertStyle(); |
|
|
|
this.$el = $(el); |
|
this.el = this.$el[0]; |
|
|
|
this.amplitude = options.amplitude || 1; |
|
|
|
// Add .parallax class |
|
this.el.classList.add('parallax'); |
|
|
|
if (this.$el.css('position') === 'static') { |
|
this.$el.css('position', 'relative'); |
|
} |
|
|
|
// Insert pseudo .img div |
|
this.$img = $('<div class="img"/>').css({ |
|
'background-image': this.$el.css('background-image'), |
|
'height': (100*(1+this.amplitude) + '%') |
|
}).prependTo(this.$el); |
|
this.$el.css('background-image', 'none'); |
|
|
|
// |
|
// setDims + resize |
|
// |
|
|
|
$window.on('resize', _.debounce(this.setDims.bind(this), 200)); |
|
|
|
this.$img.on('webkitTransitionEnd mozTransitionEnd oTransitionEnd msTransitionEnd transitionend', _.debounce(function (e) { |
|
//console.log('transitionend', e.target); |
|
|
|
if (!(e.originalEvent.target === this.$img[0] && e.originalEvent.propertyName === 'height')) { |
|
return; |
|
} |
|
|
|
e.originalEvent.stopPropagation(); |
|
|
|
this.setDims(); |
|
}.bind(this), 30)); |
|
this.setDims(); |
|
|
|
// |
|
// initial draw |
|
// |
|
|
|
var percent = this.percent(lastScrollY); |
|
this.draw(percent); |
|
|
|
instances.push(this); |
|
} |
|
Parallax.prototype.setDims = function () { |
|
//console.log('setDims'); |
|
|
|
this.offsettop = this.$el.offset().top, |
|
this.WH = $(window).height(), |
|
this.h = this.$el.outerHeight(); |
|
|
|
this.hh = this.$img.height(); |
|
|
|
this.minoffsettop = this.offsettop - this.WH; |
|
this.maxoffsettop = this.offsettop + this.h; |
|
}; |
|
Parallax.prototype.percent = function (scrolltop) { |
|
var percent = ((this.offsettop - scrolltop) + this.h) / (this.WH + this.h); |
|
|
|
return percent; |
|
}; |
|
Parallax.prototype.draw = function (percent) { |
|
//console.log(percent); |
|
|
|
var pmin = .5-this.amplitude/2; |
|
var pmax = .5+this.amplitude/2; |
|
percent = percent * (pmax - pmin) + pmin; |
|
|
|
var ty = Math.round(-percent*this.hh + (1-percent)*this.h); |
|
if (ty === this._ty) return; |
|
this._ty = ty; |
|
|
|
var t; |
|
if (Parallax.has3d) { |
|
t = 'translate3d(0,' + ty + 'px,0)'; |
|
} else { |
|
t = 'translate(0,' + ty + 'px)'; |
|
} |
|
//console.log(ty); |
|
|
|
if (percent > 0 && percent < 1) { |
|
//this.$img.css('transform', t); |
|
this.$img[0].style[TRANSFORMPROP] = t; |
|
} |
|
}; |
|
|
|
// http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support#answer-12621264 |
|
function has3d() { |
|
var el = document.createElement('p'); |
|
var has3d; |
|
var transforms = { |
|
'webkitTransform':'-webkit-transform', |
|
'OTransform':'-o-transform', |
|
'msTransform':'-ms-transform', |
|
'MozTransform':'-moz-transform', |
|
'transform':'transform' |
|
}; |
|
|
|
// Add it to the body to get the computed style. |
|
document.body.insertBefore(el, null); |
|
|
|
for (var t in transforms) { |
|
if (el.style[t] !== undefined) { |
|
el.style[t] = "translate3d(1px,1px,1px)"; |
|
has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); |
|
} |
|
} |
|
|
|
document.body.removeChild(el); |
|
|
|
return (has3d !== undefined && has3d.length > 0 && has3d !== "none"); |
|
} |
|
Parallax.has3d = has3d(); |
|
|
|
Parallax.css = '' |
|
+ '.parallax {overflow:hidden;}' |
|
+ '.parallax >.img {' |
|
+ ' display:block;width:100%; background-position:center;background-repeat:no-repeat; -webkit-background-size:cover;-moz-background-size:cover;background-size:cover;' |
|
+ ' position:absolute;left:0;top:0;' |
|
+ ' -webkit-transition:height 1ms;-moz-transition:height 1ms;-o-transition:height 1ms;-ms-transition:height 1ms;transition:height 1ms;' |
|
+ ' will-change:transform;' |
|
+ '}' |
|
; |
|
Parallax.insertStyle = function () { |
|
if (this.$style) return; //once |
|
|
|
if (!this.$style) { |
|
this.$style = $('<style/>').text(this.css).appendTo(document.head); |
|
} |
|
}; |
|
|
|
// |
|
// jQuery plugin |
|
// |
|
|
|
$.fn.parallax = function (options) { |
|
this.each(function (i, el) { |
|
var $el = $(el); |
|
|
|
var parallax = new Parallax(el, options); |
|
|
|
$el.data('parallax', parallax); |
|
}); |
|
} |
|
|
|
// |
|
// CommonJS |
|
// |
|
|
|
this.Parallax = Parallax; |
|
if (typeof module !== "undefined" && module !== null) { |
|
module.exports = this.Parallax; |
|
} |
|
}).call(this); |
TODO: PE with http://blog.keithclark.co.uk/pure-css-parallax-websites/