Created
March 31, 2015 16:48
-
-
Save ajmers/3180bd24b2f8016f40d5 to your computer and use it in GitHub Desktop.
This file contains 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
(function() { | |
console.log('gravity'); | |
var triggerGrandparents = []; | |
var z = 1000; | |
var d = document; | |
var origCopies = []; | |
var fallCopies = []; | |
// var logo = document.getElementById('monetate-logo'); | |
var buffer = 0; | |
var balls = {}; | |
var Cd = 0.47; // Dimensionless | |
var rho = 1.22; // kg / m^3 | |
var ag = 9.81; // m / s^ | |
var frameRate = 1 / 40; // Seconds | |
var frameDelay = frameRate * 1000; // ms | |
var winHeight = window.innerHeight; | |
var winWidth = window.innerWidth; | |
function Ball(node) { | |
this.node = node; | |
this.velocity = { | |
x: 0, | |
y: 0 | |
}; | |
this.position = { | |
x: 0, | |
y: 0 | |
}; | |
this.radius = this.node.offsetHeight; | |
this.mass = this.node.offsetHeight * this.node.offsetWidth * 0.1; | |
this.restitution = -0.7; | |
this.reset = function() { | |
this.velocity = { | |
x: 0, | |
y: 0 | |
}; | |
} | |
} | |
function makePlaceholder(origNode) { | |
if (!(/monetate_placeholder/.exec(origNode.className))) { | |
// Clone found node, add classes to both, hide original. | |
var clonedNode = origNode.cloneNode(true); | |
origNode.className += ' monetate_placeholder_hide'; | |
clonedNode.className += ' monetate_placeholder_dup'; | |
clonedNode.style.cssText = 'display: inline-block; position: absolute !important; left: 0px; top: 0px'; | |
origNode.style.visibility = 'hidden'; | |
// Add a wrapper node as previous sibling to found node. | |
var wrapper = document.createElement('div'); | |
wrapper.className = 'monetate_placeholder_wrap'; | |
origNode.parentNode.insertBefore(wrapper, origNode); | |
// Add hidden original node and new cloned version to the wrapper. | |
wrapper.appendChild(origNode); | |
wrapper.appendChild(clonedNode); | |
// Add cloned node to the array to be returned. | |
var ball = new Ball(clonedNode); | |
fallCopies.push(ball); | |
} else { | |
var ball = balls[origNode]; | |
} | |
return ball; | |
} | |
(function setStyles() { | |
var elementStyles = '.monetate_placeholder_wrap { ' + | |
'display: inline-block; width: auto !important; margin: 0 !important; ' + | |
'padding: 0 !important; position: relative; }' + | |
'.monetate_placeholder_hide {visibility: hidden}'; | |
var head = document.head; | |
var e = document.createElement('style'); | |
e.setAttribute('type', 'text/css'); | |
if (e.styleSheet) { //IE | |
e.styleSheet.cssText = elementStyles; | |
} else { //EVERYONE ELSE | |
var stl = document.createTextNode(elementStyles); | |
e.appendChild(stl); | |
} | |
head.appendChild(e); | |
})(); | |
function debounce(func, wait, opt_immediate) { | |
var timeout, result; | |
return function() { | |
var context = this; | |
var args = arguments; | |
var later = function() { | |
timeout = null; | |
if (!opt_immediate) { | |
result = func.apply(context, args); | |
} | |
}; | |
var callNow = opt_immediate && !timeout; | |
window.clearTimeout(timeout); | |
timeout = setTimeout(later, wait); | |
if (callNow) { | |
result = func.apply(context, args); | |
} | |
return result; | |
}; | |
}; | |
function fall(ball) { | |
ball.doneFalling = false; | |
ball.reset(); | |
window.requestAnimationFrame(function innerLoop() { | |
loop(ball); | |
if (!ball.doneFalling) { | |
window.requestAnimationFrame(innerLoop); | |
} | |
}); | |
} | |
var debouncedFall = debounce(fall, 600); | |
function loop(ball) { | |
var box = ball.node.getBoundingClientRect(); | |
var A = Math.PI * ball.radius * ball.radius / (10000); // m^2 | |
// Do physics | |
// Drag force: Fd = -1/2 * Cd * A * rho * v * v | |
// var Fx = -0.5 * Cd * A * rho * ball.velocity.x * ball.velocity.x * ball.velocity.x / Math.abs(ball.velocity.x); | |
var Fy = -0.5 * Cd * A * rho * ball.velocity.y * ball.velocity.y * ball.velocity.y / Math.abs(ball.velocity.y); | |
// Fx = (isNaN(Fx) ? 0 : Fx); | |
Fy = (isNaN(Fy) ? 0 : Fy); | |
if (box.bottom > window.innerHeight && Math.abs(Fy) < .01) { | |
ball.doneFalling = true; | |
} | |
// Calculate acceleration ( F = ma ) | |
// var ax = Fx / ball.mass; | |
var ay = ag + (Fy / ball.mass); | |
// Integrate to get velocity | |
// ball.velocity.x += ax*frameRate; | |
ball.velocity.y += ay * frameRate; | |
// Integrate to get position | |
// ball.position.x += ball.velocity.x*frameRate*100; | |
ball.position.y += ball.velocity.y * frameRate * 100; | |
ball.node.style.top = ball.position.y + 'px'; | |
// Handle collisions | |
if (box.bottom > window.innerHeight && ball.velocity.y > 0) { | |
ball.velocity.y *= ball.restitution; | |
} | |
} | |
function elementInViewport(el) { | |
var top = el.offsetTop; | |
var height = el.offsetHeight; | |
while (el.offsetParent) { | |
el = el.offsetParent; | |
top += el.offsetTop; | |
} | |
return ( | |
top >= window.pageYOffset && | |
(top + height) <= (window.pageYOffset + window.innerHeight) && top | |
); | |
} | |
function elementIsntHuge(el) { | |
var width = el.offsetWidth; | |
var height = el.offsetHeight; | |
return width / winWidth < 0.9 && height / winHeight < 0.9; | |
} | |
function init() { | |
document.body.addEventListener('mouseover', function(ev) { | |
var node = ev.target; | |
if (node.tagName === 'AREA') { | |
while (node.parentNode) { | |
for (var t = 0, l = triggerGrandparents.length; t < l; t++) { | |
if (node === triggerGrandparents[t]) { | |
return; | |
} | |
} | |
node = node.parentNode; | |
} | |
} | |
ev.preventDefault(); | |
ev.stopPropagation(); | |
if (elementIsntHuge(node)) { | |
var ball = makePlaceholder(node); | |
if (elementInViewport(ball.node)) { | |
fall(ball); | |
} | |
balls[ball.node] = ball; | |
} | |
}); | |
window.addEventListener('scroll', function() { | |
for (var key in balls) { | |
if (balls.hasOwnProperty(key)) { | |
var ball = balls[key]; | |
if (elementInViewport(ball.node)) { | |
debouncedFall(ball); | |
} | |
} | |
} | |
}); | |
} | |
var clickzones = d.getElementsByTagName('area'); | |
for (var i = 0, l = clickzones.length; i < l; i++) { | |
var href = clickzones[i].getAttribute('href'); | |
if (href === '#falling') { | |
var banner = clickzones[i].parentNode && clickzones[i].parentNode.parentNode; | |
if (banner) { | |
triggerGrandparents.push(banner); | |
} | |
clickzones[i].onclick = init; | |
} | |
} | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment