JSFiddle - React, Tailwind, and code Playground
by alexb
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.2.9/interact.min.js"></script>
<div id="a"></div>
<div id="b"></div>
CSS
div {
display: block;
height: 100px;;
width: 100px;
position: absolute;
}
#a {
background-color: red;
left: 200px;
top: 300px
}
#b {
background-color: blue;
left: 400px;
top: 100px;
}
svg {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
width: 100%;
height: 100%;
}
div {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAQAAAC0NkA6AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfiCB8VExzAUWBnAAACEklEQVRYw+2YTU8aQRjHf7yctjQR00ioyknYrZ+hHmma1p48esar8UO011qPcm/14EnxUJvAQj8DhqNZkyYe1NgETzAeRmQXFmdg2EMb/lzIZOf5PfPMy/5nYVzNMTd2nzFlc0IFO0pEAReBoB4dpoeIECMRTe64oxkNRiJqFLnggiK16WNsXAR18izi4bFInvp0MSmOnwLm8PDIATZ1BGfMqwPENSBd/lBhi1agtUWJX8RITmssFqnHf/2RAMyzoNNdL4/2iPZrvRx1ymWsGWQGASCFZRyzv6tCIW84ZNcQY7HLj+CZ5oc4lPlAhphhbbKsUw4/Oh1+I6hReDZE8FgJlz3qhJYIV4HQg4zAODQQVFlRFmMJD48l5XN5/2stiZyLt5zzhXtFjl2WSQDLqBZ/m89kWKNMiVaMNN95D/zlRmPXJFgArugon+yS5iVwymYcgVB2MFEMktyyQ4o1LtmmSUJZriNgA08x6g6r7OHQYIdb2SRXQ5W8Mq+JJr4nW9N9GCxhfYzeZnRHR5KYn6SNIH4D9Sj/9LUocYZQTL5K4QYqoDSvjMs1dNQPWqIbo1FIDRmo//f1O4P8KxCLF6HtmgZKB2LxbdDkAOBwwFcdjA4kzms+sT9gMmz2+UjW0EAFcm4gcIcupu50778S07tiv6OmZaAmxMiPBefRIPoY+YsI4cdEiJCYUyrRImCij2oP+ni8krzSl5MAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDgtMzFUMTk6MTk6MjgrMDI6MDDLqzBaAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTA4LTMxVDE5OjE5OjI4KzAyOjAwuvaI5gAAAABJRU5ErkJggg==);
background-position: center center;
background-repeat: no-repeat;
}
JavaScript
function createPathDef(x1, y1, x2, y2) {
let dx = Math.abs(y2 - y1) / 2;
let dy = Math.abs(x2 - x1) / 2;
return `M ${x1} ${y1} C ${x1 - dx} ${y1 - dy}, ${x2 - dx} ${y2 - dy}, ${x2} ${y2}`;
}
const a = document.querySelector('#a');
const x1 = a.offsetLeft;
const y1 = a.offsetTop;
const b = document.querySelector('#b');
const x2 = b.offsetLeft;
const y2 = b.offsetTop;
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.innerHTML = `<path d="${createPathDef(x1, y1, x2, y2)}" stroke="black" stroke-width="4" stroke-linecap="round" fill="transparent"/>`;
a.offsetParent.appendChild(svg);
const path = svg.firstChild;
function updatePath() {
path.setAttribute('d', createPathDef(
x1 + (parseFloat(a.dataset.x) || 0),
y1 + (parseFloat(a.dataset.y) || 0),
x2 + (parseFloat(b.dataset.x) || 0),
y2 + (parseFloat(b.dataset.y) || 0)
));
}
interact('div').draggable({
onmove: e => {
x = (parseFloat(e.target.dataset.x) || 0) + e.dx,
y = (parseFloat(e.target.dataset.y) || 0) + e.dy;
e.target.style.transform = `translate(${x}px, ${y}px)`;
e.target.setAttribute('data-x', x);
e.target.setAttribute('data-y', y);
updatePath();
}
});