I am refactoring my old code to make it more adjustable to the newest features. I am writing a class that describes what can be done with DOM Node and one of the functions does not work properly. In the code below 2 nested event listeners that are responsible for changing coordinates of the element on the page, when the element is pressed it creates "mousemove" listener that runs each time mouse changes it location, and when mouse is released it stays in new place. The issue is that when mouse is pressed mousemove event fires once, when mouse is released it fires again, but the element itself does not change its location while mouse is dragged. How to fix this?
video: {
multiple: true,
types: [
{
description: "Video",
accept: {
"video/*": [
".mp4",
".flv",
".vob",
".avi",
".wmv",
".mpg",
".gif",
],
},
},
],
},
SVG: {
multiple: true,
types: [{ description: "SVG", accept: { "image/*": [".svg"] } }],
},
};
this.style_elem = function () {
this.isActive
? (this.element.style.border = "2px solid #30C5FF")
: (this.element.style.border = "none");
this.isActive = !this.isActive;
};
this.URL_s = async function (options) {
let fileHandle = await window.showOpenFilePicker(options);
const fileArray = fileHandle.map(async (file) => {
return file.getFile();
});
const files = await Promise.all(fileArray);
const url_string = files.map((file) => {
return URL.createObjectURL(file);
});
return url_string;
};
this.changePos = function (e) {
this.element.style.top = e.clientY - this.shiftY + "px";
this.element.style.left = e.clientX - this.shiftX + "px";
};
this.init = async function () {
const URL = await this.URL_s(this.options.image);
let img_arr = URL.map((url) => {
const img = document.createElement("img");
img.src = url;
let container = document.createElement("div");
container.style.width = "fit-content";
container.style.position = "absolute";
container.appendChild(img);
this.element=container;
return container;
});
img_arr.forEach((img) => {
img.addEventListener("mousedown", (e) => {
e.preventDefault();
this.element = e.currentTarget;
this.shiftX = e.clientX - img.getBoundingClientRect().left;
this.shiftY = e.clientY - img.getBoundingClientRect().top;
this.style_elem();
this.changePos(e);
this.element.addEventListener("mousemove",this.changePos(e));
});
img.addEventListener("mouseup", (e) => {
this.style_elem();
this.element.removeEventListener("mousemove",this.changePos(e));
});
document
.getElementById("ifr")
.contentWindow.document.body.appendChild(img);
});
};
this.init();
}
}
The issue is with the mousemove
event listener. It should be added to the document
object, not the element, to handle fast mouse movements. Also, use bind(this)
to ensure this inside changePos
refers to the correct object. This should work:
img_arr.forEach((img) => {
img.onmousedown = (e) => {
e.preventDefault();
this.element = e.currentTarget;
this.shiftX = e.clientX - img.getBoundingClientRect().left;
this.shiftY = e.clientY - img.getBoundingClientRect().top;
this.style_elem();
document.addEventListener("mousemove", this.changePos.bind(this));
};
img.onmouseup = (e) => {
this.style_elem();
document.removeEventListener("mousemove", this.changePos.bind(this));
};
document.getElementById("ifr").contentWindow.document.body.appendChild(img);
});