JSFiddle - React, Tailwind, and code Playground
HTML
<!-- From the HTML & CSS Advent 2012 -->
<!-- http://advent2012.digitpaint.nl/16/ -->
<a href="http://advent2012.digitpaint.nl/16/">Click to read the original post/problem</a>
<div id="container">
<div id="box">
<div id="block"> </div>
<div id="bar"> </div>
</div>
</div>
CSS
#container{
/* Just so you can actually see the whole bar */
margin-top: 200px;
}
#box{
width: 500px;
background: #fff;
padding-top: 30px;
position: relative;
z-index: 100;
}
#block{
width: 10px;
height: 10px;
background: #f00;
position: absolute;
bottom: 5px;
left: 50%;
}
#bar{
width: 100%;
height: 5px;
background: #000;
}
JavaScript
// The elements
var box = document.getElementById("box");
var block = document.getElementById("block");
// Some constants
var gravity = 9.8;
var friction = 5;
var lastUpdate = new Date();
var curUpdate;
var curSpeed = 0;
var acceleration = 0;
var angle = 0;
var curPos = 0;
// Set the current angle and rotate
// the box to make it visible.
var slide = function(a){
angle = (a * (Math.PI/180));
box.style.webkitTransform = "rotateZ("+a+"deg)";
box.style.mozTransform = "rotateZ("+a+"deg)";
box.style.transform = "rotateZ("+a+"deg)";
}
// The tricky part
var updatePos = function(){
var curUpdate = new Date();
var timeDelta = (curUpdate - lastUpdate)/1000;
var accConstant = gravity * Math.sin(angle);
// This is the part we can't figure out...
if(angle > 0){
acceleration = accConstant - Math.min((Math.cos(angle) * friction), curSpeed + accConstant);
} else {
if(curSpeed > 0){
acceleration = accConstant - Math.max((-1 * Math.cos(angle) * friction), -1 * curSpeed + gravity * Math.sin(angle));
} else {
acceleration = accConstant - Math.max((-1 * Math.cos(angle) * friction), curSpeed + gravity * Math.sin(angle));
}
}
console.log(acceleration, accConstant, curSpeed);
// Recalculate speed based on acceleration/timeDelta
var speedIncrease = acceleration * timeDelta;
curSpeed += speedIncrease;
// Calculate position
var moveBy = curSpeed * timeDelta;
curPos += moveBy;
// Set the position
block.style.left = curPos + "px";
lastUpdate = curUpdate;
}
// Recalculate the position every second
var i = setInterval(updatePos, 1000);
// Set the current slide size, you can change this from your
// console.
slide(50);