<div>
<div id="container">
		<div class="box" id="box1">Drag and throw me</div>
		<div class="box" id="box2" style="background-color:red;">Drag and throw me too</div>
</div>
<div class="controls">
				<ul>
					<li class="controlsTitle">Options</li>
					<li>
						<label><input type="checkbox" name="snap" id="snap" value="1" /> Snap end position to grid</label>
					</li>
					<li>
						<label><input type="checkbox" name="liveSnap" id="liveSnap" value="1" /> Live snap</label>
					</li>
				</ul>
			</div>
</div>
html, body {
  margin: 0;
  padding: 0;
  height: 100vh;
  overflow: hidden;
  background-color: #0e100f
}
body{display:flex;align-items:center;justify-content:center;min-height:100vh;}

#container {
  height:801px; 
  overflow:visible; 
  padding:0; 
  position:relative;
}

.box {
	background-color: #91e600;
	text-align: center;
	width: 196px;
	height: 100px;
	line-height: 100px;
	color: black;
	position: absolute;
	top:0;
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;
	border-radius: 10px;
}

.controls {
	background-color: #222;
	border: 1px solid #555;
	color: #bbb;
	font-size: 18px;
  margin: 20px 0;
}
.controls ul {
	list-style: none;
	padding: 0;
	margin: 0;
}
.controls li {
	display: inline-block;
	padding: 8px 0 8px 10px;
	margin:0;
}
.controls input {
  vertical-align:middle;
  cursor: pointer;
}
.controls .controlsTitle {
  border-right:1px solid #555; 
  border-bottom:none; 
  padding-right:10px;
}
/*
See https://greensock.com/draggable/ for details. 
This demo uses InertiaPlugin which is a membership benefit of Club GreenSock, https://greensock.com/club/
*/
gsap.registerPlugin(InertiaPlugin);

var $snap = $("#snap"),
  $liveSnap = $("#liveSnap"),
	$container = $("#container"),
	gridWidth = $("body").width() / 5,
	gridHeight = 100,
	gridRows = 6,
	gridColumns = 5,
	i, x, y;

//loop through and create the grid (a div for each cell). Feel free to tweak the variables above
for (i = 0; i < gridRows * gridColumns; i++) {
	y = Math.floor(i / gridColumns) * gridHeight;
	x = (i * gridWidth) % (gridColumns * gridWidth);
	$("<div/>").css({position:"absolute", border:"1px solid #454545", width:gridWidth-1, height:gridHeight-1, top:y, left:x}).prependTo($container);
}

//set the container's size to match the grid, and ensure that the box widths/heights reflect the variables above
gsap.set($container, {height: gridRows * gridHeight + 1, width: gridColumns * gridWidth + 1});
gsap.set(".box", {width:gridWidth, height:gridHeight, lineHeight:gridHeight + "px"});
gsap.set("#box2", {left: gridWidth * 2})

//the update() function is what creates the Draggable according to the options selected (snapping).
function update() {
  var snap = $snap.prop("checked"),
      liveSnap = $liveSnap.prop("checked");
	Draggable.create(".box", {
		bounds: $container,
		edgeResistance: 0.65,
		type: "x,y",
		inertia: true,
    autoScroll: true,
		liveSnap: liveSnap,
		snap:{
			x: function(endValue) {
				return (snap || liveSnap) ? Math.round(endValue / gridWidth) * gridWidth : endValue;
			},
			y: function(endValue) {
				return (snap || liveSnap) ? Math.round(endValue / gridHeight) * gridHeight : endValue;
			}
		}
	});
}

//when the user toggles one of the "snap" modes, make the necessary updates...
$snap.on("change", applySnap);
$liveSnap.on("change", applySnap);

function applySnap() {
	if ($snap.prop("checked") || $liveSnap.prop("checked")) {
		$(".box").each(function(index, element) {
			gsap.to(element, {
				x: Math.round(gsap.getProperty(element, "x") / gridWidth) * gridWidth,
				y: Math.round(gsap.getProperty(element, "y") / gridHeight) * gridHeight,
				delay: 0.1,
				ease: "power2.inOut"
			});
		});
	}
	update();
}

update();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. https://cdn.jsdelivr.net/npm/gsap@3.1.0/dist/gsap.min.js
  3. https://cdn.jsdelivr.net/npm/gsap@3.1.0/dist/Draggable.min.js
  4. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/InertiaPlugin.min.js