Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

What is causing my drag and drop function to stutter with an iFrame?

I’m trying to develop an application that allows users to display multiple Youtube videos, with additional functionality including being able to drag and resize the videos however they’d like.

My drag seems to work as expected, until I add an iframe into the middle. Then, it begins to stutter and lag when I’m dragging the video container. Almost as if it’s losing track of the pointer.

What could be causing this issue?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

dragElement(document.getElementById("container"));

function dragElement(elmnt) {
  var pos1 = 0,
    pos2 = 0,
    pos3 = 0,
    pos4 = 0;
  var dragHandles = elmnt.getElementsByClassName("drag-handle");

  // Assign drag functionality to each drag handle
  for (var i = 0; i < dragHandles.length; i++) {
    dragHandles[i].addEventListener("mousedown", function(e) {
      dragMouseDown(e, elmnt);
    });
  }

  function dragMouseDown(e, elmnt) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = throttle(function(e) {
      elementDrag(e, elmnt);
    }, 16); // Throttle to approximately 60 FPS
  }

  function elementDrag(e, elmnt) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = elmnt.offsetTop - pos2 + "px";
    elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
  }

  // Throttle function
  function throttle(func, limit) {
    let lastFunc;
    let lastRan;
    return function(...args) {
      const context = this;
      if (!lastRan) {
        func.apply(context, args);
        lastRan = Date.now();
      } else {
        clearTimeout(lastFunc);
        lastFunc = setTimeout(function() {
          if (Date.now() - lastRan >= limit) {
            func.apply(context, args);
            lastRan = Date.now();
          }
        }, limit - (Date.now() - lastRan));
      }
    };
  }
}
* {
  box-sizing: border-box;
}

#container {
  position: absolute;
  z-index: 9;
  background-color: #bcd8c1;
  border: 1px solid #bcd8c1;
  text-align: center;
  padding: 0;
  width: 400px;
  height: 300px;
  min-width: 300px;
  min-height: 200px;
  resize: both;
  overflow: auto;
}

.drag-handle {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  height: 6%;
  width: 100%;
  cursor: move;
  background-color: #bcd8c1;
  color: #fff;
}

.video {
  width: 94%;
  height: 88%;
  background-color: rgb(145, 153, 150);
  margin: auto;
}

iframe {
  width: 100%;
  height: 100%;
}

.drag-handle button {
  font-size: 0.7em;
  background-color: #bcd8c1;
  color: antiquewhite;
  border: none;
  margin: 5px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script src="https://kit.fontawesome.com/06e1971d77.js" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="style.css" />
  <title>title</title>
</head>

<body>
  <div id="container">
    <div class="drag-handle">
      <button id="play-pause-button"><i class="fa-solid fa-play"></i></button>
    </div>
    <div class="video">
      <iframe src="https://iframetester.com/"></iframe> 
    </div>
    <div class="drag-handle"></div>
  </div>
</body>
<script src="script.js"></script>

</html>

>Solution :

It begins to "stutter", when I move the mouse fast enough, and get over the position where the iframe "previously" was.

Adding a class to the dragged element, that applies pointer-events: none to the iframe(s) within, appears to be able to mitigate the issue.

dragElement(document.getElementById("container"));

function dragElement(elmnt) {
  var pos1 = 0,
    pos2 = 0,
    pos3 = 0,
    pos4 = 0;
  var dragHandles = elmnt.getElementsByClassName("drag-handle");

  // Assign drag functionality to each drag handle
  for (var i = 0; i < dragHandles.length; i++) {
    dragHandles[i].addEventListener("mousedown", function(e) {
      dragMouseDown(e, elmnt);
    });
  }

  function dragMouseDown(e, elmnt) {
    e = e || window.event;
    e.preventDefault();
    elmnt.classList.add('dragging'); /* add class here */
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = throttle(function(e) {
      elementDrag(e, elmnt);
    }, 16); // Throttle to approximately 60 FPS
  }

  function elementDrag(e, elmnt) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = elmnt.offsetTop - pos2 + "px";
    elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
  }

  function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
    elmnt.classList.remove('dragging'); /* remove class again when done dragging */
  }

  // Throttle function
  function throttle(func, limit) {
    let lastFunc;
    let lastRan;
    return function(...args) {
      const context = this;
      if (!lastRan) {
        func.apply(context, args);
        lastRan = Date.now();
      } else {
        clearTimeout(lastFunc);
        lastFunc = setTimeout(function() {
          if (Date.now() - lastRan >= limit) {
            func.apply(context, args);
            lastRan = Date.now();
          }
        }, limit - (Date.now() - lastRan));
      }
    };
  }
}
* {
  box-sizing: border-box;
}

#container {
  position: absolute;
  z-index: 9;
  background-color: #bcd8c1;
  border: 1px solid #bcd8c1;
  text-align: center;
  padding: 0;
  width: 400px;
  height: 300px;
  min-width: 300px;
  min-height: 200px;
  resize: both;
  overflow: auto;
}

.drag-handle {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  height: 6%;
  width: 100%;
  cursor: move;
  background-color: #bcd8c1;
  color: #fff;
}

.video {
  width: 94%;
  height: 88%;
  background-color: rgb(145, 153, 150);
  margin: auto;
}

iframe {
  width: 100%;
  height: 100%;
}

.drag-handle button {
  font-size: 0.7em;
  background-color: #bcd8c1;
  color: antiquewhite;
  border: none;
  margin: 5px;
}

/* make iframes in dragged container ignore pointer events */
#container.dragging iframe {
  pointer-events: none;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <script src="https://kit.fontawesome.com/06e1971d77.js" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="style.css" />
  <title>title</title>
</head>

<body>
  <div id="container">
    <div class="drag-handle">
      <button id="play-pause-button"><i class="fa-solid fa-play"></i></button>
    </div>
    <div class="video">
      <iframe src="https://iframetester.com/"></iframe> 
    </div>
    <div class="drag-handle"></div>
  </div>
</body>
<script src="script.js"></script>

</html>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading