Drag and drop: Element shifting from its initial position after being clicked

Currently, I am in the process of creating my own Drag'n'drop feature for one of my projects and have encountered a problem. All the elements that can be dragged are enclosed within a container utilizing display:flex. When I click on one of these elements, I set its position to absolute on mousedown so that I can adjust its left and top properties while dragging it. Here is an outline of what I am doing:

let container = document.querySelector("#big-container")
var dragging = false;
var draggedObject;
let shiftX=0;
let shiftY=0;
document.querySelectorAll(".draggable").forEach((draggable,index) => {
    draggable.style.order = index;
    draggable.draggable =false;
    draggable.ondragstart = ()=>{return false}
    draggable.addEventListener("mousedown",ev =>{
        draggedObject = draggable;
        shiftX = ev.offsetX+5;
        shiftY = ev.offsetY+5;
        draggable.style.position = "absolute";
        draggable.style.left = (ev.clientX - shiftX) + 'px';
        draggable.style.top = (ev.clientY - shiftY) + 'px';
        dragging = true;
        let placeholder = document.createElement("div");
        placeholder.id = "placeholder";
        placeholder.style.order = draggable.style.order;
        container.appendChild(placeholder);
    })

})

document.addEventListener("mousemove", ev =>{
    if(dragging){
        draggedObject.style.left = ev.clientX - shiftX + 'px';
        draggedObject.style.top = ev.clientY - shiftY + 'px';
    }
})

document.addEventListener("mouseup",ev =>{
    if(dragging){
        draggedObject.style.position = 'static'
        let placeholder = document.querySelector("#placeholder");
        container.removeChild(placeholder);
        dragging = false
    }
})
/* the :not(:last-of-type(div)) is there so the console doesn't get affected */
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    background-color: black;
}
.draggable {
    width: 90px;
    height: 120px;
    margin: 5px;
}


#placeholder {
    width: 90px;
    height: 120px;
    margin: 5px;
    background-color: rgba(0, 0, 0, 0.3);
    border: dashed grey 5px;
}
<body draggable="false" ondragstart="return false;">
<div id = "big-container" style ="display: flex; background-color: rgb(76, 104, 95); width: 500px; height: 500px;">
    <div style="background-color: rgb(204, 125, 111);" class="draggable"></div>
    <div style="background-color: rgb(170, 214, 120);" class="draggable"></div>
    <div style="background-color: rgb(129, 212, 167);" class="draggable"></div>
    <div style="background-color: rgb(162, 137, 196);" class="draggable"></div>
</div>
</body>

The intention behind this implementation is to keep the element stationary when clicked and then move it along with the mouse as it gets dragged (with the point where it was initially clicked serving as the anchor). The addition of shiftX = ev.offsetX+5; is necessary to accommodate the element's margin.

However, there seems to be a slight positional shift in the element when clicking on it without moving the mouse at all. This displacement is minimal (possibly around 1 or 2 pixels) and does not occur consistently (certain areas within the element do not exhibit this positional shift).

I would greatly appreciate any insights on what might be causing this issue. Thank you.

Answer №1

To accurately determine the position, utilize the getBoundingClientRect() method.

let container = document.querySelector("#big-container");
var dragging = false;
var draggedObject;
let shiftX = 0;
let shiftY = 0;
document.querySelectorAll(".draggable").forEach((draggable, index) => {
  draggable.style.order = index;
  draggable.draggable = false;
  draggable.ondragstart = () => {
    return false;
  };
  draggable.addEventListener("mousedown", (ev) => {
    draggedObject = draggable;
    var x = draggable.getBoundingClientRect().top - 5;
    var y = draggable.getBoundingClientRect().left - 5;
    shiftX = ev.offsetX + 5;
    shiftY = ev.offsetY + 5;
    draggable.style.position = "absolute";
    draggable.style.left = y + "px";
    draggable.style.top = x + "px";
    dragging = true;
    let placeholder = document.createElement("div");
    placeholder.id = "placeholder";
    placeholder.style.order = draggable.style.order;
    container.appendChild(placeholder);
  });
});

document.addEventListener("mousemove", (ev) => {
  if (dragging) {
    draggedObject.style.left = ev.clientX - shiftX + "px";
    draggedObject.style.top = ev.clientY - shiftY + "px";
  }
});

document.addEventListener("mouseup", (ev) => {
  if (dragging) {
    draggedObject.style.position = "static";
    let placeholder = document.querySelector("#placeholder");
    container.removeChild(placeholder);
    dragging = false;
  }
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  background-color: black;
}
#big-container {
  width: 500px;
  height: 500px;
}
.draggable {
  width: 90px;
  height: 120px;
  margin: 5px;
}

#placeholder {
  width: 90px;
  height: 120px;
  margin: 5px;
  background-color: rgba(0, 0, 0, 0.3);
  border: dashed grey 5px;
}
<body draggable="false" ondragstart="return false;">
    <div
      id="big-container"
      style="display: flex; background-color: rgb(76, 104, 95);"
    >
      <div
        style="background-color: rgb(204, 125, 111);"
        class="draggable"
      ></div>
      <div
        style="background-color: rgb(170, 214, 120);"
        class="draggable"
      ></div>
      <div
        style="background-color: rgb(129, 212, 167);"
        class="draggable"
      ></div>
      <div
        style="background-color: rgb(162, 137, 196);"
        class="draggable"
      ></div>
    </div>

  </body>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

My eCommerce website is currently experiencing some technical difficulties that need to be addressed

