Home > front end >  Multiple Draggable divs "tangle"
Multiple Draggable divs "tangle"

Time:02-02

I'm trying to develop a maths game for kids that does not need the keyboard. Round divs are draggable into blue boxes (also divs).

Dragging down quickly on any round div over the other round divs causes them to wander! (touch or slow mouse both work fine).

sample: https://roger-eve.w3spaces.com/dizzy_divs.html

My hunch is a 3D transform at the end of the script is to blame but I don't really understand it.

Any help Greatly appreciated

CodePudding user response:

If I understood correctly, then in your example, you'd better use Pointer Events and Pointer capture. Your example with PointerEvents below:

const box1 = document.querySelector("#box1");
const box2 = document.querySelector("#box2");
const box3 = document.querySelector("#box3");
const box4 = document.querySelector("#box4");
const box5 = document.querySelector("#box5");
const item1 = document.querySelector("#item1");
const item2 = document.querySelector("#item2");
const item3 = document.querySelector("#item3");
const item4 = document.querySelector("#item4");
const item5 = document.querySelector("#item5");
let active = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;
//////////////////////////////////////////
// Moved from dragend
//////////////////////////////////////////
const box1Size = box1.getBoundingClientRect(); //the size of box1
const box2Size = box2.getBoundingClientRect(); //the size of box2
const box3Size = box3.getBoundingClientRect(); //the size of box2
const box4Size = box4.getBoundingClientRect(); //the size of box2
const box5Size = box5.getBoundingClientRect(); //the size of box2
//Add Event Listeners for Touchscreens
//container.addEventListener("touchstart", dragStart, false);
//container.addEventListener("touchend", dragEnd, false);
//container.addEventListener("touchmove", drag, false);
item1.addEventListener('pointerdown', dragStart);
item1.addEventListener('pointerup', dragEnd);
item2.addEventListener('pointerdown', dragStart);
item2.addEventListener('pointerup', dragEnd);
item3.addEventListener('pointerdown', dragStart);
item3.addEventListener('pointerup', dragEnd);
item4.addEventListener('pointerdown', dragStart);
item4.addEventListener('pointerup', dragEnd);
item5.addEventListener('pointerdown', dragStart);
item5.addEventListener('pointerup', dragEnd);


function dragStart(e) { //when the drag starts
  this.addEventListener('pointermove', drag);
  this.setPointerCapture(e.pointerId);

  if (e.type === "touchstart") { //if its a touchscreen
    initialX = e.touches[0].clientX - xOffset; //set initial x-cordinate to where it was before drag started
    initialY = e.touches[0].clientY - yOffset; //set initial y-cordinate to where it was before drag started
  } else { //if its not a touchscreen (mouse)
    initialX = e.clientX - xOffset; //set initial x-cordinate to where it was before drag started
    initialY = e.clientY - yOffset; //set initial y-cordinate to where it was before drag started
  }
}

