One of the ways to do this is by using the attribute position: absolute
in his CSS. This way you can use a fixed value to position your element through the property left
and top
of CSS. The disadvantage may occur when the screen is resized.
To calculate and obtain the value of the horizontal distance, we will use the property clientX
of the object ev
. The estate clientY
will give us the vertical position of the object.
However, this is not enough, because the captured value will be obtained based on the beginning of the object (and not from where it was clicked)
To correct this flaw, we’ll have to capture the position X
and Y
of the object and subtract with the position clientX
and clientY
, respectively. This way we will capture, more precisely, the initial point of the click mouse.
Once this is done, we just need to capture the final position of the mouse and subtract with the difference obtained above.
It seems a little complicated, but I’ll be leaving a code with the explanation of step by step.
Example:
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
/* Armanezaremos as coordenadas do evento */
ev.dataTransfer.setData("left", ev.clientX);
ev.dataTransfer.setData("top", ev.clientY);
}
function drop(ev) {
ev.preventDefault();
const data = ev.dataTransfer.getData("text");
const clone = document.getElementById(data).cloneNode(true)
clone.id = new Date().getMilliseconds()
/**
* Utilizamos esta função para capturar a posição
* relativa do objeto ao viewport
*/
const rect = document.getElementById(data).getBoundingClientRect()
/**
* Aqui, iremos obter a diferença entre a posição inicial
* do mouse (ao ser pressionado) com a posição relativa
* do objeto inicial.
*
* Este cálculo servirá para corrigir a posição final
*/
let left = ev.dataTransfer.getData("left") - rect.left
let top = ev.dataTransfer.getData("top") - rect.top
/**
* Finalmente iremos capturar a posição final do mouse
* e corrigir com os valores acima
*/
clone.style.left = `${ev.clientX - left}px`
clone.style.top = `${ev.clientY - top}px`
ev.target.appendChild( clone );
}
#etiqueta {
width: 400px;
height: 100px;
padding: 10px;
border: 1px solid #aaaaaa;
margin: 0 auto;
}
#toolbox {
width: 150px;
height: 500px;
padding: 10px;
border: 1px solid #aaaaaa;
position: absolute;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
#etiqueta label { position: absolute }
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script type="text/javascript" src="js/script.js"></script>
</head>
<body>
<div id="toolbox">
<ul>
<label id ="lblDesc" draggable="true" ondragstart="drag(event)">@Descrição</label>
<label id ="lblPrec" draggable="true" ondragstart="drag(event)">@Preço</label>
<label id ="lblSku" draggable="true" ondragstart="drag(event)">@Sku</label>
</ul>
</div>
<div id="etiqueta" ondrop="drop(event)" ondragover="allowDrop(event)">
</div>
<br>
</body>
</html>