parallaxis
Version:
A tiny parallax library that updates styles on scroll
338 lines (277 loc) • 9.38 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.parallaxis = factory());
}(this, (function () { 'use strict';
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var performanceNow = createCommonjsModule(function (module) {
// Generated by CoffeeScript 1.7.1
(function() {
var getNanoSeconds, hrtime, loadTime;
if ((typeof performance !== "undefined" && performance !== null) && performance.now) {
module.exports = function() {
return performance.now();
};
} else if ((typeof process !== "undefined" && process !== null) && process.hrtime) {
module.exports = function() {
return (getNanoSeconds() - loadTime) / 1e6;
};
hrtime = process.hrtime;
getNanoSeconds = function() {
var hr;
hr = hrtime();
return hr[0] * 1e9 + hr[1];
};
loadTime = getNanoSeconds();
} else if (Date.now) {
module.exports = function() {
return Date.now() - loadTime;
};
loadTime = Date.now();
} else {
module.exports = function() {
return new Date().getTime() - loadTime;
};
loadTime = new Date().getTime();
}
}).call(commonjsGlobal);
});
var root = typeof window === 'undefined' ? commonjsGlobal : window;
var vendors = ['moz', 'webkit'];
var suffix = 'AnimationFrame';
var raf = root['request' + suffix];
var caf = root['cancel' + suffix] || root['cancelRequest' + suffix];
for(var i = 0; !raf && i < vendors.length; i++) {
raf = root[vendors[i] + 'Request' + suffix];
caf = root[vendors[i] + 'Cancel' + suffix]
|| root[vendors[i] + 'CancelRequest' + suffix];
}
// Some versions of FF have rAF but not cAF
if(!raf || !caf) {
var last = 0
, id = 0
, queue = []
, frameDuration = 1000 / 60;
raf = function(callback) {
if(queue.length === 0) {
var _now = performanceNow()
, next = Math.max(0, frameDuration - (_now - last));
last = next + _now;
setTimeout(function() {
var cp = queue.slice(0);
// Clear queue here to prevent
// callbacks from appending listeners
// to the current frame's queue
queue.length = 0;
for(var i = 0; i < cp.length; i++) {
if(!cp[i].cancelled) {
try{
cp[i].callback(last);
} catch(e) {
setTimeout(function() { throw e }, 0);
}
}
}
}, Math.round(next));
}
queue.push({
handle: ++id,
callback: callback,
cancelled: false
});
return id
};
caf = function(handle) {
for(var i = 0; i < queue.length; i++) {
if(queue[i].handle === handle) {
queue[i].cancelled = true;
}
}
};
}
var index = function(fn) {
// Wrap in a new function to prevent
// `cancel` potentially being assigned
// to the native rAF function
return raf.call(root, fn)
};
var cancel = function() {
caf.apply(root, arguments);
};
var polyfill = function() {
root.requestAnimationFrame = raf;
root.cancelAnimationFrame = caf;
};
index.cancel = cancel;
index.polyfill = polyfill;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var cache = new WeakMap();
var difference = function difference(a, b) {
return Math.abs(a - b);
};
var elements = function elements(className) {
var els = [].concat(_toConsumableArray(document.querySelectorAll('.' + className)));
return els.map(function (el) {
var relative = el.dataset.relative === 'true';
var offset = relative ? elY(el) : 0;
var end = parseInt(el.dataset.end, 10);
var start = parseInt(el.dataset.start, 10);
var opacityStart = parseFloat(el.dataset.opacityStart);
var opacityEnd = parseFloat(el.dataset.opacityEnd);
var translateXStart = parseInt(el.dataset.translatexStart, 10);
var translateXEnd = parseInt(el.dataset.translatexEnd, 10);
var translateYStart = parseInt(el.dataset.translateyStart, 10);
var translateYEnd = parseInt(el.dataset.translateyEnd, 10);
var scaleStart = parseFloat(el.dataset.scaleStart);
var scaleEnd = parseFloat(el.dataset.scaleEnd);
var updates = {};
if (!isNaN(opacityStart) && !isNaN(opacityEnd)) {
updates.opacity = {
end: opacityEnd,
start: opacityStart
};
}
if (!isNaN(translateXStart) && !isNaN(translateXEnd)) {
updates.translateX = {
end: translateXEnd,
start: translateXStart
};
}
if (!isNaN(translateYStart) && !isNaN(translateYEnd)) {
updates.translateY = {
end: translateYEnd,
start: translateYStart
};
}
if (!isNaN(scaleStart) && !isNaN(scaleEnd)) {
updates.scale = {
end: scaleEnd,
start: scaleStart
};
}
if (typeof end === 'undefined' || typeof start === 'undefined' || Object.keys(updates) === 0) {
return null;
}
return { el: el, end: end, offset: offset, relative: relative, start: start, updates: updates };
}).filter(function (x) {
return x;
});
};
var elY = function elY(el) {
return scrollY() + el.getBoundingClientRect().top;
};
var init = function init() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$className = _ref.className,
className = _ref$className === undefined ? 'js-parallaxis' : _ref$className;
var els = elements(className);
if (els.length) {
var updateFunc = update(els);
updateOffsetsOnResize(els);
updateFunc();
window.addEventListener('scroll', function () {
return index(updateFunc);
});
}
};
var interpolate = function interpolate(start, end, progress) {
var p = difference(start, end) * progress;
return start > end ? start - p : start + p;
};
var interval = function interval(start, end, current) {
return difference(start, current) / difference(start, end);
};
var limit = function limit(min, max, value) {
return Math.max(Math.min(value, max), min);
};
var prefixedTransformProp = function prefixedTransformProp() {
var el = document.createElement('div');
var vendors = ['Webkit', 'webkit', 'Moz', 'moz', 'ms', 'o'];
if (el.style.transform != null) {
return 'transform';
}
for (var v in vendors) {
var prop = vendors[v] + 'Transform';
if (typeof el.style[prop] !== 'undefined') {
return prop;
}
}
};
var scrollY = function scrollY() {
return parseInt(window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0, 10);
};
var update = function update(els) {
var transformProp = prefixedTransformProp();
return function () {
var y = scrollY();
els.map(function (_ref2) {
var el = _ref2.el,
end = _ref2.end,
offset = _ref2.offset,
start = _ref2.start,
updates = _ref2.updates;
var s = offset + start;
var e = offset + end;
var state = cache.get(el);
if (y >= s && y <= e || state !== 'before' && y < s || state !== 'after' && y > e) {
var translateX = 0;
var translateY = 0;
var scale = 1;
var current = limit(s, e, y);
var i = interval(s, e, current);
if (updates.opacity) {
var _updates$opacity = updates.opacity,
_end = _updates$opacity.end,
_start = _updates$opacity.start;
var opacity = interpolate(_start, _end, i).toFixed(2);
el.style.opacity = opacity;
}
if (updates.translateX) {
var _updates$translateX = updates.translateX,
_end2 = _updates$translateX.end,
_start2 = _updates$translateX.start;
translateX = parseInt(interpolate(_start2, _end2, i), 10);
}
if (updates.translateY) {
var _updates$translateY = updates.translateY,
_end3 = _updates$translateY.end,
_start3 = _updates$translateY.start;
translateY = parseInt(interpolate(_start3, _end3, i), 10);
}
if (updates.scale) {
var _updates$scale = updates.scale,
_end4 = _updates$scale.end,
_start4 = _updates$scale.start;
scale = interpolate(_start4, _end4, i).toFixed(2);
}
el.style[transformProp] = 'translate3d(' + translateX + 'px, ' + translateY + 'px, 0) scale(' + scale + ')';
if (y < s) {
cache.set(el, 'before');
} else if (y > e) {
cache.set(el, 'after');
} else {
cache.set(el, 'during');
}
}
});
};
};
var updateOffsetsOnResize = function updateOffsetsOnResize(els) {
var updateOffsets = function updateOffsets() {
return els.map(function (x) {
if (x.relative) {
x.offset = elY(x.el);
}
});
};
var d = void 0;
window.addEventListener('resize', function () {
window.clearTimeout(d);
d = window.setTimeout(updateOffsets, 50);
});
};
return init;
})));