Search code examples
javascriptdragdrop

Dragged item going faster than cursor


I'm trying to write some code to create a drag and drop minigame. So far I'm having a problem with the touchable part of the code. When I added the draggable option (with cursor only) it worked perfectly.

But I tried to add some touchable code (to allow people on phones or tablets to use it as well) using this tuto : https://www.kirupa.com/html5/drag.htm .

I have one major problem though : the dragged item is going faster than the cursor the further you go from the dragstart point.

You can see the problem here with the javascript below : http://jsfiddle.net/0n8x6gue/1/

var container = document.querySelector("#section");
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;

    // item avec lequel on interagit
    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) {
    e.preventDefault();
    if (e.type === "touchmove") {

      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)";
}
#bloc_page {
  width: 75%;
  margin: auto;
  min-width: 900px;
}

#section {
  display: flex;
  height: 500px;
  border: solid 1px;
}

h1 {
  text-align: center;
}


/* Jeu */

.yobi.ui-draggable-dragging {
  border: dashed rgba(53, 187, 243, 0.9);
}

#propositions {
  height: 100%;
  width: 25%;
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.yobi {
  border: solid rgba(53, 187, 243, 0.9);
  padding: 8px;
  margin: 10px;
  font-size: 24px;
  font-weight: bold;
  text-align: center;
  list-style-type: none;
  background-color: white;
  user-select: none;
}

 :hover {
  border-color: rgba(255, 134, 172, 0.9);
  cursor: pointer;
}

 :active {
  cursor: none;
}
<!DOCTYPE html>

<html lang="fr" xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta charset="utf-8" />
  <title>Test</title>
  <!--Titre de la page dans l'onglet en haut-->
  <link href="main.css" rel="stylesheet" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <script type="text/javascript" src="app.js" async></script>
  <script>
    (window.jQuery || document.write('<script src="/scripts/jquery-3.6.0.min.js"><\/script>'));
  </script>
  <!--Charger jQuery depuis fichier local si le CDN est indisponible-->
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
</head>

<body>
  <div id="bloc_page">
    <header>
      <h1>Les Jours de la Semaine - 曜日</h1>
    </header>

    <section id="section">
      <div id="propositions">
        <ul>
          <li class="yobi">げつようび</li>
          <li class="yobi">かようび</li>
          <li class="yobi">すいようび</li>
          <li class="yobi">もくようび</li>
          <li class="yobi">きんようび</li>
          <li class="yobi">どようび</li>
          <li class="yobi">にちようび</li>
        </ul>
      </div>
    </section>
  </div>
</body>

</html>


Solution

  • Looks like the problem is in setTranslate function. Your block already moves by setting activeItem.currentX and activeItem.currentY variables and then translates its position.

    In your case it leads to double movement: your block moves 2x faster than the cursor.

    To fix your problem, you can change your drag function this way:

    function drag(e) {
        if (active) {
            e.preventDefault();
            
            if (e.type === "touchmove") {
                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;
    
            if (e.type === "touchmove") {
                setTranslate(activeItem.currentX, activeItem.currentY, activeItem);
            }
        }
    }