Draggable + Resizable Div

by Rajesh Danabal

HTML

<div class="container" id="node-container"></div>

CSS

body { margin: 0; background: #111; height: 100vh; display: flex; justify-content: center; align-items: center; }
  .container { position: relative; width: 800px; height: 600px; background: #222; }
  .item {
    position: absolute;
    background: #444;
    border: 1px solid #888;
    border-radius: 6px;
    box-sizing: border-box;
    user-select: none;
  }
  .header { height: 20px; background: #666; cursor: move; }
  .resize { position: absolute; width: 5px; height: 5px; background: #aaa; cursor: se-resize; bottom: 0; right: 0; }

JavaScript

const gridSize = 5;
const minW = gridSize,
  minH = gridSize;
const container = document.getElementById("node-container");
let items = [];

function snap(v) {
  return Math.round(v / gridSize) * gridSize;
}

function overlaps(a, b) {
  return !(
    a.x + a.w <= b.x ||
    a.x >= b.x + b.w ||
    a.y + a.h <= b.y ||
    a.y >= b.y + b.h
  );
}

function createItem(x, y, w, h) {
  const el = document.createElement("div");
  el.className = "item";
  el.style.left = x + "px";
  el.style.top = y + "px";
  el.style.width = w + "px";
  el.style.height = h + "px";



  const resizeHandle = document.createElement("div");
  resizeHandle.className = "resize";
  el.appendChild(resizeHandle);

  container.appendChild(el);

  const data = { el, x, y, w, h };
  items.push(data);

  let drag = false,
    resize = false;
  let startX, startY, startPos;

  el.addEventListener("pointerdown", (e) => {
    console.log('element mouse down');
    drag = true;
    startX = e.clientX;
    startY = e.clientY;
    startPos = { x: data.x, y: data.y };
    e.preventDefault();
  });

  resizeHandle.addEventListener("pointerdown", (e) => {
    console.log('resize handler mouse down');
    resize = true;
    startX = e.clientX;
    startY = e.clientY;
    startPos = { w: data.w, h: data.h };
    e.preventDefault();
    e.stopPropagation();
  });

  window.addEventListener("pointermove", (e) => {
    if (drag) {
      let nx = snap(startPos.x + (e.clientX - startX));
      let ny = snap(startPos.y + (e.clientY - startY));

      // collision check
      const test = { ...data, x: nx, y: ny };
      const collide = items.some((it) => it !== data && overlaps(test, it));
      if (!collide) {
        data.x = nx;
        data.y = ny;
        el.style.left = nx + "px";
        el.style.top = ny + "px";
      }
    }
    if (resize) {
      let nw = snap(startPos.w + (e.clientX - startX));
      let nh = snap(startPos.h +...