Basic Inertia Drag
HTML
<div id="container">
<div id="handle"></div>
</div>
CSS
#container {
position: relative;
border: 2px solid #ccc;
height: 400px;
width: 400px;
}
#handle {
border-radius: 40px;
background: #ff00ff;
position: absolute;
margin: -20px 0 0 -20px;
height: 40px;
width: 40px;
}
JavaScript
var FRICTION_COEFF = 0.85;
var BOUNCE = 0.2;
var container = document.querySelector( '#container' );
var handle = document.querySelector( '#handle' );
var bounds = container.getBoundingClientRect();
var radius = handle.offsetWidth / 2;
var dragging = false;
var mouse = { x: 0, y: 0 };
var position = { x: 0, y: 0 };
var previous = { x: position.x, y: position.y }; // in case position is initialised at non-zero values
var velocity = { x: 0, y: 0 };
function step() {
requestAnimationFrame( step );
if ( dragging ) {
previous.x = position.x;
previous.y = position.y;
position.x = mouse.x;
position.y = mouse.y;
velocity.x = ( position.x - previous.x );
velocity.y = ( position.y - previous.y );
} else {
position.x += velocity.x;
position.y += velocity.y;
velocity.x *= FRICTION_COEFF;
velocity.y *= FRICTION_COEFF;
}
if ( position.x > bounds.width - radius ) {
velocity.x *= -BOUNCE;
position.x = bounds.width - radius;
}
if ( position.x < radius ) {
velocity.x *= -BOUNCE;
position.x = radius;
}
if ( position.y > bounds.height - radius ) {
velocity.y *= -BOUNCE;
position.y = bounds.height - radius;
}
if ( position.y < radius ) {
velocity.y *= -BOUNCE;
position.y = radius;
}
// could use css transforms
handle.style.left = position.x + 'px';
handle.style.top = position.y + 'px';
}
// attach to handle instead to init drag only when grabbing the handle
container.addEventListener( 'mousedown', function() { dragging = true; });
document.addEventListener( 'mouseup', function() { dragging = false; } );
document.addEventListener( 'mousemove', function( event ) {
mouse.x = event.x - bounds.left;
mouse.y = event.y - bounds.top;
});
step();