<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();
This Pen doesn't use any external CSS resources.