Reputation: 35
Good afternoon I am trying to find a way to allow an ellipse (dot) move over an image area only (canvas) and find a way to retrieve the coordinate to store in a database in order to retrieve it later on and be able to redraw the ellipse without being draggable.
Right now, I have a rectangle instead of a dot, the rectangle is not limited to the image area and I am not sure how I can retrieve the coordinate of it to store it using asp.net core MVC. Thank you.
//Make the DIV element draggagle:
dragElement(document.getElementById("mydiv"));
function dragElement(elmnt) {
var pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
/* if present, the header is where you move the DIV from:*/
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
/* otherwise, move the DIV from anywhere inside the DIV:*/
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
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 = elementDrag;
}
function elementDrag(e) {
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;
}
}
#mydiv {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<p>Click and hold the mouse button down while moving the Ellipse element</p>
<svg viewBox="0 0 400 400" width="400" height="400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<image stroke="null" xlink:href="https://www.pngkey.com/png/full/8-80588_car-cartoon-png-group-picture-pollution-voiture-png.png" id="svg_1" height="400" width="400" y="0" x="0"/>
</g>
<div id="mydiv">
<div id="mydivheader">
<g data-id="00000000-0000-0000-0000-000000000000" class="draggable">
<ellipse class="0" cx="3" cy="3" rx="3" ry="3" style=""></ellipse>
</g>
</div>
</div>
</svg>
Upvotes: 0
Views: 183
Reputation: 13070
Why not use the build-in HTML Drag and Drop API? In your markup you mix HTML and SVG – that is why the ellipse does not show up. The logic is fine, but I think it makes sense to use drag and drop.
If the image of the car needs to be replaced by an SVG don't mix up the ellipse with that SVG.
The style of the div#drop
has the property position:relative
. That is on purpose – it is important if you move the div#drop
to some other position in the document.
I changed the way that the relative position (relX,relY) is calculated. It now uses Element.getBoundingClientRect(). I also replaced e.layerX/Y
with e.offsetX/Y
.
//Make the DIV element draggagle:
var mydiv = document.getElementById("mydiv");
var drop = document.getElementById("drop");
mydiv.addEventListener('dragstart', e => {
let data = JSON.stringify({
id: e.target.id,
x: e.offsetX,
y: e.offsetY
});
e.dataTransfer.setData("text/plain", data);
});
drop.addEventListener('dragover', e => {
e.preventDefault();
e.dataTransfer.dropEffect = "move";
});
drop.addEventListener('drop', e => {
e.preventDefault();
let data = JSON.parse(e.dataTransfer.getData("text/plain"));
let mydiv = document.getElementById(data.id);
let dropRect = drop.getBoundingClientRect();
let relX = e.clientX - data.x - dropRect.x;
let relY = e.clientY - data.y - dropRect.y;
console.log('relative pos:', `${relX},${relY}`);
mydiv.style.left = `${relX}px`;
mydiv.style.top = `${relY}px`;
});
body {
/* Padding added just to show that
* using getBoundingClientRect() is working.
*/
padding: 10px 0 0 20px;
}
#drop {
position: relative;
}
#mydiv {
position: absolute;
z-index: 9;
text-align: center;
cursor: move;
left: 0;
top: 0;
}
#mydiv ellipse {
fill: green;
}
<p>Click and hold the mouse button down while moving the Ellipse element</p>
<div id="drop">
<img src="https://www.pngkey.com/png/full/8-80588_car-cartoon-png-group-picture-pollution-voiture-png.png" width="400" />
<div id="mydiv" draggable="true">
<svg viewBox="0 0 6 6" width="20" height="20" xmlns="http://www.w3.org/2000/svg">
<g data-id="00000000-0000-0000-0000-000000000000" class="draggable">
<ellipse cx="3" cy="3" rx="3" ry="3" />
</g>
</svg>
</div>
</div>
OP ask if the position of the ellipse can be updated using form inputs. In the following example I added a form for updating the values. The values of the form will also update when the ellipse is moved around.
//Make the DIV element draggagle:
var mydiv = document.getElementById("mydiv");
var drop = document.getElementById("drop");
mydiv.addEventListener('dragstart', e => {
let data = JSON.stringify({
id: e.target.id,
x: e.offsetX,
y: e.offsetY
});
e.dataTransfer.setData("text/plain", data);
});
drop.addEventListener('dragover', e => {
e.preventDefault();
e.dataTransfer.dropEffect = "move";
});
drop.addEventListener('drop', e => {
e.preventDefault();
let data = JSON.parse(e.dataTransfer.getData("text/plain"));
let mydiv = document.getElementById(data.id);
let dropRect = drop.getBoundingClientRect();
let relX = e.clientX - data.x - dropRect.x;
let relY = e.clientY - data.y - dropRect.y;
// update the form values
let form = document.forms.form01;
form.x.value = relX;
form.y.value = relY;
// update the position of the ellipse
mydiv.style.left = `${relX}px`;
mydiv.style.top = `${relY}px`;
});
document.forms.form01.addEventListener('change', e => {
let form = e.target.form;
let x = parseInt(form.x.value);
let y = parseInt(form.y.value);
// update the position of the ellipse
mydiv.style.left = `${x}px`;
mydiv.style.top = `${y}px`;
});
body {
/* Padding added just to show that
* using getBoundingClientRect() is working.
*/
padding: 10px 0 0 20px;
}
#drop {
position: relative;
}
#mydiv {
position: absolute;
z-index: 9;
text-align: center;
cursor: move;
left: 0;
top: 0;
}
#mydiv ellipse {
fill: green;
}
<p>Click and hold the mouse button down while moving the Ellipse element OR input X anf Y values in the form (and hit enter):</p>
<form name="form01">
<label>X: <input name="x" type="text"/></label>
<label>Y: <input name="y" type="text"/></label>
</form>
<div id="drop">
<img src="https://www.pngkey.com/png/full/8-80588_car-cartoon-png-group-picture-pollution-voiture-png.png" width="400" />
<div id="mydiv" draggable="true">
<svg viewBox="0 0 6 6" width="20" height="20" xmlns="http://www.w3.org/2000/svg">
<g data-id="00000000-0000-0000-0000-000000000000" class="draggable">
<ellipse cx="3" cy="3" rx="3" ry="3" />
</g>
</svg>
</div>
</div>
Upvotes: 1