Dragging with custom events and pointer capture

Demonstration of using custom events and pointer capture to drag an element round the screen

by Richard Hunter

HTML

<div id="container">
<div id="foo" class="draggable"></div>
</div>

CSS

.draggable {
  background: pink;
  padding: 10px;
  width: 50px;
  height: 40px;
  border: solid 3px black;
  position: absolute;
  left: 0;
  top: 0;
}
#container {
  position: relative;
  background: green;
  height: 100vh;
  width: 100vw;
}
body {
  margin: 0;
}

JavaScript

let pointerDown = false;
let startX;
let startY;

let fooPosition = {
	left: 20,
  top: 20,
};

function render() {
	foo.style.transform = `translate(${fooPosition.left}px, ${fooPosition.top}px)`;
}

foo.addEventListener('pointerdown', (event) => {
  event.target.setPointerCapture(event.pointerId);
  pointerDown = true;
  startX = event.clientX;
  startY = event.clientY;
});

foo.addEventListener('pointermove', (event) => {
  if (pointerDown) {
    var dragEvent = new CustomEvent("drag", {
    	bubbles: true,
      detail: {
        id: 'foo',
        xdiff: event.clientX - startX,
        ydiff: event.clientY - startY,
        hazcheeseburger: true
      }
    });
    
    startX = event.clientX;
    startY = event.clientY;
    
    event.target.dispatchEvent(dragEvent);
  }
});

foo.addEventListener('pointerup', (event) => {
  event.target.releasePointerCapture(event.pointerId);
  pointerDown = false;
});
const leftLimit = 200;
const topLimit = 200;


container.addEventListener('drag', (event) => {

  fooPosition = {
  	...fooPosition,
    left: Math.min(leftLimit, Math.max(20, fooPosition.left + event.detail.xdiff)),
    top: Math.min(topLimit, Math.max(20, fooPosition.top + event.detail.ydiff)),
  };
  
  render();
});

render();