Custom Draggable Element
by Richard Hunter
HTML
<div id="container">
<my-draggable id="alpha">
<div class="foo"></div>
</my-draggable>
<my-draggable id="beta">
<div class="bar"></div>
</my-draggable>
</div>
CSS
.foo {
background: pink;
padding: 10px;
width: 50px;
height: 40px;
border: solid 3px black;
}
.bar {
background: antiquewhite;
padding: 10px;
width: 40px;
height: 30px;
border: dashed 3px dodgerblue;
}
#container {
position: relative;
background: green;
height: 100vh;
width: 100vw;
}
body {
margin: 0;
}
JavaScript
let alphaPosition = {
left: 20,
top: 20,
};
let betaPosition = {
left: 50,
top: 50,
};
class Draggable extends HTMLElement {
constructor() {
super();
this.pointerDown = false;
this.style.position = 'absolute';
this.style.left = 0;
this.style.top = 0;
this.addEventListener('pointerdown', (event) => {
event.target.setPointerCapture(event.pointerId);
this.pointerDown = true;
this.startX = event.clientX;
this.startY = event.clientY;
});
this.addEventListener('pointermove', (event) => {
if (this.pointerDown) {
var dragEvent = new CustomEvent("drag", {
bubbles: true,
detail: {
id: this.id,
xdiff: event.clientX - this.startX,
ydiff: event.clientY - this.startY,
}
});
this.startX = event.clientX;
this.startY = event.clientY;
event.target.dispatchEvent(dragEvent);
}
});
this.addEventListener('pointerup', (event) => {
event.target.releasePointerCapture(event.pointerId);
this.pointerDown = false;
});
}
}
customElements.define('my-draggable', Draggable);
function render() {
alpha.style.transform = `translate(${alphaPosition.left}px, ${alphaPosition.top}px)`;
beta.style.transform = `translate(${betaPosition.left}px, ${betaPosition.top}px)`;
}
const leftLimit = 200;
const topLimit = 200;
container.addEventListener('drag', (event) => {
if (event.detail.id === 'alpha') {
alphaPosition = {
...alphaPosition,
left: Math.min(leftLimit, Math.max(20, alphaPosition.left + event.detail.xdiff)),
top: Math.min(topLimit, Math.max(20, alphaPosition.top + event.detail.ydiff)),
};
render();
}
if (event.detail.id === 'beta') {
betaPosition = {
...betaPosition,
left: betaPosition.left + event.detail.xdiff,
top: betaPosition.top + event.detail.ydiff,
};
render();
}
});
render();