Move an image with Javascript using mouse events - javascript

This should be simple enough, but every time I try I end up with a different issue.
I am trying to move an image around the screen using mouse events such as mousedown, mouseup, mousemove, clientX and clientY. I am then trying to apply it to the image using absolute positioning.
I thought the below code would work as I get the coordinates on the initial click, and then the idea was to update them with mouse movement, but this does not work.
var image;
var dog = document.getElementById("dogPic");
var cat = document.getElementById("catPic");
dog.addEventListener("mousedown", initialClick, false);
cat.addEventListener("mousedown", initialClick, false);
function initialClick(e) {
var initialX = e.clientX;
var initialY = e.clientY;
image = document.getElementById(this.id);
document.addEventListener("mousemove", function(e){
var newX = e.clientX - initialX;
var newY = e.clientY - initialY;
image.style.left = newX;
image.style.top = newY;
}, false);
}
I am not asking for a complete answer, but can anyone direct me as to how I can approach dragging an image around the screen using the mouse movement events?
Thanks

var dog = document.getElementById("dogPic");
var cat = document.getElementById("catPic");
var moving = false;
dog.addEventListener("mousedown", initialClick, false);
cat.addEventListener("mousedown", initialClick, false);
function move(e){
var newX = e.clientX - 10;
var newY = e.clientY - 10;
image.style.left = newX + "px";
image.style.top = newY + "px";
}
function initialClick(e) {
if(moving){
document.removeEventListener("mousemove", move);
moving = !moving;
return;
}
moving = !moving;
image = this;
document.addEventListener("mousemove", move, false);
}
#dogPic, #catPic {
width: 20px;
height: 20px;
position: absolute;
background: red;
top: 10px;
left: 10px;
}
#dogPic {
background: blue;
top: 50px;
left: 50px;
}
<div id="dogPic"></div>
<div id="catPic"></div>

I made a modification to have a more realistic dragging experience. This required adding an X and Y offset so instead of jumping when picked up, the object seems to just move as expected.
let gMouseDownX = 0;
let gMouseDownY = 0;
let gMouseDownOffsetX = 0;
let gMouseDownOffsetY = 0;
function addListeners() {
document.getElementById('cursorImage').addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
}
function mouseUp() {
window.removeEventListener('mousemove', divMove, true);
}
function mouseDown(e) {
gMouseDownX = e.clientX;
gMouseDownY = e.clientY;
var div = document.getElementById('cursorImage');
//The following block gets the X offset (the difference between where it starts and where it was clicked)
let leftPart = "";
if(!div.style.left)
leftPart+="0px"; //In case this was not defined as 0px explicitly.
else
leftPart = div.style.left;
let leftPos = leftPart.indexOf("px");
let leftNumString = leftPart.slice(0, leftPos); // Get the X value of the object.
gMouseDownOffsetX = gMouseDownX - parseInt(leftNumString,10);
//The following block gets the Y offset (the difference between where it starts and where it was clicked)
let topPart = "";
if(!div.style.top)
topPart+="0px"; //In case this was not defined as 0px explicitly.
else
topPart = div.style.top;
let topPos = topPart.indexOf("px");
let topNumString = topPart.slice(0, topPos); // Get the Y value of the object.
gMouseDownOffsetY = gMouseDownY - parseInt(topNumString,10);
window.addEventListener('mousemove', divMove, true);
}
function divMove(e){
var div = document.getElementById('cursorImage');
div.style.position = 'absolute';
let topAmount = e.clientY - gMouseDownOffsetY;
div.style.top = topAmount + 'px';
let leftAmount = e.clientX - gMouseDownOffsetX;
div.style.left = leftAmount + 'px';
}
addListeners();
<div style="height:500px;width:500;background-color:blue;">
<img src="http://placehold.it/100x100" id="cursorImage" ondragstart="return false;"/>
</div>

