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?
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>