Search code examples
javascriptdrag-and-drop

javascript drag and drop not offsetting dragimage when using touch input


I am using html5 drag and drop functionality in a project. I am trying to alter the position of the drag image relative to the position of the input (mouse or finger). The following code works fine on a desktop when using a mouse, however when using a touch panel on a phone screen, the image is never offset.

I originally thought it might be a screen pixel-density issue, but even when I replace the offset with much bigger numbers, nothing happens.

    function dragStart(ev)
    {
        console.log("dragging");
        console.log(ev);

        // Place the drag image offset to the mouse cursor location
        ev.dataTransfer.setDragImage(ev.target, 50, 50);

        ev.dataTransfer.setData("text", ev.target.dataset.tileIndex);
    }

Solution

  • Drag event is a mouse event and not supported well on touch devices. Hence, on many touch devices, not only the drag image, but also the drag event even doesn't work properly. To have better support on touch devices, you could try to handle with touch events.

    const X_OFFSET = 20;
    const Y_OFFSET = 20;
    
    const dragItem = document.getElementById("DragItem");
    let imageElement = null;
    
    function dragStart(event) {
      if (!event.dataTransfer || !event.target) {
        return;
      }
    
      // Place the drag image offset to the mouse cursor location
      event.dataTransfer.setDragImage(event.target, X_OFFSET, Y_OFFSET);
    
      event.dataTransfer.setData('text/html', event.target);
    }
    
    function touchStart(event) {
      var touch = event.targetTouches[0];
    
      const image = event.target.cloneNode(true);
      image.style.position = 'fixed';
      image.style.display = 'none';
      document.body.appendChild(image);
      imageElement = image;
    }
    
    function touchMove(event) {
      const touch = event.targetTouches[0];
      const left = touch.pageX - X_OFFSET;
      const top = touch.pageY - Y_OFFSET;
    
      if (imageElement) {
        imageElement.style.left = left + 'px';
        imageElement.style.top = top + 'px';
        imageElement.style.display = 'block';
      }
    }
    
    function touchEnd(event) {
      if (imageElement) {
        document.body.removeChild(imageElement);
        imageElement = null;
      }
    }
    
    dragItem.addEventListener("dragstart", dragStart);
    dragItem.addEventListener("touchstart", touchStart);
    dragItem.addEventListener("touchmove", touchMove);
    dragItem.addEventListener("touchend", touchEnd);
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div style="user-select:none; touch-action: none;" id="DragItem" draggable="true">
        Drag me
      </div>
    </main>