function dragEnd(e) { //when the drag ends
  this.removeEventListener('pointermove', drag);
  this.releasePointerCapture(e.pointerId);

  const elementSize = e.target.getBoundingClientRect(); //the size of the circle
  if (elementSize.left >= box1Size.left && elementSize.right <= box1Size.right && elementSize.top >= box1Size.top && elementSize.bottom <= box1Size.bottom) {
    //if the circle is in box1
    initialX = currentX; //set the initial x-cordinate to where it is now
    initialY = currentY; //set the initial y-cordinate to where it is now
    box1.innerHTML = box1.innerHTML   " "   e.target.innerHTML;
  } else if (elementSize.left >= box2Size.left && elementSize.right <= box2Size.right && elementSize.top >= box2Size.top && elementSize.bottom <= box2Size.bottom) {
    //if the circle is in box2
    initialX = currentX; //set the initial x-cordinate to where it is now
    initialY = currentY; //set the initial y-cordinate to where it is now
    box2.innerHTML = box2.innerHTML   " "   e.target.innerHTML;
  } else if (elementSize.left >= box3Size.left && elementSize.right <= box3Size.right && elementSize.top >= box3Size.top && elementSize.bottom <= box3Size.bottom) {
    //if the circle is in box3
    initialX = currentX; //set the initial x-cordinate to where it is now
    initialY = currentY; //set the initial y-cordinate to where it is now
    box3.innerHTML = box3.innerHTML   " "   e.target.innerHTML;
  } else if (elementSize.left >= box4Size.left && elementSize.right <= box4Size.right && elementSize.top >= box4Size.top && elementSize.bottom <= box4Size.bottom) {
    //if the circle is in box4
    initialX = currentX; //set the initial x-cordinate to where it is now
    initialY = currentY; //set the initial y-cordinate to where it is now
    box4.innerHTML = box4.innerHTML   " "   e.target.innerHTML;
  } else if (elementSize.left >= box5Size.left && elementSize.right <= box5Size.right && elementSize.top >= box5Size.top && elementSize.bottom <= box5Size.bottom) {
    //if the circle is in box5
    initialX = currentX; //set the initial x-cordinate to where it is now
    initialY = currentY; //set the initial y-cordinate to where it is now
    box5.innerHTML = box5.innerHTML   " "   e.target.innerHTML;
  } else { //if the circle is in neither box1 nor box2
    /*currentX = 0;
    currentY = 0;
    initialX = 0;
    initialY = 0;
    xOffset = 0;
    yOffset = 0;
    setTranslate(0, 0, e.target);*/
  }
  currentX = 0;
  currentY = 0;
  initialX = 0;
  initialY = 0;
  xOffset = 0;
  yOffset = 0;
  setTranslate(0, 0, e.target);
  active = false; //the drag is no longer active
}

function drag(e) { //when the circle is being dragged
  if (e.type === "touchmove") { //if its a touchscreen
    currentX = e.touches[0].clientX - initialX; //set current x-cordinate to where it is now
    currentY = e.touches[0].clientY - initialY; //set current y-cordinate to where it is now
  } else { //if its not a touchscreen (mouse)
    currentX = e.clientX - initialX; //set current x-cordinate to where it is now
    currentY = e.clientY - initialY; //set current y-cordinate to where it is now
  }

  xOffset = currentX;
  yOffset = currentY;
  setTranslate(currentX, currentY, e.target);
}

function setTranslate(xPos, yPos, e) {
  e.style.transform = "translate3d("   xPos   "px, "   yPos   "px, 0)";
}
.flex-container {
  display: flex;
}

[id^=i] {
  width: 80px;
  height: 80px;
  margin: auto;
  background-color: ivory;
  border: 1px solid DarkRed;
  border-radius: 50%;
  touch-action: none;
  user-select: none;
  /*position: absolute;*/
  font-size: 40px;
  text-align: center;
}

[id^=b] {
  /* this applies to all elements with ids beginning with "b"    */
  font-size: 40px;
  border: 2px solid LightGrey;
  width: 100px;
  height: 100px;
  background-color: blue;
  color: ivory;
  text-align: center;
}
<h2>Trial</h2>
<div>
  <table>
    <tr>
      <td>
        <div id="box1"  ;></div>
      </td>
      <td>
        <div id="item1" draggable="false">A</div>
      </td>
    </tr>
    <tr>
      <td>
        <div id="box2" ></div>
      </td>
      <td>
        <div id="item2">B</div>
      </td>
    </tr>
    <tr>
      <td>
        <div id="box3" ></div>
      </td>
      <td>
        <div id="item3">C</div>
      </td>
    </tr>
    <tr>
      <td>
        <div id="box4" ></div>
      </td>
      <td>
        <div id="item4">D</div>
      </td>
    </tr>
    <tr>
      <td>
        <div id="box5" ></div>
      </td>
      <td>
        <div id="item5">E</div>
      </td>
    </tr>
  </table>
</div>

  •  Tags:  
  • Related