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/
Related
I noticed these resize pointers in the css spec...
https://drafts.csswg.org/css-ui-3/#valdef-cursor-se-resize
Is there a CSS shortcut for 4 corner resizability similar to the one corner ('resize: both') method?
If not, are there known conflicts when combining resizability with a draggable div?
My starting point was here...
https://www.w3schools.com/howto/howto_js_draggable.asp
Any help navigating the posX, posY is appreciated.
notes for getBoundingClient()
———---
| |
|____ | div.getBoundingClientRect()
SE (bottom right):
Height and width / top and left are stationary
SW (bottom left):
Height and width and left / top is stationary
NW (top left):
Height and width top and left
NE (top right):
Height and width and Top / Left is stationary
edit: removed padding and borders.
const myDiv = document.getElementById('mydiv')
let isResizing = false;
//Make the DIV element draggable:
dragElement(myDiv);
function dragElement(elmnt) {
if (!isResizing) {
let 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;
}
}
}
// Resize
(function fourCorners() {
const resizers = document.querySelectorAll('.resizer')
let currentResizer
for (let resizer of resizers) {
resizer.addEventListener('mousedown', mouseDown)
function mouseDown(e) {
currentResizer = e.target
e.preventDefault()
isResizing = true;
let posX = e.clientX;
let posY = e.clientY;
myDiv.addEventListener('mousemove', mouseMove)
myDiv.addEventListener('mouseup', mouseUp)
function mouseMove(e) {
e.preventDefault()
const rect = myDiv.getBoundingClientRect()
if (currentResizer.classList.contains('se')) {
//console.log(currentResizer.classList.value)
myDiv.style.width = rect.width - (posX - e.clientX) + 'px';
myDiv.style.height = rect.height - (posY - e.clientY) + 'px';
} else if (currentResizer.classList.contains('sw')) {
//console.log(currentResizer.classList.value)
myDiv.style.width = rect.width + (posX - e.clientX) + 'px';
myDiv.style.height = rect.height - (posY - e.clientY) + 'px';
myDiv.style.left = rect.left - (posX - e.clientX) + 'px';
} else if (currentResizer.classList.contains('ne')) {
//console.log(currentResizer.classList.value)
myDiv.style.width = rect.width - (posX - e.clientX) + 'px';
myDiv.style.height = rect.height + (posY - e.clientY) + 'px';
myDiv.style.top = rect.top - (posY - e.clientY) + 'px';
} else {
//console.log(currentResizer.classList.value)
myDiv.style.width = rect.width + (posX - e.clientX) + 'px';
myDiv.style.height = rect.height + (posY - e.clientY) + 'px';
myDiv.style.top = rect.top - (posY - e.clientY) + 'px';
myDiv.style.left = rect.left - (posX - e.clientX) + 'px';
}
posX = e.clientX;
posY = e.clientY;
}
function mouseUp(e) {
myDiv.removeEventListener('mousemove', mouseMove)
myDiv.removeEventListener('mouseup', mouseUp)
isResizing = false
}
}
}
})()
* {
margin: 0;
padding : 0;
}
#mydiv {
position: absolute; /* NECESSARY */
background-color: whitesmoke;
box-sizing: border-box;
text-align: center;
/* border: 1px solid #222; */
height: 200px;
width: 200px;
/* resize: both; /* CSS RESIZE */
overflow: hidden; /* CSS RESIZE */
}
#mydivheader {
/* padding: 10px; */
cursor: move;
background-color: dodgerblue;
color: #fff;
}
#content {
color: #000;
margin: 0px;
background-color: whitesmoke;
}
/* ::-webkit-resizer {
position: absolute;
height: 20px;
width: 20px;
border-top-left-radius: 25px;
background-color: #dd0;
z-index: 2;
} */
.resizer {
position: absolute;
height: 20px;
width: 20px;
background-color: #dd0;
z-index: 2;
}
.resizer.nw {
top: -1px;
left: -1px;
cursor: nw-resize;
border-bottom-right-radius: 25px;
}
.resizer.ne {
top: -1px;
right: -1px;
cursor: ne-resize;
border-bottom-left-radius: 25px;
}
.resizer.sw {
bottom: -1px;
left: -1px;
cursor: sw-resize;
border-top-right-radius: 25px;
}
.resizer.se {
bottom: -1px;
right: -1px;
cursor: se-resize;
border-top-left-radius: 25px;
}
<div id="mydiv">
<div class='resizer nw'></div>
<div class='resizer ne'></div>
<div class='resizer sw'></div>
<div class='resizer se'></div>
<div id="mydivheader">Click here to move
<div id='content'>
<div id='image-container'><img height='auto' width='100%' src='https://picsum.photos/600' /></div>
</div>
</div>
</div>
Well if you want to make it nice and easy you could use jQuery to help it resize would probably be the easiest way. Then after you learn how to do it with jQuery you could do it with pure js.
So, you want the resize handle to appear on all four corners? That'll require some bounds checking.
You can modify the offset check in drag to account for any corner and handle the drag as a resize event instead. The code somewhat works for top-left and bottom-right resizing, but doe not work too well with the opposite corners. This is a start.
This is a start:
const cursor = document.querySelector('#cursor');
const cornerThreshold = 4;
const dragStart = e => {
const [ horz, vert ] = getDirection(e, cornerThreshold);
const bounds = e.target.getBoundingClientRect();
const cursor = getCursorType(e);
if (cursor === 'grab') {
e.target.dataset.isDragging = true;
} else {
e.target.dataset.isResizing = true;
}
e.target.dataset.startWidth = bounds.width;
e.target.dataset.startHeight = bounds.height;
e.target.dataset.originX = e.clientX;
e.target.dataset.originY = e.clientY;
e.target.dataset.offsetX = e.clientX - e.target.offsetLeft;
e.target.dataset.offsetY = e.clientY - e.target.offsetTop;
e.target.dataset.dirHorz = horz;
e.target.dataset.dirVert = vert;
e.target.style.zIndex = 999;
};
const dragEnd = e => {
delete e.target.dataset.isDragging;
delete e.target.dataset.offsetX;
delete e.target.dataset.offsetY;
delete e.target.dataset.originX;
delete e.target.dataset.originY;
delete e.target.dataset.startWidth;
delete e.target.dataset.startHeight;
delete e.target.dataset.dirHorz;
delete e.target.dataset.dirVert;
delete e.target.dataset.resizeDirection;
e.target.style.removeProperty('z-index');
e.target.style.removeProperty('cursor');
};
const drag = e => {
e.target.style.cursor = getCursorType(e);
cursor.textContent = `(${e.clientX}, ${e.clientY})`;
if (e.target.dataset.isDragging) {
e.target.style.left = `${e.clientX - parseInt(e.target.dataset.offsetX, 10)}px`;
e.target.style.top = `${e.clientY - parseInt(e.target.dataset.offsetY, 10)}px`;
} else if (e.target.dataset.isResizing) {
const bounds = e.target.getBoundingClientRect();
const startWidth = parseInt(e.target.dataset.startWidth, 10);
const startHeight = parseInt(e.target.dataset.startWidth, 10);
const deltaX = e.clientX - parseInt(e.target.dataset.originX, 10);
const deltaY = e.clientY - parseInt(e.target.dataset.originY, 10);
const originX = parseInt(e.target.dataset.originX, 10);
const originY = parseInt(e.target.dataset.originY, 10);
const dirHorz = parseInt(e.target.dataset.dirHorz, 10);
const dirVert = parseInt(e.target.dataset.dirVert, 10);
if (dirHorz < 0) {
e.target.style.left = `${originX + deltaX}px`;
e.target.style.width = `${startWidth - deltaX}px`
} else if (dirHorz > 0) {
e.target.style.width = `${startWidth + deltaX}px`;
}
if (dirVert < 0) {
e.target.style.top = `${originY + deltaY}px`;
e.target.style.height = `${startHeight - deltaY}px`;
} else if (dirVert > 0) {
e.target.style.height = `${startHeight + deltaY}px`;
}
}
};
const focus = e => { };
const unfocus = e => { e.target.style.removeProperty('cursor'); };
const getDirection = (e, threshold) => {
const bounds = e.target.getBoundingClientRect();
const offsetX = e.clientX - e.target.offsetLeft;
const offsetY = e.clientY - e.target.offsetTop;
const isTop = offsetY <= threshold;
const isLeft = offsetX <= threshold;
const isBottom = offsetY > (bounds.height - threshold);
const isRight = offsetX > (bounds.width - threshold);
if (isTop && isLeft) return [ -1, -1 ];
else if (isTop && isRight) return [ -1, 1 ];
else if (isBottom && isLeft) return [ 1, -1 ];
else if (isBottom && isRight) return [ 1, 1 ];
else return [ 0, 0 ];
};
const getCursorType = (e) => {
if (e.target.dataset.isDragging) {
return 'grabbing';
} else {
const [ horz, vert ] = getDirection(e, cornerThreshold);
const isTop = vert === -1;
const isLeft = horz === -1;
const isBottom = vert === 1;
const isRight = horz === 1;
if ((isTop && isLeft) || (isBottom && isRight)) return 'nwse-resize';
if ((isTop && isRight) || (isBottom && isLeft)) return 'nesw-resize';
}
return 'grab';
};
document.querySelectorAll('.draggable').forEach(draggable => {
draggable.addEventListener('mousedown', dragStart);
draggable.addEventListener('mouseup', dragEnd);
draggable.addEventListener('mousemove', drag);
draggable.addEventListener('mouseenter', focus);
draggable.addEventListener('mouseleave', unfocus);
});
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.container {
position: relative;
width: 60%;
height: 60%;
border: thin solid grey;
}
.square {
position: absolute;
height: 2em;
width: 2em;
}
.color-red { background: red; }
.color-blue { background: blue; }
.color-green { background: green; }
#square-1 { top: 10px; left: 10px; }
#square-2 { top: 50px; left: 50px; }
#square-3 { top: 100px; left: 100px; }
<div class="container">
<div id="square-1" class="square color-red draggable resizable"></div>
<div id="square-2" class="square color-blue draggable resizable"></div>
<div id="square-3" class="square color-green draggable resizable"></div>
</div>
<br />
<div>Cursor: <span id="cursor">(0, 0)</span></div>
I am trying to make a walking animation, the program does that the character goes to the mouse click. but I can't make it when it's moving to change the image and when it's stopping return to the first image.
here is the code for the js file and the css file:
import "./styles.css";
var theThing = document.querySelector("#thing");
var cont = document.querySelector("#contentCont");
cont.addEventListener("click", getClickPosition, false);
function getClickPosition(e) {
theThing.src = "ddd2.gif";
var parentPosition = getPosition(cont);
var xPosition = e.clientX - parentPosition.x - theThing.offsetWidth / 2;
var yPosition = e.clientY - parentPosition.y - theThing.offsetHeight / 2;
var translate3dValue =
"translate3d(" + xPosition + "px," + yPosition + "px,0)";
theThing.style.transform = translate3dValue;
}
function getPosition(element) {
var xPos = 0;
var yPos = 0;
while (element) {
xPos += element.offsetLeft - element.scrollLeft + element.clientLeft;
yPos += element.offsetTop - element.scrollTop + element.clientTop;
element = element.offsetParent;
}
return {
x: xPos,
y: yPos
};
}
body {
background-color: #fff;
padding: 50px;
margin: 0;
}
#contentCont {
width: 600px;
height: 600px;
border: 15px #ededed solid;
overflow: hidden;
background-color: #f2f2f2;
cursor: pointer;
}
#thing {
width: 80px;
height: 80px;
transition: transform 0.7s ease-in;
}
right now its start at image 1 and change to image 2 when walking but doesnt return to image 1 when stopping.
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>
I am making a game and I am using div's instead of canvas.rect's and I want one div to always be inside of another div. I ran into this problem when I made a test script that looked like this.
var mousex, mousey;
function mousepos(e){
mousex = e.clientX;
mousey = e.clientY;
document.getElementById("xy").innerText = mousex + " , " + mousey;
}
function testdiv(){
document.getElementById("testdiv").style.left = mousex;
document.getElementById("testdiv").style.top = mousey;
setTimeout(testdiv, 30);
}
#city{
border: 1px dotted white;
background-color: lightgreen;
height: 500;
width: 500;
resize: both;
overflow: hidden;
max-height: 500px;
max-width: 500px;
min-height: 100px;
min-width: 100px;
}
#xy{
color: white;
}
#testdiv{
background-color: white;
position: absolute;
width: 100px;
height: 100px;
}
#body{
background-color: black;
}
<body id="body" onload="testdiv()">
<center>
<div id="city" onmousemove="mousepos(event);">
<div id="testdiv"></div>
</div>
<p id="xy"></p>
</center>
</body>
The code detects your mouse X and mouse Y when your mouse is over the big green div, then it puts the white div's left corner on your mouse X and mouse Y. My problem is that when my mouse is draging the white div down or right, I can drag it off of the green div.
Is there a way I could fix this problem?
Since there are no supported parent selectors in the current JS.
You could either use Jquery or CSS, I am listing both Javascript options, and CSS options
Option 1: $("a.active").parents('li').css("property", "value");
Option 2: Sibling Combination to match any ParentElement
element that is preceded by an ChildElement element.
// Just change the parent and child elemets below
ParentElement ~ ChildElement {
property: value;
}
You can make a check before changing the child div position, if its new position is outside of where you want it to be, you can skip it.
Something like:
if (mouse.x > parent_div_width){
return;
}
else {
child_div_Xpos = mouse.x
}
You can to try this code:
var mousex, mousey;
function mousepos(e) {
mousex = e.clientX;
mousey = e.clientY;
document.getElementById("xy").innerText = mousex + " , " + mousey;
}
var coordCity = document.getElementById("city").getBoundingClientRect();
var elem = document.getElementById("testdiv");
let i = 0
function testdiv() {
elem.style.left = mousex + 'px';
elem.style.top = mousey + 'px';
var coord = elem.getBoundingClientRect();
if(coord.left < coordCity.left ||
coord.right > coordCity.right ||
coord.bottom > coordCity.bottom ||
coord.top < coordCity.top) {
console.log('rect is out');
};
i++;
if(i === 100) {
return;
}
setTimeout(testdiv, 50);
}
And you need add in css px to value of width and height:
#city{
border: 1px dotted white;
background-color: lightgreen;
height: 500px;
width: 500px;
resize: both;
overflow: hidden;
max-height: 500px;
max-width: 500px;
min-height: 100px;
min-width: 100px;
}
And always save youre nodes to variable, because it does youre code faster, I use variable i for stop test. You can use another solution.
I created next app:
https://codepen.io/piotrazsko/pen/VrrZBq
I figured out a simple, more understandable way to do this.
I created a variables for the testdiv's width, height, x, y, x offset from
mouse, and y offset from mouse.
var divw = 50;
var divh = 50;
var divofx = 25;
var divofy = 25;
Then I made a variable for the city divs width.
var cityw = 500;
Then, I used screen.width / 2 to find the center of the screen.
var centerx = screen.width / 2;
Then, I made the size of the testdiv changeable at any time by putting the code below into the main function :
document.getElementById("testdiv").style.width = divw;
document.getElementById("testdiv").style.height = divh;
Then I used the width variable to find the edges of the city div.
Then, based off of the edges, I made some simple collision detecting if statements. I also did not need to change the Y mutch since it pretty mutch stays the same.
if(mousex + divw > centerx + (cityw / 2)){
mousex = centerx + (cityw / 2) - divw;
}
else{
document.getElementById("testdiv").style.left = mousex;
}
if(mousey > (cityw - divh) + 10){
mousey = (cityw - divh) + 10;
}
else{
document.getElementById("testdiv").style.top = mousey;
}
if(mousex < centerx - cityw / 2){
mousex = centerx - cityw / 2;
}
if(mousey < 8){
mousey = 8;
}
setTimeout(testdiv, 1);
Now the whole program looks like:
<html>
<head>
<style>
#city{
border: 1px dotted white;
background-color: lightgreen;
height: 500;
width: 500;
overflow: none;
max-height: 500px;
max-width: 500px;
min-height: 100px;
min-width: 100px;
}
#xy{
color: white;
}
#testdiv{
background-color: white;
position: absolute;
width: 100px;
height: 100px;
}
#body{
background-color: black;
}
</style>
<script>
var mousex, mousey;
var divw = 50;
var divh = 50;
var divofx = 25;
var divofy = 25;
var cityw = 500;
function mousepos(e){
mousex = e.clientX - divofx;
mousey = e.clientY - divofy;
document.getElementById("xy").innerText = mousex + " , " + mousey;
}
function testdiv(){
var centerx = screen.width / 2;
document.getElementById("city").style.width = cityw;
document.getElementById("testdiv").style.width = divw;
document.getElementById("testdiv").style.height = divh;
if(mousex + divw > centerx + (cityw / 2)){
mousex = centerx + (cityw / 2) - divw;
}
else{
document.getElementById("testdiv").style.left = mousex;
}
if(mousey > (cityw - divh) + 10){
mousey = (cityw - divh) + 10;
}
else{
document.getElementById("testdiv").style.top = mousey;
}
if(mousex < centerx - cityw / 2){
mousex = centerx - cityw / 2;
}
if(mousey < 8){
mousey = 8;
}
setTimeout(testdiv, 1);
}
</script>
</head>
<body id="body" onload="testdiv()" onmousemove="mousepos(event);">
<center>
<div id="city" onmousemove="mousepos(event);">
<div id="testdiv"></div>
</div>
<p id="xy"></p>
</center>
</body>
</html>
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";
}