This code work with just plain javascript
function addListeners() {
document.getElementById('image').addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
}
function mouseUp() {
window.removeEventListener('mousemove', divMove, true);
}
function mouseDown() {
window.addEventListener('mousemove', divMove, true);
}
function divMove(e){
var div = document.getElementById('image');
div.style.position = 'absolute';
div.style.top = e.clientY + 'px';
div.style.left = e.clientX + 'px';
}
addListeners();
<div style="height:500px;width:500;background-color:blue;">
<img src="http://placehold.it/100x100" id="image" />
</div>

Super simple working code with Jquery. Live demo: http://jsfiddle.net/djjL16p2/
<div id="content" style="margin-top: 100px">
<img id="lolcat" src="http://obeythekitty.com/wp-content/uploads/2015/01/lolcat_airplane.jpg" style="height: 100px; width: 120px; position: absolute;" draggable="false" />
</div>
JS:
$("#lolcat").mousedown(function() {
$(this).data("dragging", true);
});
$("#lolcat").mouseup(function() {
$(this).data("dragging", false);
});
$("#lolcat").mousemove(function(e) {
if (!$(this).data("dragging"))
return;
$(this).css("left", e.clientX - $(this).width()/2);
$(this).css("top", e.clientY - $(this).height()/2);
});

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>

Automatic drag and drop with a click

I'm looking for an automatic drag and dropper. First, when I click anywhere on the screen, get coordinates, then drag and drop an element with the ID of "ball". using jQuery OR javascript.
I coded a similar script to what I want, but this script got patched when the website's client got updated. This one automatically dragged and dropped when I pressed key 1(keycode 49),
(function () {
'use strict';
var mouseX = 0;
var mouseY = 0;
var invName = '';
var timer = 0;
document.body.addEventListener('mousemove', function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
});
$('.inventory-box').mousedown(function (e) {invName = e.currentTarget.id;});
function drop () {
$('#' + invName).trigger($.Event('mousedown', {button: 0}));
$('body').trigger($.Event('mouseup', {
button: 0,
clientX: mouseX,
clientY: mouseY
}));
timer = setTimeout(drop, 100);
}
window.addEventListener('keyup', function (e) {
if (e.keyCode == 49 && !timer) {
invName = 'ball';
drop();
setTimeout(function () {
(clearTimeout(timer), timer = 0);
}, 20);
}
});
})();
when I click anywhere on the screen, it gets it's coordinates, then drag and drops an element with the ID of "ball"
Here's a very simple vanilla JavaScript method that will locate an element with the ID of "ball" at the cursor location upon click.
The "ball" will follow the cursor until the next click, then the ball will be dropped at the click location.
const ball = document.getElementById('ball');
const ballHalfHeight = Math.round(ball.offsetHeight / 2);
const ballHalfWidth = Math.round(ball.offsetWidth / 2);
let dragState = false;
// move ball to position
function moveBallTo(x, y) {
ball.style.top = y - ballHalfHeight + 'px';
ball.style.left = x - ballHalfWidth + 'px';
}
// listen for 'mousemove' and drag ball
function dragListener(evt) {
const {clientX, clientY} = evt;
moveBallTo(clientX, clientY);
};
// respond to 'click' events (start or finish dragging)
window.addEventListener('click', (evt) => {
const {clientX, clientY} = evt;
moveBallTo(clientX, clientY);
ball.classList.remove('hidden');
// handle dragging
if (!dragState) {
window.addEventListener('mousemove', dragListener);
} else {
window.removeEventListener('mousemove', dragListener);
}
dragState = !dragState;
});
.div-ball {
position: fixed;
background-color: dodgerblue;
width: 2rem;
height: 2rem;
border-radius: 1rem;
}
.hidden {
opacity: 0;
}
<body>
<h4>Click anywhere</h4>
<div class="div-ball hidden" id="ball"></div>
</body>

Javascript help handling mouseclick in canvas

