JSFiddle - React, Tailwind, and code Playground
by frumbert
HTML
<script src="https://unpkg.com/plain-draggable"></script>
<ol>
<li>Drag the blue or green circle onto a red square to make it stick to it</li>
<li>Now, resize the browser horizontally or vertically</li>
</ol>
<div class="outer">
<div class="drag blue">
</div>
<div class="drag green">
</div>
<div class="snap one">
</div>
<div class="snap two">
</div>
</div>
CSS
.outer {
margin: 1rem auto;
width: 50vw;
height: 25vh;
border:1px solid indigo;
position: relative;
}
.outer>div {
position: absolute;
}
.snap {
width: 1rem;
height: 1rem;
background-color: red;
z-index: 1;
}
.one {
top: 50%;
right: 45%;
}
.two {
bottom: 55%;
left: 55%;
}
.drag {
bottom: 1rem;
left: 1rem;
width: 1rem;
height: 1rem;
z-index: 2;
border-radius: 50px;
background-color: rgba(0,0,255,.5);
}
.drag.green {
background-color: rgba(0,224,0,.5);
bottom: 40%;
}
JavaScript
let snapped = false, grab;
const tolerance = 20;
const drags = document.querySelectorAll(".drag");
const snaps = document.querySelectorAll(".snap");
Array.from(drags).map(function(el) {
const d = new PlainDraggable(el, {
onMove: function(el) {
snapped = !!el.snapped;
},
onDragStart: function (obj) {
grab = obj;
},
onDragEnd: function (newPosition) {
const bb = this.containment.getBoundingClientRect();
var dropped = this.snap.targets.find(function(bound) {
const target = bound.boundingBox;
const xpos = newPosition.left - bb.x;
const ypos = newPosition.top - bb.y;
console.dir(target);
return (Math.abs(target.x - xpos) < tolerance) && (Math.abs(target.y - ypos) < tolerance);
});
console.dir(dropped);
if (!snapped) {
grab.target.style.transform = 'none';
this.position(); // future-proof consecutive drags
}
grab = undefined;
},
snap: {
targets: Array.from(snaps)
},
containment: document.querySelector("outer")
});
});