Create and position divs relative to parent - javascript

I am trying to create(and position) rectangle divs on a parent div. The created div should be positioned relative. Here is a working jsfiddle example -> Just draw some rectangles by holding mouse button.
var newRect = null;
var offset = $('#page').offset();
function point(x, y) {
this.x = x;
this.y = y;
}
function rect(firstPoint) {
this.firstPoint = firstPoint;
this.div = document.createElement("div");
this.div.style.position = "relative";
this.div.style.border = "solid 1px grey";
this.div.style.top = this.firstPoint.y+"px";
this.div.style.left = this.firstPoint.x+"px";
this.div.style.width = "0px";
this.div.style.height = "0px";
$("#page").append(this.div);
}
$("#page").mousedown(function (e) {
if(e.which == 1) {
var x = e.pageX - offset.left;
var y = e.pageY - offset.top;
newRect = new rect(new point(x, y));
}
});
$("#page").mousemove(function (e) {
if(newRect) {
newRect.div.style.width = Math.abs(newRect.firstPoint.x-(e.pageX - offset.left))+"px";
newRect.div.style.height = Math.abs(newRect.firstPoint.y-(e.pageY - offset.top))+"px";
}
});
$("#page").mouseup(function (e) {
if(e.which == 1 && newRect != null) {
if(Math.abs(newRect.firstPoint.x-(e.pageX - offset.left)) < 10) {
$("#"+newRect.div.id).remove();
newRect = null;
return;
}
$("#"+newRect.div.id).on('mousedown', function (e) {
e.stopImmediatePropagation();
});
newRect = null;
}
});
#page{
width: 210mm;
height: 297mm;
border:solid 2px #6D6D6D;
cursor: crosshair;
background-color: white;
float:left;
background-repeat: no-repeat;
background-size: contain;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="page">
</div>
After drawing the first rectangle, which is positioned correctly, each rectangle is positioned false. I think that there is something wrong with the calculation of the position... maybe someone can give me a hint.

Change
this.div.style.position = "relative";
to
this.div.style.position = "absolute";
Bonus: Here's a version that allows you to draw in any direction: https://jsfiddle.net/g4z7sf5c/5/
I simply added this code to the mousemove function:
if (e.pageX < newRect.firstPoint.x) {
newRect.div.style.left = e.pageX + "px";
}
if (e.pageY < newRect.firstPoint.y) {
newRect.div.style.top = e.pageY + "px";
}

Related

How to use vanilla script to bounce elements from each other

