So I'm trying to do a drag/drop on elements in javascript. The video tutorial I used is here; https://www.youtube.com/watch?v=KTlZ4Hs5h80. I've coded it exactly as it says and I am able to move an object by it's x value but not it's y. So, in summary, whenever I move my mouse the position of the image changes by x, but is constant for y so I can only move my image left and right, and not up and down.
This is my html file:
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<LINK href="gameStyle.css" rel="stylesheet" type="text/css">
</head>
<body>
<section id="main">
<img id="bowl" src="images/bowl.gif">
<img id="egg" src="images/egg.gif">
</section>
<script type="text/javascript" src="gameScript2.js">
</script>
</body>
</html>
This is my javascript file:
function eggIntoBowl()
{
function Draggable(element, dragStart, dragDrop){
this.element = element;
this.dragStart = dragStart;
this.dragDrop = dragDrop;
this.element.classList.add('draggable');
var self = this;
var move = function(event){
event.stopPropagation();
event.preventDefault();
var originalX = parseInt(window.getComputedStyle(this).left);
var originalY = parseInt(window.getComputedStyle(this).top);
var mouseDownX = event.clientX;
var mouseDownY = event.clientY;
function dragEgg(event)
{
self.element.style.left = originalX + event.clientX - mouseDownX + "px"
self.element.style.top = originalY + event.clientY - mouseDownY + "py"
event.stopPropagation();
}
function dropEgg(event)
{
document.removeEventListener('mousemove', dragEgg, true);
document.removeEventListener('mouseup', dropEgg, true);
event.stopPropagation();
}
document.addEventListener('mouseup', dropEgg, true);
document.addEventListener('mousemove', dragEgg, true);
};
this.element.addEventListener('mousedown',move,false);
};
var egg = document.getElementById('egg');
var dragObject = new Draggable(egg);
};
window.addEventListener("load", eggIntoBowl, false);
and this is my css:
body{
width: 896px;
height: 652px;
background: #fff url(images/eggsToBowlScene.jpg) no-repeat;
}
#egg{
position:absolute;
top:190px;
left:56px;
}
#bowl{
position:absolute;
top:141px;
left:231px;
}
.draggable:hover{
cursor: move;
}
Any ideas? I can't work out what I've done wrong. I used another drag/drop tutorial in the past and the same thing happened so I tried this other one, therefore I'm guessing it has something to do with my html file or css..?
In the dragEgg() method you are using "py" instead of "px". This is not meant to be an x and y value, it is short for "pixels". The browser doesn't understand what unit a "py" is so it won't move. Changing it to "px" will tell the browser how many pixels to offset on the Y axis.
self.element.style.top = originalY + event.clientY - mouseDownY + "px";
Why are you using this code if you can use simply the jQuery UI draggable interacion?
http://jqueryui.com/draggable/
Related
I am using MacBook Pro and mouse is touchpad. I do not use physical mouse.
I am now exercising Javascript events programming. I suppose to make a toolbar, then I could drag and drop image item using Javascript mouse event. I wrote codes as below. Currently, I only implement the ball image could listen to mouse event. My purpose is to select the ball, then a new ball image could be created and put to the place where mouse is moved and released. I could create multiple balls and moved to the body of html page wherever I want.
The following codes could not invoke mouseup events. And the ball sticks to the mouse and could not be released/unattached.
Any help and hints?
Thanks in advance!
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<p>Drag image item from toolbar</p>
<table><tr><td>
<img src="soccer-gate.jpeg" id="gate">
</td>
<td>
<img src="ball.jpeg" id="ball">
</td>
</tr>
</table>
<script>
ball.onmousedown = function(event) {
var ball_temp = document.getElementById("ball");;
var ball_clone = ball_temp.cloneNode(true);
ball_clone.id = "ball_clone";
let shiftX = event.clientX - ball_clone.getBoundingClientRect().left;
let shiftY = event.clientY - ball_clone.getBoundingClientRect().top;
console.log("event client X,Y is ",event.clientX,event.clientY);
ball_clone.style.position = 'absolute';
ball_clone.style.zIndex = 1000;
document.body.append(ball_clone);
function moveAt(pageX, pageY) {
ball_clone.style.left = pageX - shiftX + 'px';
ball_clone.style.top = pageY - shiftY + 'px';
console.log("pageX,pageY is ", pageX,pageY);
}
function onMouseMove(event) {
console.log("mouse move");
moveAt(event.pageX, event.pageY);
}
document.addEventListener('mousemove', onMouseMove);
};
ball.onmouseup = function(event) {
console.log("remove mousemove event")
document.removeEventListener('mousemove', onMouseMove);
};
document.addEventListener('mouseup',onmouseup);
ball.ondragstart = function() {
return false;
};
</script>
</body>
</html>
I have to say the truth, I wrote codes by reference a book. And I modify the codes and there are bugs. I use chatGPT finally fix my bugs.
There are two mistakes in original codes. onmouseup shall not be ball.onmouseup, and also this function should be inside onmousedown function.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<p>Drag image item from toolbar</p>
<table><tr><td>
<img src="soccer-gate.svg" id="gate">
</td>
<td>
<img src="ball.svg" id="ball">
</td>
</tr>
</table>
<script>
ball.onmousedown = function(event){
var ball_temp = document.getElementById("ball");;
var ball_clone = ball_temp.cloneNode(true);
ball_clone.id = "ball_clone";
let shiftX = event.clientX - ball_clone.getBoundingClientRect().left;
let shiftY = event.clientY - ball_clone.getBoundingClientRect().top;
console.log("event client X,Y is ",event.clientX,event.clientY);
ball_clone.style.position = 'absolute';
ball_clone.style.zIndex = 1000;
document.body.append(ball_clone);
function moveAt(pageX, pageY) {
ball_clone.style.left = pageX - shiftX + 'px';
ball_clone.style.top = pageY - shiftY + 'px';
console.log("pageX,pageY is ", pageX,pageY);
console.log("event.clientX,event.clientY is ", event.clientX, event.clientY);
console.log("ball_clone.getBoundingClientRect().left,ball_clone.getBoundingClientRect().top is ", ball_clone.getBoundingClientRect().left,ball_clone.getBoundingClientRect().top);
console.log("shiftX,shiftY is",shiftX,shiftY);
console.log("ball_clone.style.left,ball_clone.style.top is",ball_clone.style.left,ball_clone.style.top);
}
function onMouseMove(event) {
console.log("mouse move");
moveAt(event.pageX, event.pageY);
}
document.addEventListener('mousemove', onMouseMove);
onmouseup = function(event) {
console.log("remove mousemove event")
document.removeEventListener('mousemove', onMouseMove);
};
document.addEventListener('mouseup',onmouseup);
ball.ondragstart = function() {
return false;
};
}
</script>
</body>
</html>
I'm making a simple HTML5 app, that will be wrapped to be used on Android, iOS and web browsers. In my app I need a set of points to be dragged and sorted in a certain way, I'm using raphael.js for the animations and movememts and it works fine with 3 or 4 circles, but when I use more the laggy performance appears (mobile browser). I also need the app to be able to draw lines on freehand, like a marker, and the code i'm using refers to drag to, so the performance is awful. The interesting part is that the first moves work great, as i move more elements the performance drops down drastically. It works fine in the pc browser, but works fine for 3 or 4 movements on the mobie browser.
Is there any way to make drag and drop run fast and smooth with large quantity of elements?
Here's the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Raphaël · Drag-n-drop</title>
<link rel="stylesheet" href="demo.css" type="text/css" media="screen">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon-precomposed" href="/Raphael.png">
<link rel="stylesheet" href="demo-print.css" type="text/css" media="print">
<style>
#background {
width: 100%;
height: 100%;
position: fixed;
left: 0px;
top: 0px;
z-index: -1; /* Ensure div tag stays behind content; -999 might work, too. */
}
.stretch {
width:100%;
height:100%;
}
</style>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="raphael-min.js"></script>
<script>
window.onload = function () {
var y = $(window).height();
var x = $(window).width();
y=y/30;
var posX=y;
var posY=y;
var posX2=x-y;
var R = Raphael(0, 0, "100%", "100%");
var nJ=10
var jugador=new Array();
var rival=new Array();
crearJugadores(nJ);
crearRivales(nJ);
function crearJugadores(nJ) {
nJ=nJ;
for (var i=0;i<nJ;i++)
{
jugador[i]= R.circle(posX, posY, y).attr({fill: "hsb(0, 1, 1)", stroke: "none", opacity: .5});
posY=posY+(2*y);
};
};
function crearRivales(nJ) {
posX=x-y;
posY=y;
nJ=nJ;
for (var i=0;i<nJ;i++)
{
rival[i]= R.circle(posX, posY, y).attr({fill: "#214dcf", stroke: "none", opacity: .5});
posY=posY+(2*y);
};
};
var start = function () {
this.ox = this.attr("cx");
this.oy = this.attr("cy");
this.animate({r: (1.5*y), opacity: .3}, 100, ">");
},
move = function (dx, dy) {
this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
this.animate({r: y, opacity: 1}, 500, ">");
};
R.set(rival).drag(move, start, up);
R.set(jugador).drag(move, start, up);
initDrawing(R);
};
var g_masterPathArray;
var g_masterDrawingBox;
var g_masterPaper;
function initDrawing(R) {
g_masterPaper = R;
var masterBackground = g_masterPaper.rect(0,0,"100%","100%");
masterBackground.attr({fill:"blue", opacity: 0});
masterBackground.mousemove(function (event) {
var evt = event;
var IE = document.all?true:false;
var x, y;
if (IE) {
x = evt.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = evt.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
else {
x = evt.pageX;
y = evt.pageY;
}
// subtract paper coords on page
this.ox = x;
this.oy = y;
});
var start = function () {
g_masterPathArray = new Array();
},
move = function (dx, dy) {
if (g_masterPathArray.length == 0) {
g_masterPathArray[0] = ["M",this.ox,this.oy];
g_masterDrawingBox = g_masterPaper.path(g_masterPathArray);
g_masterDrawingBox.attr({stroke: "#000000","stroke-width": 3});
}
else
g_masterPathArray[g_masterPathArray.length] =
["L",this.ox,this.oy];
g_masterDrawingBox.attr({path: g_masterPathArray});
},
up = function () {
;
};
masterBackground.drag(move, start, up);
masterBackground.toBack();
}
</script>
</head>
<body>
<div id="background">
<img src="cancha.jpg" class="stretch" alt="" />
</div>
<div id="holder"></div>
</body>
</html>
Any ideas??
Thanks
I want to use the 'mouse's drag' to drag a background's position around, inside a box.
The CSS:
.filmmakers #map {
width : 920px;
height : 500px;
margin-top : 50px;
margin-left : 38px;
border : 1px solid rgb(0, 0, 0);
cursor : move;
overflow : hidden;
background-image : url('WorldMap.png');
background-repeat : no-repeat;
}
The html:
<div id = "map" src = "WorldMap.png" onmousedown = "MouseMove(this)"> </div>
The Javascript:
function MouseMove (e) {
var x = e.clientX;
var y = e.clientY;
e.style.backgroundPositionX = x + 'px';
e.style.backgroundPositionY = y + 'px';
e.style.cursor = "move";
}
Nothing happens, no errors, no warnings, nothing... I have tried lots of things: an absolutely positioned image inside a div (you can guess why that didn't work), A draggable div inside a div with a background image, a table with drag and drop, and finally I tried this:
function MouseMove () {
e.style.backgroundPositionX = 10 + 'px';
e.style.backgroundPositionY = 10 + 'px';
e.style.cursor = "move";
}
This works, but its not relative to the mouse's position, pageX and pageY don't work either.
A live demo: http://jsfiddle.net/VRvUB/224/
P.S: whatever your idea is, please don't write it in JQuery
From your question I understood you needed help implementing the actual "dragging" behavior. I guess not. Anyway, here's the results of my efforts: http://jsfiddle.net/joplomacedo/VRvUB/236/
The drag only happens when the mouse button, and.. well, it behaves as I think you might want it to. Just see the fiddle if you haven't =)
Here's the code for those who want to see it here:
var AttachDragTo = (function () {
var _AttachDragTo = function (el) {
this.el = el;
this.mouse_is_down = false;
this.init();
};
_AttachDragTo.prototype = {
onMousemove: function (e) {
if ( !this.mouse_is_down ) return;
var tg = e.target,
x = e.clientX,
y = e.clientY;
tg.style.backgroundPositionX = x - this.origin_x + this.origin_bg_pos_x + 'px';
tg.style.backgroundPositionY = y - this.origin_y + this.origin_bg_pos_y + 'px';
},
onMousedown: function(e) {
this.mouse_is_down = true;
this.origin_x = e.clientX;
this.origin_y = e.clientY;
},
onMouseup: function(e) {
var tg = e.target,
styles = getComputedStyle(tg);
this.mouse_is_down = false;
this.origin_bg_pos_x = parseInt(styles.getPropertyValue('background-position-x'), 10);
this.origin_bg_pos_y = parseInt(styles.getPropertyValue('background-position-y'), 10);
},
init: function () {
var styles = getComputedStyle(this.el);
this.origin_bg_pos_x = parseInt(styles.getPropertyValue('background-position-x'), 10);
this.origin_bg_pos_y = parseInt(styles.getPropertyValue('background-position-y'), 10);
//attach events
this.el.addEventListener('mousedown', this.onMousedown.bind(this), false);
this.el.addEventListener('mouseup', this.onMouseup.bind(this), false);
this.el.addEventListener('mousemove', this.onMousemove.bind(this), false);
}
};
return function ( el ) {
new _AttachDragTo(el);
};
})();
/*** IMPLEMENTATION ***/
//1. Get your element.
var map = document.getElementById('map');
//2. Attach the drag.
AttachDragTo(map);
This isn't working because you are passing the element "map" to your MouseMove function, and using it as both an event object and an element. You can fix this painlessly by using JavaScript to assign your event handler rather than HTML attributes:
<div id="map"></div>
And in your JavaScript:
document.getElementById('map').onmousemove = function (e) {
// the first parameter (e) is automatically assigned an event object
var x = e.clientX;
var y = e.clientY;
// The context of this is the "map" element
this.style.backgroundPositionX = x + 'px';
this.style.backgroundPositionY = y + 'px';
}
http://jsfiddle.net/VRvUB/229/
The downside of this approach is that the backgroundPositionX and backgroundPositionY style properties are not supported in all browsers.
You mention "an absolutely positioned image inside a div" which is probably the more compatible solution for this. To make this setup work, you need to set the position of the outer element to relative, which makes absolute child elements use its bounds as zero.
<div id="map">
<img src="" alt="">
</div>
CSS:
#map {
position:relative;
overflow:hidden;
}
#map img {
position:absolute;
left:0;
top:0;
}
Here it is applied to your code: http://jsfiddle.net/VRvUB/232/
This works 100%
Vanilla Javascript
document.getElementById('image').onmousemove = function (e) {
var x = e.clientX;
var y = e.clientY;
this.style.backgroundPositionX = -x + 'px';
this.style.backgroundPositionY = -y + 'px';
this.style.backgroundImage = 'url(https://i.ibb.co/vhL5kH2/image-14.png)';
}
document.getElementById('image').onmouseleave = function (e) {
this.style.backgroundPositionX = 0 + 'px';
this.style.backgroundPositionY = 0 + 'px';
this.style.backgroundImage = 'url(https://i.ibb.co/Ph9MCB2/template.png)';
}
.container {
max-width: 670px;
height: 377px;
}
#image {
max-width: 670px;
height: 377px;
cursor: crosshair;
overflow: hidden;
background-image: url('https://i.ibb.co/Ph9MCB2/template.png');
background-repeat: no-repeat;
}
<div class="container">
<div id="image">
</div>
</div>
well right now im trying to learn how to use the canvas tag on html, and im having trouble handling mouse events when i apply css to the document.
the issue starts when i move the div containing the canvas and center it on the page, the first poing of the canvas wouldnt be 0 because its centered and for some reason 0,0 would be the beginning of the screen and not the beginning of the canvas, which i found weird because im adding the event listener to the canvas directly.
here is the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test</title>
<style type="text/css">
body {
font: 100%/1.4 Verdana, Arial, Helvetica, sans-serif;
background: #42413C;
margin: 0;
padding: 0;
color: #000;
}
#divId {
width: 800px;
height: 600px;
text-align:center;
margin: 20px auto;
background-color:#0099FF;
}
</style>
<script>
window.onload = function () {
var canvas = document.getElementById('canvasId');
var c = canvas.getContext('2d');
alert("lol");
canvas.addEventListener('mousedown', hmd, false);
function hmd(e) {
alert ("x: " + e.clientX + " y: " + e.clientY);
}
}
</script>
</head>
<body>
<div id="divId">
<canvas height="300" width="800" id="canvasId" />
</div>
</body>
</html>
so i read somewhere that the issue was caused by the div, but when i tried to give css directly to the canvas tag it didnt work, so basically what i need to do, is to get that canvas centered or placed anywhere on the screen, but having its first pixel as 0,0.
adding a solution would be hard because its centering automatically, so i would need to know the user resolution to be able to calculate the offset so what im looking for is a way to do it simply with css or something.
To get the coordinates relatively to the canvas, do this:
function hmd(e) {
var rx = e.pageX, ry = e.pageY;
rx -= canvas.offsetLeft;
ry -= canvas.offsetTop;
alert ("x: " + rx + " y: " + ry);
}
This assumes your canvas variable definition is global.
Edit: another method:
function hmd(e) {
var rx, ry;
if(e.offsetX) {
rx = e.offsetX;
ry = e.offsetY;
}
else if(e.layerX) {
rx = e.layerX;
ry = e.layerY;
}
}
Here's what I've been using for my latest experimentation. It works with damn near everything: Borders, paddings, position:fixed elements offsetting the HTML element, etc. It also works on all touch devices and even if the browser is zoomed.
http://jsfiddle.net/simonsarris/te8GQ/5/
var stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingLeft'], 10) || 0;
var stylePaddingTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingTop'], 10) || 0;
var styleBorderLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderLeftWidth'], 10) || 0;
var styleBorderTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderTopWidth'], 10) || 0;
var html = document.body.parentNode;
var htmlTop = html.offsetTop;
var htmlLeft = html.offsetLeft;
function getMouse(e) {
var element = can,
offsetX = 0,
offsetY = 0,
mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft;
offsetY += stylePaddingTop + styleBorderTop + htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {
x: mx,
y: my
};
}
I'm learning how to drag-and-drop-move DIV's around the document in javascript. Here is a live demo:
http://jsfiddle.net/BBANc/
This works fine in Firefox and I'm not currently developing with any other browser. However, if you change set_coords_in_js to false, the demo fails.
Using Firebug to set some breakpoints, you'll notice that this line fails:
var div_left = parseInt( mov_div_1.style.left, 10 );
There is no value for mov_div_1.style.left at this point. So javascript has no idea what the existing value is, and sets div_left to 'NaN'. This style is set, and appears to be valid in the document, but there is no value in the DOM!
If you set set_coords_in_js back to true, then the above has a value and everything works perfectly as it should.
Why?
If you want to play with this locally, copy-and-paste this into your local demo file. To see the values (or lack thereof) in Firebug, set your breakpoint on line 39 or 40 and step through, hovering your mouse over the things in the line. Make sure you set set_coords_in_js to false to see the problem.
drag_move_div.html:
<!DOCTYPE html>
<html>
<head>
<title>drag move div demo</title>
<style type='text/css'>
.movDiv {
position: absolute;
left: 80px;
top: 80px;
cursor: move;
border: 1px dashed green;
padding: 1em;
}
.coordinates_display { font-weight: bold; }
</style>
<script type='text/javascript'>
window.onload = function() {
mov_div_1 = document.getElementById('mov_div_1');
set_coords_in_js = true;
function update_coordinates( newX, newY ) {
document.getElementById('coordinate_x').innerHTML = newX;
document.getElementById('coordinate_y').innerHTML = newY;
}
// why do I need to set these here in javascript when they are set in css?
if( set_coords_in_js ) {
mov_div_1.style.left = '80px';
mov_div_1.style.top = '80px';
}
update_coordinates( mov_div_1.style.left, mov_div_1.style.top );
mov_div_1.onmousedown = function(e){
mov_div_1.style.backgroundColor = 'black';
mov_div_1.style.color = 'white';
var div_left = parseInt( mov_div_1.style.left, 10 );
var div_top = parseInt( mov_div_1.style.top, 10 );
var startX = e.clientX;
var startY = e.clientY;
mov_div_1.onmousemove = function(e){
var newX = ( div_left + e.clientX - startX );
var newY = ( div_top + e.clientY - startY );
mov_div_1.style.left = newX + 'px';
mov_div_1.style.top = newY + 'px';
update_coordinates( mov_div_1.style.left, mov_div_1.style.top );
};
};
mov_div_1.onmouseup = function(){
mov_div_1.onmousemove = null;
mov_div_1.style.backgroundColor = '';
mov_div_1.style.color = '';
};
};
</script>
</head>
<body>
<div class='movDiv' id='mov_div_1'>[ Click & Drag Me Around (slowly) ]</div>
<p>Coordinates:
<span id='coordinate_x' class='coordinates_display'></span> x
<span id='coordinate_y' class='coordinates_display'></span></p>
</body>
</html>
See this related question. When you access element.style, you're not accessing the computed style (which includes stylesheet declarations), you're accessing the "style" attribute on the element itself. So when you try to get a value from mov_div_1.style, no style attribute is available, and it will come back as an empty string.
To fix this, you need to use either element.currentStyle (older IE versions, I think) or element.getComputedStyle() (modern browsers):
var computedStyle = mov_div_1.currentStyle || getComputedStyle(mov_div_1);
var div_left = parseInt( computedStyle.left, 10 );
var div_top = parseInt( computedStyle.top, 10 );
See the working jsFiddle here.