cn.status.im/js/lib/ScrollOver.js

154 lines
3.9 KiB
JavaScript

let Scrllr = require("./Scrllr.js"),
Scale = require("d3-scale"),
Interpolator = require("d3-interpolate"),
Ease = require("d3-ease")
function ScrollOver(options) {
options = extend(options, ScrollOver.options)
this.PROPERTIES = ['translateX', 'translateY', 'opacity', 'scale']
this.keyframes = options.keyframes
}
ScrollOver.prototype = {
constructor : ScrollOver,
init : function() {
new Scrllr({onScrollCallback:update.bind(this)}).init()
this.toAnimate = this.keyframes.filter((item) => {return item.animate})
this.toReveal = this.keyframes.filter((item) => {return item.reveal})
this.toAnimate.forEach((keyframe) => {
if(keyframe) keyframe.animate.forEach((property) => { property.scale = this.createScale(property.property, keyframe.domain, property.range) })
})
function update(scrollY) {
this.toAnimate.forEach((keyframe) => {
if(keyframe) this.updateCSSValues(keyframe.element, this.calculatePropertyValues(keyframe.animate, scrollY))
})
this.toReveal.forEach((keyframe) => {
if(keyframe) {
if(scrollY >= keyframe.reveal.when) this.updateCSSClass(keyframe.element, keyframe.reveal.className)
}
})
}
return this
},
calculatePropertyValues: function(animations, scrollY) {
let CSSValues = new Object()
this.PROPERTIES.forEach((propertyName) => {
CSSValues[propertyName] = this.getDefaultPropertyValue(propertyName)
animations.forEach((animation) => {
if (animation.property == propertyName) CSSValues[propertyName] = this.scaleValue(animation.scale, scrollY)
})
})
return CSSValues
},
scaleValue: function(scale, scrollY) {
return scale(scrollY)
},
updateCSSValues: function(element, CSS) {
element.style.transform = 'translate3d(' + CSS.translateX +'px, ' + CSS.translateY + 'px, 0) scale('+ CSS.scale +')'
element.style.opacity = CSS.opacity
return element
},
updateCSSClass: function(element, className) {
(element.classList) ? element.classList.add(className) : element.className += ' ' + className
return element
},
getDefaultPropertyValue: function(propertyName) {
switch (propertyName) {
case 'translateX':
return 0
case 'translateY':
return 0
case 'scale':
return 1
case 'rotate':
return 0
case 'opacity':
return 1
default:
return null
}
},
createScale: function(propertyName, domain, range) {
switch (propertyName) {
case 'translateX':
case 'translateY':
case 'scale':
case 'opacity':
return Scale.scaleLinear().domain(domain).range(range).interpolate(this.easeInterpolate(Ease.easeCubicOut)).clamp(true)
default:
return null
}
},
easeInterpolate: function(ease) {
return function(a, b) {
var i = Interpolator.interpolate(a, b)
return function(t) {
return (Math.round(i(ease(t)) * 100) / 100)
}
}
}
}
ScrollOver.options = {
keyframes : {}
}
/**
* Helper function for extending objects
*/
function extend (object /*, objectN ... */) {
if(arguments.length <= 0) {
throw new Error('Missing arguments in extend function');
}
var result = object || {},
key,
i;
for (i = 1; i < arguments.length; i++) {
var replacement = arguments[i] || {};
for (key in replacement) {
// Recurse into object except if the object is a DOM element
if(typeof result[key] === 'object' && ! isDOMElement(result[key])) {
result[key] = extend(result[key], replacement[key]);
}
else {
result[key] = result[key] || replacement[key];
}
}
}
return result;
}
/**
* Check if object is part of the DOM
* @constructor
* @param {Object} obj element to check
*/
function isDOMElement(obj) {
return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType);
}
module.exports = ScrollOver