I've tried adding the top and left changes, and margin (with different positioning changes too) changes to each element if one approaches another but only the margin change works once. Is there a way to make them work more consistently?
This is where I've used a function to add the event listeners:
var three = document.getElementById('three');
var test = document.getElementById('test');
var two = document.getElementById('two');
var obj = null;
function testmovea(object, event) {
obj = document.getElementById(object.id);
document.addEventListener("mousemove", move);
}
function move(event) {
obj.innerText = event.clientX + ' ' + event.clientY;
obj.style.position = 'absolute';
obj.style.left = event.clientX + "px";
obj.style.top = event.clientY + "px";
three.addEventListener('mouseover', borders);
three.addEventListener('mouseleave', bordersOff);
two.addEventListener('mouseenter', bTwo);
test.addEventListener('mouseenter', bTest);
two.addEventListener('mouseleave', bTwoReset);
test.addEventListener('mouseleave', bTestReset);
document.addEventListener("mouseup", stopMove);
}
function bTwo() {
two.style.margin = "10%";
}
function bTwoReset() {
two.style.margin = "0%";
}
function bTest() {
test.style.margin = "10%";
}
function bTestReset() {
test.style.margin = "0%"
}
This is the mouse stop event I use:
function stopMove() {
document.removeEventListener('mousemove', move);
test.removeEventListener('mouseover', bTest);
two.removeEventListener('mouseover', bTwo);
test.removeEventListener('mouseleave', bTestReset);
two.removeEventListener('mouseleave', bTwoReset);
}
the testmovea function relies on a onmousedown property defined for a DOM element of the page
Update:
I've managed to get it to partially work:
function collide(el1, el2) {
if(twoBoundX >= threeBoundY || threeBoundY >= twoBoundX) {
two.style.margin = + event.clientX + "px";
two.style.margin = + event.clientY + "px";
}
}
where twoBoundX and threeBoundY are getBoundingClientRect() of the respective elements
Here's the full code snippet:
<html>
<head>
<style type="text/css">
#two {
border: 1px solid black;
padding: 1%;
margin: 1%;
margin-top: 10%;
width: 10%;
}
#three {
border: 1px solid black;
padding: 1%;
margin-top: 2%;
}
</style>
</head>
<body>
<div id="two" onmousedown="testmovea(this, event)" onclick="currentTwoPos()">
stop movement
</div>
<div id="three" onmousedown="testmovea(this)">Expand div</div>
<div style="height: 30%" id="two" contenteditable="true">
some contenteditable</div>
</body>
<script>
var three = document.getElementById('three');
var two = document.getElementById('two');
const twoBound = two.getBoundingClientRect();
const threeBound = three.getBoundingClientRect();
var threeBoundX = threeBound.x;
var threeBoundY = threeBound.y;
var twoBoundX = twoBound.x;
var twoBoundY = twoBound.y;
var twoBoundBottom = null;
var twoBoundTop = null;
var obj = null;
function collide(el1, el2) {
if(twoBoundX >= threeBoundY || threeBoundY >= twoBoundX) {
two.style.left = event.clientX + "px";
two.style.top = event.clientY + "px";
three.style.left = event.clientX + "px";
three.style.top = event.clientY + "px";
}
}
function testmovea(object, event) {
obj = document.getElementById(object.id);
document.addEventListener("mousemove", move);
}
function move(event) {
obj.innerText = event.clientX + ' ' + event.clientY;
obj.style.position = 'absolute';
obj.style.left = event.clientX + "px";
obj.style.top = event.clientY + "px";
two.addEventListener('mouseover', collide);
three.addEventListener('mouseover', collide);
document.addEventListener("mouseup", stopMove);
}
function stopMove() {
mousemove = false;
document.removeEventListener('mousemove', move);
three.removeEventListener('mouseover', collide);
two.removeEventListener('mouseover', collide);
}
</script>
</html>
collision detection
You need to define a function that checks whether two of your shapes collide. If you only have rectangles whose vertex are parallel with the OX and OY vertexes, it would look like this:
function areColliding(r1, r2) {
return !(
(r1.x > r2.x + r2.w) ||
(r1.x + r1.w < r2.x) ||
(r1.y > r2.y + r2.h) ||
(r1.y + r1.h < r2.y)
);
}
Of course, if some rotation or even other shapes are involved into your problem, then you need to extend/adjust the collision detector accordingly.
a shared function
You need to create a function that would receive the current status of the elements and the move that happens. It would look like this:
function handleMove(currentPositions, proposedPositions) {
while (!validPositions(proposedPositions)) {
proposedPositions = generateNewPositions(currentPositions, handleCollisions(proposedPositions));
}
refreshUI(proposedPositions);
}
currentPositions is the set of positions your elements currently have
proposedPositions is the set of positions your elements are going to have if there are no collisions
validPositions checks for any pair of shapes that would collide and returns true if none of those pair collide and false if at least one such pair collides
proposedPositions is being refreshed while there are still collisions
generateNewPositions is your handler for collision-based changes
handleCollisions effectuates changes to avoid collision
refreshUI refreshes the UI
event handling
your mouse events should handle change updates by loading all the positions of your elements and calling this shared functionality.
Note: If you have further problems, then you might need to create a reproducible example so we could see your exact structure, styling and code as well.
<html>
<head>
<style type="text/css">
#two {
border: 1px solid black;
width: 10%;
padding: 1%;
margin: 1%;
margin-top: 10%;
}
#three {
border: 1px solid black;
padding: 1%;
margin-top: 2%;
}
</style>
</head>
<body>
<div id="two" onmousedown="testmovea(this, event)" style="position: relative;">
stop movement
</div>
<div id="three" onmousedown="testmovea(this)" style="position: relative;">Expand div</div>
<!--<div style="height: 30%; position: relative;" id="two" contenteditable="true">
some contenteditable</div>-->
</body>
<script>
var three = document.getElementById('three');
var two = document.getElementById('two');
let moveStarted = false;
function collide() {
const first = two.getBoundingClientRect();
const second = three.getBoundingClientRect();
if (!(
(first.x + first.width < second.x) ||
(second.x + second.width < first.x) ||
(first.y + first.height < second.y) ||
(second.y + second.height < first.y)
)) {
two.style.left = event.clientX + "px";
two.style.top = event.clientY + "px";
three.style.left = event.clientX + "px";
three.style.top = event.clientY + "px";
}
}
function testmovea(object, event) {
obj = document.getElementById(object.id);
if (!moveStarted) {
document.addEventListener("mousemove", move);
moveStarted = true;
}
}
function move(event) {
//obj.innerText = event.clientX + ' ' + event.clientY;
obj.style.left = event.clientX + "px";
obj.style.top = event.clientY + "px";
if (!obj.classList.contains("dragged")) obj.classList.add("dragged");
collide(obj);
}
function stopMove() {
mousemove = false;
if (moveStarted) {
document.removeEventListener('mousemove', move);
moveStarted = false;
}
}
document.addEventListener("mouseup", stopMove);
</script>
</html>