I'm in need of assistance with a particular error I encountered. I was following an ecommerce example application and everything seemed to be going smoothly until I clicked on "Shop Now." At that point, I received the following message: Server Error T ...

What is the best method to keep my sidebar navigation child menus expanded and active after a new HTTP request in Laravel?

I am facing an issue with the child menus on my website. Whenever I click on a child menu, it becomes active after an HTTP request but I would like it to remain expanded even after the page is refreshed. Below is the structure of the menu: <ul clas ...

Ensuring the header of the table is working properly and implementing a scrollable feature for the

Currently, I am facing a design issue in my Angular Project that I need help with. I am attempting to achieve a scrolling effect on the body of a table while keeping the header fixed. Although I have tried to implement this feature, I have been unsuccess ...

Tips for placing a large image within a small div

I have an image with a ratio of 1920*1300 that I want to be displayed on any device the website is viewed and cover the entire div. Check out my code below: .carousel { width: 100vw; height: 80vh; position: relative; } .carousel a { width: 1 ...

I encountered an error while trying to load the resource from http://premieroptie.nl/wp-content/themes/theme51771/favicon.ico: net::ERR_NAME_NOT_RESOLVED

Upon opening my website URL, computertechnet.nl, I noticed an error when inspecting and checking the console tab. The specific error message is: Failed to load resource: net::ERR_NAME_NOT_RESOLVED for . In addition, a second warning was displayed: G ...

Error in jQuery sortable function occurs when dragging multiple elements

When using the sortable() function on multiple lists, I encountered a persistent bug. To drag more than one item, I added the following code to the start function: e.item.siblings(".selected").appendTo(e.item); However, a new issue arose where the plac ...

A guide to saving an ArrayBuffer as a file using JavaScript

I am currently developing a file uploader for the Meteor framework. The approach involves breaking down the file on the client side from an ArrayBuffer into small packets of 4096 bits, which are then sent to the server through a Meteor.method. The abridge ...

What is the best way to incorporate sound into a button using HTML or CSS for maximum impact?

Can anyone help me with a school project? I need to make a button play a sound when clicked. I've tried using both the <button> and <audio> tags, but they don't seem to be working for me. Perhaps CSS could be a solution. So far, the o ...

Converting string literals to an array of enums

I have a scenario where I am getting the following data in an API response: { "roles": [ "ADMIN", "USER" ] } The response always includes an array of roles (USER, PRESENTER, ORGANIZER, and ADMIN). I am looking to transform this into a valid TypeScript a ...

Implementing a sorting mechanism for ajax data retrieval

Currently, I am using the code below to save HTML created with jQuery in a database and retrieve it later: $('div[read]').each(function(){ var kelas = $(this).attr('kelas'); $.post('admin.php',{kelas:kelas,id:id},func ...

Encountered an error while trying to access the 'add' property of an undefined object in Flatpickr integration with Vue.js

I'm currently attempting to integrate flatpickr into a Vue component that will then send dates to an eventHub. Unfortunately, I'm encountering difficulties as flatpickr appears to be unable to locate the input field. The structure of my wrapper ...

Encountered an issue while building npm: "Error: Unable to locate module @restart/context

Lately, I've encountered an issue with npm build after upgrading to the latest version of react-bootstrap (1.0.0-beta.6). While creating an optimized production build... Failed to compile. Module not found: '@restart/context/forwardRef'. P ...

Empty body detected in Jquery AJAX request with Django REST running in a Docker environment

Using JavaScript to load a template called index.html from the /static directory. The JavaScript code in app.js: var obj = new Object(); obj.startTime = "123"; obj.endTime = "456"; console.log("fetchNext "+JSON.stringify(obj)); v ...

Which tool would be better for starting a new Angular project: angular-seed or yeoman?

I'm having trouble deciding on the best approach to create a new AngularJS application. There seem to be various methods available, such as using angular-seed from https://github.com/angular/angular-seed or yeoman - http://www.sitepoint.com/kickstar ...

Is javascript or ajax the best choice for updating a database in asp.net mvc?

I need help with updating a row in my database based on a change event from a dropdown list. I am not sure whether to use javascript or ajax for this purpose as I want to avoid page refresh. Any recommendations on which method is best and where I can find ...

Changing the appearance of the navigation bar from a horizontal list to a vertical list for the mobile version of a website - bullets are not displaying

I am in the process of creating a mobile-friendly version of a website, and in order to achieve this, I need to switch a navbar from a display:inline-style list to a bulleted list. Below are the HTML and CSS files for a simplified version of this: ul li ...

Tips for integrating media queries with styles applied through a toggle function

Currently, I am facing an issue with my mobile menu. It is toggled by JavaScript code when the user clicks the mobile menu icon. The main problem arises when resizing the screen from a mobile view to a larger view - the menu remains open. I attempted to ...

Adjusting the size of a DIV based on the number of characters entered in the text field

I have created a text box that dynamically prints out the entered text in a div below as it is typed. The current setup allows for 24 characters to be displayed in the DIV before text wrapping occurs. My goal is to double the height of the DIV for every ad ...

What is the process for retrieving the value of the 2nd td by clicking on the checkbox in the 1st td with JavaScript

When I click on "in", I am looking to retrieve the value of "out". This can be easily understood by referring to the image below: The timesheet displayed is generated using an array. All the data is stored in the array and needs to be presented in a table ...

Invoking a .js file within an UpdatePanel from the CodeBehind

I have been dedicating my time to self-teach ASP.NET and JavaScript for a project, and I've hit a roadblock that has consumed dozens of hours. After discovering a fantastic drag-and-drop JavaScript list online, I copied the provided source code and o ...