HichiHachi
HichiHachi

Reputation: 491

How to stop stuttering on "dragover" event

Im trying to create a drag n drop list, and have most of it working fine. Although when I initially drag my element I am getting a stuttering motion. Im unsure how to go about fixing this.

Heres a codepen to see the effect...https://codepen.io/hichihachi/pen/zYvNYZq

<body>
  <ul>
    <li draggable=true>
      <div class="card" >1</div>
    </li>
    <li draggable=true>
      <div class="card">2</div>
    </li>
    <li draggable=true>
      <div class="card">3</div>
    </li>
    <li draggable=true>
      <div class="card">4</div>
    </li>
  </ul>
</body>
const lists = document.querySelectorAll("li");
let dragged;

lists.forEach(e => {
  e.addEventListener("dragstart", dragStart);
  e.addEventListener("dragend", dragEnd);
  e.addEventListener("dragover", dragOver);
  e.addEventListener("dragenter", dragEnter);
  e.addEventListener("dragleave", dragLeave);
  e.addEventListener("drop", dragDrop);
})

function dragStart(){
  this.className += " hold";
  setTimeout(()=>{
    this.className= "invisible";
  },0);
  dragged = this;
  dragged.nextSibling.className = "hovered";
}

function dragEnd(){
  this.className="";

}

function dragOver(e){
  e.preventDefault();
  const mY = event.clientY;
  const elY = this.offsetTop + (160*2) /2;
  if(mY<elY){
    this.className="hovered";
  }else{
    this.className="hovered-bottom"
  }
}

function dragEnter(e){
  e.preventDefault();
  // this.className = "hovered";
}

function dragLeave(){
  this.className = "";
}

function dragDrop(e){
  this.className = "";
  insert(e, this);
}

function insert(e, el){
  const mY = event.clientY;
  const elY = el.offsetTop + el.offsetHeight /2;
  if(mY<elY){
    el.insertAdjacentElement("beforebegin", dragged);
  }else{
    el.insertAdjacentElement("afterend", dragged);
  }
}

Any help would be appreciated thanks!

Upvotes: 2

Views: 910

Answers (1)

Justin Grant
Justin Grant

Reputation: 244

the problem is that your li nodes depend on each other for context. When you engage with one li element, the others fall out of place for a microsecond. As you drag the selected object, and your cursor is still in that space, the dom isn't consistently sure where it belongs or if it's still in transition. AS a result you're getting a back and forth between the selected object and its neighbors until your cursor has left the parent ul.

If I'm understanding what you've done correctly, it looks like you have some paddings defined to compensate for this, but it seems to be contributing to the problem as well.

To address the issue, I made the card itself within the li draggable and gave the li specific dimensions so it keeps the dimensions of the parent real estate intact.

<li>
  <div draggable=true class="card" >1</div>
</li>

li { ... width: 400px; height: 150px; display:block; }

additionally, I removed any items that add variance to the position or size of the engaged elements

.hold{border-color:green;}
.hovered{/*padding-top:160px;*/}
.hovered-bottom{/*padding-bottom:160px;*/}
.invisible{visibility:hidden;/*display:none;*/}

This removes any jitters from your dragging action, and from here you can work on embellishing things like a thicker border on drag. Just keep in mind that you have to account for the space in every state so if you want a thicker border while dragging a card, you have to compensate for the space it takes when sitting in place, for example, a 1px border and 2px margin to make up for a 3px border and no margin on drag.

my forked example from yours: https://codepen.io/mrjt/pen/zYvNwoy

Upvotes: 3

Related Questions