Open LePhenix47 opened 1 year ago
We will create a function that will take in a container as an HTMLElement
and a position as a number
for the X or Y coordinate of the mouse
function getClosestElement(container, position) {
// Implementation steps go here
}
Inside the function, we select all the draggable elements that we are not dragging
function getClosestElement(container, position) {
const draggableElements = [...container.querySelectorAll(".draggable:not(.dragging)")];
// Implementation continues...
}
We're going to create a closestElement
to store the element closest to the draggable by default set to null
And closestOffset
to store the closest offset by default set to -∞ in order to ensure that the first valid offset encountered during the iteration will always be considered as the closest offset
function getClosestElement(container, position) {
const draggableElements = [...container.querySelectorAll(".draggable:not(.dragging)")];
let closestElement = null;
let closestOffset = Number.NEGATIVE_INFINITY;
// Implementation continues...
}
We can get the DOM Rect using the getBoundingClientRect
const draggableRect = draggable.getBoundingClientRect()
currentOffset
using a formula:If vertical DnD:
const currentOffset = position - draggableRect.top - draggableRect.height / 2;
If horizontal DnD:
const currentOffset = position - draggableRect.left - draggableRect.width/2
In this example we'll take a vertical DnD:
function getClosestElement(container, position) {
const draggableElements = [...container.querySelectorAll(".draggable:not(.dragging)")];
let closestElement = null;
let closestOffset = Number.NEGATIVE_INFINITY;
for (const draggable of draggableElements) {
const draggableRect = draggable.getBoundingClientRect();
const currentOffset = position - draggableRect.top - draggableRect.height / 2;
// Implementation continues...
}
}
We need to verify it's above the element (currentOffset < 0)
AND has the offset nearer to 0 (currentOffset > closestOffset)
.
If that's the case, set the closestElement
to the current draggable (not dragging) and also set the closestOffset
to be the currentOffset
function getClosestElement(container, position) {
const draggableElements = [...container.querySelectorAll(".draggable:not(.dragging)")];
let closestElement = null;
let closestOffset = Number.NEGATIVE_INFINITY;
for (const draggable of draggableElements) {
const draggableRect = draggable.getBoundingClientRect();
const currentOffset = position - draggableRect.top - draggableRect.height / 2;
const isAboveAfterElement = currentOffset < 0;
const hasOffsetNearerToZero = currentOffset > closestOffset;
if (isAboveAfterElement && hasOffsetNearerToZero) {
closestOffset = currentOffset;
closestElement = draggable;
}
}
// Implementation continues...
}
function getClosestElement(container, position) {
const draggableElements = [...container.querySelectorAll(".draggable:not(.dragging)")];
let closestElement = null;
let closestOffset = Number.NEGATIVE_INFINITY;
for (const draggable of draggableElements) {
const draggableRect = draggable.getBoundingClientRect();
const currentOffset = position - draggableRect.top - draggableRect.height / 2;
const isAboveAfterElement = currentOffset < 0;
const hasOffsetNearerToZero = currentOffset > closestOffset;
if (isAboveAfterElement && hasOffsetNearerToZero) {
closestOffset = currentOffset;
closestElement = draggable;
}
}
return closestElement;
}
This completes the step-by-step explanation of how to create a basic drag and drop functionality
How to create a drag and drop (basic)
1) Select all the draggable elements
We need to add a “dragging” class that will serve for our CSS styling on our draggables on
dragstart
and remove it ondragend
:2) Select the containers containing the draggables
We need to add an event listener on
dragover
where we will: