JSFiddle - React, Tailwind, and code Playground
by artoo
HTML
<div id="js-drop" class="drop-zone" data-order="2,4,5,3,6,1">
<div class="droppable steps step-1"></div>
<div class="droppable steps step-2"></div>
<div class="droppable steps step-3"></div>
<div class="droppable steps step-4"></div>
<div class="droppable steps step-5"></div>
<div class="droppable steps step-6"></div>
</div>
<div id="js-drag" class="drag-zone">
<div class="drag-wrap">
<img class="draggable" src="http://placehold.it/100x100">
</div>
<div class="drag-wrap">
<img class="draggable" src="http://placehold.it/100x100">
</div>
<div class="drag-wrap">
<img class="draggable" src="http://placehold.it/100x100">
</div>
<div class="drag-wrap">
<img class="draggable" src="http://placehold.it/100x100">
</div>
<div class="drag-wrap">
<img class="draggable" src="http://placehold.it/100x100">
</div>
<div class="drag-wrap">
<img class="draggable" src="http://placehold.it/100x100">
</div>
</div>
CSS
*, *:before, *:after {
box-sizing: border-box;
}
html, body { height: 100%; }
body {
margin: 0;
background-color:#568eb9;
background-image: linear-gradient(rgba(255,255,255,.3) 2px, transparent 2px),
linear-gradient(90deg, rgba(255,255,255,.3) 2px, transparent 2px),
linear-gradient(rgba(255,255,255,.2) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.2) 1px, transparent 1px);
background-size:100px 100px, 100px 100px, 20px 20px, 20px 20px;
background-position:-2px -2px, -2px -2px, -1px -1px, -1px -1px
}
.drop-zone {
height: 70vh;
position: relative;
}
.steps {
position: absolute;
height: 100px;
width: 100px;
background: white;
border: 1px solid #568eb9;
box-shadow: 0 5px 15px rgba(0,0,0,.2);
}
.step-1 { top: 50px; left: 50px; }
.step-2 { top: 200px; left: 50px; }
.step-3 { top: 250px; left: 200px; }
.step-4 { top: 250px; left: 350px; }
.step-5 { top: 250px; left: 500px; }
.step-6 { top: 200px; left: 650px; }
.can--drop:not(.caught--it):not(.can--catch) {
/*animation: bounce 1.5s ease infinite;*/
animation: glow 1.5s ease infinite;
}
@keyframes glow {
50% {
background: rgba(255,255,255,.6);
}
}
@keyframes bounce {
50% {
transform:
scale(.98)
translateY(-5%);
}
}
.steps:before {
content: '';
position: absolute;
top: 0; left: 0;
height: 100%; width: 100%;
background: #6dc001;
transform-origin: center;
transform: scale(0);
}
.can--catch:before {
animation: grow .75s ease infinite;
}
@keyframes grow {
from { transform: scale(0); }
to {
opacity: 0;
transform: scale(1);
}
}
.drag-zone {
display: flex;
align-items: center;
justify-content: space-around;
height: 30vh;
background: rgba(255,255,255,.3);
border-top: 1px solid rgba(255,255,255,.5);
}
...
JavaScript
(function() {
function init() {
var startPos = null;
interact('.draggable').draggable({
snap: {
targets: [startPos],
range: Infinity,
relativePoints: [ { x: 0.5, y: 0.5 } ],
endOnly: true
},
onstart: function (event) {
var rect = interact.getElementRect(event.target);
// record center point when starting the very first a drag
startPos = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
}
event.interactable.draggable({
snap: {
targets: [startPos]
}
});
},
// call this function on every dragmove event
onmove: function (event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
target.classList.add('getting--dragged');
},
onend: function (event) {
event.target.classList.remove('getting--dragged')
}
});
interact('.droppable:not(.caught--it)').dropzone({
accept: '.draggable',
overlap: .5,
ondropactivate: function (event) {
event.target.classList.add('can--drop');
},
ondragenter: function (event) {
var draggableElement = event.relatedTarget,
dropzoneElement = event.target,
dropRect = interact.getElementRect(dropzoneElement),
dropCenter = {
x: dropRect.left + dropRect.width / 2,
y: dropRect.top + dropRect.height /...