I'm trying to get my inputhandler to work in Javascript.
What
In my Game.update I currently have this code:
this.Update = function() {
if (input.GetMousePressed()) {
console.log(input.GetMousePosition());
}
}
And this is my inputhandler:
function InputHandler(canvas) {
this.canvas = canvas;
this.mousePressed = false;
this.mouseDown = false;
this.mousePosition = new Position(0, 0);
this.GetMousePosition = function() {
return this.mousePosition;
}
this.SetMousePosition = function(event) {
var rect = this.canvas.getBoundingClientRect();
this.mousePosition = new Position(event.clientX - rect.left, event.clientY - rect.top);
}
this.GetMousePressed = function() {
return this.mousePressed;
}
this.canvas.onmousedown = function(event) {
input.mouseDown = true;
input.SetMousePosition(event);
}
this.canvas.onclick = function(event) {
input.mouseClicked = true;
input.SetMousePosition(event);
}
window.onmouseup = function(event) {
if (input.mouseDown == true) {
input.mousePressed = true;
input.mouseDown = false;
}
}
The first problem is that I dont know how to handle mousePressed and set it to false. Now it stays true forever.
I'm quite new to Javascript and I'm thankful for any change that would make this better or cleaner code or if what Im doing is bad practice.
I'm using addEventListener for normal button pressing and maybe I should for this to?
Not sure why you need mousepressed/mouseup and click events. The only difference between successful pressed/up and click is that click target should be the same element.
So I would either use the first option or the last but not both.
Your mousePressed flag is set to true because it gets assigned true value once you press the mouse. You need to reset it back to false at some point.
Usually, you don't even need this flag since you trigger whatever function you need inside mousepressed event. Not sure why you would save the information that this happened, do you use it somewhere else?
Also, yes using addEventListener would be better.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
position: absolute;
margin: auto;
left: 0;
right: 0;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
var imageWidth = 180;
var imageHeight = 160;
var canvas = null;
var ctx = null;
var mouseDown = false;
var mouseX = 0;
var mouseY = 0;
var bounds = null;
function canvas_onmousedown(e) {
mouseDown = true;
}
function canvas_onmousemove(e) {
if (mouseDown) {
mouseX = e.clientX - bounds.left;
mouseY = e.clientY - bounds.top;
}
}
function canvas_onmouseup(e) {
mouseDown = false;
}
function loop() {
ctx.fillStyle = "gray";
ctx.fillRect(0,0,imageWidth,imageHeight);
if (mouseDown) {
ctx.fillStyle = "yellow";
} else {
ctx.fillStyle = "black";
}
ctx.fillRect(mouseX - 25,mouseY - 25,50,50);
requestAnimationFrame(loop);
}
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = imageWidth;
canvas.height = imageHeight;
canvas.onmousedown = canvas_onmousedown;
canvas.onmousemove = canvas_onmousemove;
canvas.onmouseup = canvas_onmouseup;
ctx = canvas.getContext("2d");
bounds = canvas.getBoundingClientRect();
requestAnimationFrame(loop);
}
</script>
</body>
</html>

Create and position divs relative to parent

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";
}

Div placement in javascript

I would like it to create the div where the mouse is. I have the following code:
var mouseisdown = false;
$(document).mousedown(function(event) {
mouseisdown = true;
doSomething();
}).mouseup(function(event) {
mouseisdown = false;
});
function doSomething(e){
var draw = document.createElement("div");
draw.className = "draw";
document.body.appendChild(draw);
draw.style.top = e.clientY + "px";
draw.style.left = e.clientX + "px";
if (mouseisdown)
doSomething();
}
Basically you already had it, but you overcomplicated it:
Remove the mouseisdown variable and the event listeners
Add doSomething as a click event listener
Don't call doSomething recursively
$(document).click(function doSomething(e){
var draw = document.createElement("div");
draw.className = "draw";
document.body.appendChild(draw);
draw.style.top = e.clientY + "px";
draw.style.left = e.clientX + "px";
});
.draw {
position: absolute;
height: 10px;
width: 10px;
margin: -5px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Click somewhere

Categories