Create a Draggable Element in JavaScript


#1

by kirupa | 26 April 2018

Have questions? Discuss this HTML5 / JavaScript tutorial with others on the forums.


This is a companion discussion topic for the original entry at http://www.kirupa.com/html5/drag.htm

#2

Hi,
How about if i want to have multiple draggable elements?
Thank you very much for your concerning.


#3

Hi Alvin!
That will require adjusting the draggable element from being hard coded for a single element to handle an arbitrary number of elements. I used the ideas from the Handling Events for Many Elements article to make that adjustment.

The full code for being able to drag multiple elements looks as follows:

<!DOCTYPE html>
<html>

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
  <title>Drag Multiple Elements</title>
  <style>
    #container {
      width: 100%;
      height: 400px;
      background-color: #333;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      border-radius: 7px;
      touch-action: none;
    }

    .item {
      border-radius: 50%;
      touch-action: none;
      user-select: none;
      position: relative;
    }

    .one {
      width: 100px;
      height: 100px;
      background-color: rgb(245, 230, 99);
      border: 10px solid rgba(136, 136, 136, .5);
      top: 0px;
      left: 0px;
    }

    .two {
      width: 60px;
      height: 60px;
      background-color: rgba(196, 241, 190, 1);
      border: 10px solid rgba(136, 136, 136, .5);
      top: 30%;
      left: 10%;
    }

    .three {
      width: 40px;
      height: 40px;
      background-color: rgb(0, 255, 231);
      border: 10px solid rgba(136, 136, 136, .5);
      top: -40%;
      left: -10%;
    }

    .four {
      width: 80px;
      height: 80px;
      background-color: rgb(233, 210, 244);
      border: 10px solid rgba(136, 136, 136, .5);
      top: -10%;
      left: 5%;
    }

    .item:active {
      opacity: .75;
    }

    .item:hover {
      cursor: pointer;
    }
  </style>
</head>

<body>

  <div id="outerContainer">
    <div id="container">
      <div class="item one">

      </div>
      <div class="item two">

      </div>
      <div class="item three">

      </div>
      <div class="item four">

      </div>
    </div>
  </div>

  <script>
    var container = document.querySelector("#container");
    var activeItem = null;

    var active = false;

    container.addEventListener("touchstart", dragStart, false);
    container.addEventListener("touchend", dragEnd, false);
    container.addEventListener("touchmove", drag, false);

    container.addEventListener("mousedown", dragStart, false);
    container.addEventListener("mouseup", dragEnd, false);
    container.addEventListener("mousemove", drag, false);

    function dragStart(e) {

      if (e.target !== e.currentTarget) {
        active = true;

        // this is the item we are interacting with
        activeItem = e.target;

        if (activeItem !== null) {
          if (!activeItem.xOffset) {
            activeItem.xOffset = 0;
          }

          if (!activeItem.yOffset) {
            activeItem.yOffset = 0;
          }

          if (e.type === "touchstart") {
            activeItem.initialX = e.touches[0].clientX - activeItem.xOffset;
            activeItem.initialY = e.touches[0].clientY - activeItem.yOffset;
          } else {
            console.log("doing something!");
            activeItem.initialX = e.clientX - activeItem.xOffset;
            activeItem.initialY = e.clientY - activeItem.yOffset;
          }
        }
      }
    }

    function dragEnd(e) {
      if (activeItem !== null) {
        activeItem.initialX = activeItem.currentX;
        activeItem.initialY = activeItem.currentY;
      }

      active = false;
      activeItem = null;
    }

    function drag(e) {
      if (active) {
        if (e.type === "touchmove") {
          e.preventDefault();

          activeItem.currentX = e.touches[0].clientX - activeItem.initialX;
          activeItem.currentY = e.touches[0].clientY - activeItem.initialY;
        } else {
          activeItem.currentX = e.clientX - activeItem.initialX;
          activeItem.currentY = e.clientY - activeItem.initialY;
        }

        activeItem.xOffset = activeItem.currentX;
        activeItem.yOffset = activeItem.currentY;

        setTranslate(activeItem.currentX, activeItem.currentY, activeItem);
      }
    }

    function setTranslate(xPos, yPos, el) {
      el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
    }
  </script>
</body>

</html>

You can see a live demo of it here: https://www.kirupa.com/html5/examples/drag_multiple.htm

Let me know if this works for you.

Cheers,
Kirupa


#4

Hi Kirupa,

Yes, it works pretty well.
This code really helps me a lot.
Thank you very much.

Best Regards,
Alvin