Javascript Prevent Draggable div outside parent div

I have draggable div. I want this draggable div to be restricted within parent using javascript. I know how to prevent draggable div using jquery UI draggable plugin. But I am not sure how to restrict draggable using native javascript. Please find below my code:
<!DOCTYPE HTML>
<html>
<head>
<style>
.draggabletarget {
float: left;
width: 100px;
height: 35px;
margin: 15px;
padding: 10px;
border: 1px solid #aaaaaa;
}
</style>
</head>
<body>
<div class="parent" style="border:1px solid red;height:600px;width:600px;">
<div class="draggabletarget" ondragstart="dragStart(event)" ondrag="dragging(event)" draggable="true" id="dragtarget">
<p >Drag me!</p>
</div>
</div>
<script>
function dragStart(event) {
event.dataTransfer.setData("Text", event.target.id);
}
function dragging(event) {
document.getElementById("demo").innerHTML = "The p element is being dragged";
}
function allowDrop(event) {
event.preventDefault();
}
</script>
</body>
</html>
In this code i have a div with class parent. I want my draggable div whose class is draggabletarget shouldn't drag outside the parent div. How can i do this in native javascript. Please suggest
function $(el){
return document.getElementById(el);
}
var isDragging = false;
var tzdragg = function(){
return {
move : function(divid,xpos,ypos){
var a = $(divid);
$(divid).style.left = xpos + 'px';
$(divid).style.top = ypos + 'px';
},
setDragging : function() {
isDragging = true;
},
resetDragging : function() {
isDragging = false;
},
startMoving : function(evt){
evt = evt || window.event;
var posX = evt.clientX,
posY = evt.clientY,
a = $('elem'),
divTop = a.style.top,
divLeft = a.style.left;
divTop = divTop.replace('px','');
divLeft = divLeft.replace('px','');
var diffX = posX - divLeft,
diffY = posY - divTop;
document.onmousemove = function(evt){
evt = evt || window.event;
var posX = evt.clientX,
posY = evt.clientY,
aX = posX - diffX,
aY = posY - diffY;
var boun=document.getElementById("parent").offsetWidth-document.getElementById("elem").offsetWidth;
if((aX>0)&&(aX<boun)&&(aY>0)&&(aY<boun))
tzdragg.move('elem',aX,aY);
}
},
stopMoving : function(){
var a = document.createElement('script');
document.onmousemove = function(){}
if(!isDragging) {
console.log('clicked');
}
},
}
}();
#elem
{
position: absolute;
width: 100px;
height: 100px;
background-color: black;
-webkit-user-select: none;
-moz-user-select: none;
-o-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
cursor: default;
}
<div style="height:400px; width:400px; border:solid 1px black;position: absolute;top: 0;
left: 0;" id='parent'>
<div id='elem' onmousedown='tzdragg.resetDragging();tzdragg.startMoving(event);' onmouseup='tzdragg.stopMoving();' onmousemove='tzdragg.setDragging();'
>
</div>
</div>
If you need to use pure javascript.
<div id='container'>Drag the box around</div>
<div id='slider'></div>
body {
background-color : lightgray;
}
#container {
position : fixed;
border-radius : 10px;
background-color : brown;
border : solid 1px black;
font : 15px arial,sans-serif;
text-align : center;
}
#slider {
position : fixed;
border-radius : 10px;
background: black;
}
div {
cursor : default;
}
document.onselectstart = function(e) {
e.preventDefault();
return false;
}
var slider = document.getElementById('slider'),container = document.getElementById('container');
document.mouseState = 'up';
slider.mouseState = 'up';
slider.lastMousePosY = null;
slider.lastMousePosX = null;
slider.proposedNewPosY = parseInt(slider.style.top, 10); //converts '10px' to 10
slider.proposedNewPosX = parseInt(slider.style.left, 10);
slider.style.top = '40px';
slider.style.left = '40px';
slider.style.height = '60px';
slider.style.width = '60px';
container.style.top = '20px';
container.style.left = '20px';
container.style.height = '200px';
container.style.width = '400px';
document.onmousedown = function() {
document.mouseState = 'down';
};
document.onmouseup = function() {
document.mouseState = 'up';
slider.mouseState = 'up';
};
slider.onmousedown = function(e) {
slider.lastMousePosY = e.pageY;
slider.lastMousePosX = e.pageX;
slider.mouseState = 'down';
document.mouseState = 'down';
};
slider.onmouseup = function(e) {
slider.mouseState = 'up';
document.mouseState = 'up';
};
var getAtInt = function getAtInt(obj, attrib) {
return parseInt(obj.style[attrib], 10);
};
document.onmousemove = function(e) {
if ((document.mouseState === 'down') && (slider.mouseState === 'down')) {
slider.proposedNewPosY = getAtInt(slider, 'top') + e.pageY - slider.lastMousePosY;
slider.proposedNewPosX = getAtInt(slider, 'left') + e.pageX - slider.lastMousePosX;
if (slider.proposedNewPosY < getAtInt(container, 'top')) {
slider.style.top = container.style.top;
} else if (slider.proposedNewPosY > getAtInt(container, 'top') + getAtInt(container, 'height') - getAtInt(slider, 'height')) {
slider.style.top = getAtInt(container, 'top') + getAtInt(container, 'height') - getAtInt(slider, 'height') + 'px';
} else {
slider.style.top = slider.proposedNewPosY + 'px';
}
if (slider.proposedNewPosX < getAtInt(container, 'left')) {
slider.style.left = container.style.left;
} else if (slider.proposedNewPosX > getAtInt(container, 'left') + getAtInt(container, 'width') - getAtInt(slider, 'width')) {
slider.style.left = getAtInt(container, 'left') + getAtInt(container, 'width') - getAtInt(slider, 'width') + 'px';
} else {
slider.style.left = slider.proposedNewPosX + 'px';
}
slider.lastMousePosY = e.pageY;
slider.lastMousePosX = e.pageX;
}
};
here is working example

