dragging SVG elements

by Richard Hunter

HTML

<svg id="svg" width="500" height="500">
  <rect x="50" y="50" width="100" height="100" fill="red" stroke-width="20" stroke="black" />
  <g id="group" transform="translate(0, 0)">
    <rect x="0" y="0" width="100" height="100" fill="red" />
    <text x="0" y="0">hello rich</text>
    <rect id="foo" x="0" y="0" width="100" height="100" opacity="0" fill="blue" />
  </g>

</svg>

CSS

.foo {
  border: dashed 10px blue;
  background: pink;
}

JavaScript

const foo = document.getElementById('foo');

function makeDraggable(svgEl) {
  let startX;
  let startY;
  let pointerDown = false;

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

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

      startX = event.clientX;
      startY = event.clientY;

      event.target.dispatchEvent(dragEvent);
    }
  });

  svgEl.addEventListener('pointerup', (event) => {
    event.stopPropagation();
    pointerDown = false;
    svgEl.releasePointerCapture(event.pointerId);
  });
}

makeDraggable(foo);

let svgEl = document.getElementById('svg');
let groupEl = document.getElementById('group');
let groupX = 0;
let groupY = 0;

svgEl.addEventListener('drag', (event) => {
  groupX = event.detail.xdiff + groupX;
  groupY = event.detail.ydiff + groupY;
  
  group.setAttributeNS(null, 'transform', `translate(${groupX}, ${groupY})`);
});