How to draw rectangle box over an image present inside div?

I have developed a page where I dynamically import images and display them inside a div tag. Now i wanted to draw an rectangle over the image, and it should start from any point on the image.
I referred many sources and tried to implement the idea from it.
<style>
#rubberBand {
position: absolute;
visibility: hidden;
width: 0px; height: 0px;
border: 2px solid red;
}
</style>
<div class="imageside" id="picture"> </div>
<div ID="rubberBand"></div>
In the above code, the image is display at the div id "picture". Till this part of the code works fine.
var pic, rubber, pt = { x: 0, y: 0 };
picture= getpicture();
function getpicture(){
pic= document.getElementById('picture')
pic.innerHTML= getgImage(event.target.dataset.number);
}
function startRubber (evt) {
var ev = evt || window.event,
rs = rubber.style,
bb = pic.innerHTML.getBoundingClientRect();
console.dir(ev);
rs.left = bb.left + 'px';
rs.top = bb.top + 'px';
rs.width = bb.width + 'px';
rs.height = bb.height + 'px';
rs.display = 'block';
pt = { x: ev.clientX - bb.left, y: ev.clientY - bb.top };
return false;
}
function stopRubber () {
rubber.style.display = 'none';
}
function moveRubber (evt) {
var ev = evt || window.event;
rubber.style.left = (evt.clientX - pt.x) + 'px';
rubber.style.top = (evt.clientY - pt.y) + 'px';
}
rubber = document.getElementById('rubberBand');
pic = document.getElementById('picture').innerHTML;
pic.onmousedown = startRubber;
document.onmouseup = stopRubber;
document.onmousemove = moveRubber;
In the above code, the function getpicture() is responsible to display the images dynamically. When i execute the above code, the image displays on the page, but I am not able to draw the rectangle over the image. In console, no errors. Can someone help me out with problem and help me to draw the rectangle over the image.
check this out.
https://jsfiddle.net/2at9n7ye/3/
your issue is that you are accessing the pic variable before you load it.
var pic, rubber, pt = {
x: 0,
y: 0
};
picture = getpicture();
function getpicture() {
pic = document.getElementById('picture');
pic.innerHTML = "<img src='https://i.imgur.com/mvMlmMb.jpg' id='img' width='100px' height='100px'/>";
}
function startRubber(evt) {
var ev = evt || window.event,
rs = rubber.style,
bb = pic.getBoundingClientRect
rs.left = bb.left + 'px';
rs.top = bb.top + 'px';
rs.width = bb.width + 'px';
rs.height = bb.height + 'px';
rs.display = 'block';
pt = {
x: ev.clientX - bb.left,
y: ev.clientY - bb.top
};
return false;
}
function stopRubber() {
rubber.style.display = 'none';
}
function moveRubber(evt) {
var ev = evt || window.event;
rubber.style.left = (evt.clientX - pt.x) + 'px';
rubber.style.top = (evt.clientY - pt.y) + 'px';
}
(function() {
rubber = document.getElementById('rubberBand');
pic = document.getElementById('picture');
pic.addEventListener("mousedown", startRubber);
document.addEventListener("mouseup", stopRubber);
document.addEventListener("mousemove", moveRubber);
})();

Draggable element gets stuck near edges

Dragging the element seems to make it get stuck randomly before touching the edges of its parent container. Would someone be able to spot why this is going on?
On a side note, I could not get the remembered position transferred to "updateDrag" correctly.
And no, I don't want any jQuery solution, like one created with jQuery UI.
let $container = document.getElementById('container');
let $element = document.getElementById('element');
let mousePosition;
let offset = [0, 0];
let isDown = false;
function initDrag(event) {
isDown = true;
// Element also remembers previous position wrong
// offset = [
// $element.offsetLeft - event.clientX,
// $element.offsetTop - event.clientY
// ];
offset = [
0,
0
];
}
function updateDrag(event) {
event.preventDefault();
if (isDown) {
mousePosition = {
x: event.clientX,
y: event.clientY
};
let diffY = mousePosition.y - offset[1];
let diffX = mousePosition.x - offset[0];
if (diffY >= 0 && diffY + $element.offsetHeight <= $container.offsetHeight) {
$element.style.top = (mousePosition.y + offset[1]) + 'px';
}
if (diffX >= 0 && diffX + $element.offsetWidth <= $container.offsetWidth) {
$element.style.left = (mousePosition.x + offset[0]) + 'px';
}
}
}
function haltDrag() {
isDown = false;
}
$element.addEventListener('mousedown', initDrag, false);
document.addEventListener('mouseup', haltDrag, false);
document.addEventListener('mousemove', updateDrag, false);
#container {
position: relative;
top: 10px;
left: 10px;
height: 300px;
width: 300px;
background-color: green;
}
#element {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background: red;
color: blue;
}
<div id="container">
<div id="element"></div>
</div>

position bug in draggable div

I have div that behaves a little strange,
When I move it the first time its working good, but the second time the position starts to bug
I have position: absolute in the main div, but thats all.
Any idea how to clean from bugging ?
http://jsfiddle.net/dymond/tQdFZ/14/ <-- the jsfiddle
javascript.
var draggable = document.getElementsByClassName('hand'),
draggableCount = draggable.length,
i, currZ = 1;
function startDrag(evt) {
var diffX = evt.clientX - this.offsetLeft,
diffY = evt.clientY - this.offsetTop,
that = this;
this.style.opacity = "0.5";
this.style.zIndex = currZ++;
function moveAlong(evt) {
that.parentNode.style.left = (evt.clientX - diffX) + 'px';
that.parentNode.style.top = (evt.clientY - diffY) + 'px';
}
function stopDrag() {
document.removeEventListener('mousemove', moveAlong);
document.removeEventListener('mouseup', stopDrag);
changeClass()
}
function changeClass() {
var diceClass = document.getElementsByClassName("hand");
for (var i = 0; i < diceClass.length; i++) {
diceClass[i].style.opacity = "1";
}
}
document.addEventListener('mouseup', stopDrag);
document.addEventListener('mousemove', moveAlong);
}
for (i = 0; i < draggableCount; i += 1) {
draggable[i].addEventListener('mousedown', startDrag);
}
Css
**.draggable {
position: absolute;
width: 100px;
height: 100px;
background: red;
}
.hand{
cursor : move;
width: 98px;
min-height: 16px;
background: yellow;
border:1px solid black;
}
textarea{
padding-top:20px;
resize : none;
overflow : hidden;
background : transparent;
width:95px;
border:none;
}
offsetLeft and offsetTop of this is always 0 because this refers to .hand not .dragabble so this:
var diffX = evt.clientX - this.offsetLeft,
diffY = evt.clientY - this.offsetTop,
Should be this:
var diffX = evt.clientX - this.parentNode.offsetLeft,
diffY = evt.clientY - this.parentNode.offsetTop,
Updated Fiddle: http://jsfiddle.net/knoxzin1/tQdFZ/15/

Categories