Display local DOM children relative to mouse position - javascript

I want to create a polymer element for drawing shapes. This element have a canvas and a paper-dropdown-menu in its local dom. The idea is to draw using mouse on the canvas and once the drawing action is done, the dropdown-menu will show up next to the shape so one can select the name. My main problem here is: how to display the paper-dropdown-menu relative to the mouse position ?

As the user moves their mouse around over an element, the mousemove event is fired. You can listen to these events while the user is "drawing" and keep track of the mouse position:
var canvas = document.querySelector('.canvas');
var position = document.querySelector('.position');
canvas.addEventListener('mousemove', function(e) {
position.innerText =
'client x: ' + e.clientX +
' client y: ' + e.clientY;
});
.canvas {
background-color: grey;
width: 100px;
height: 100px;
}
<div class="canvas"></div>
<span class="position"></span>
The user will somehow stop drawing, and you can use the last mousemove event to figure out where to render the dropdown (via inline absolute positioning). In the following demo, the "dropdown" appears whenever a click occurs inside the canvas:
var canvas = document.querySelector('.canvas');
var position = document.querySelector('.position');
var dropdown = document.querySelector('.dropdown');
var lastPosition = {x: -100, y: -100};
canvas.addEventListener('mousemove', function(e) {
position.innerText =
'client x: ' + e.clientX +
' client y: ' + e.clientY;
lastPosition.x = e.clientX;
lastPosition.y = e.clientY;
});
canvas.addEventListener('click', function(e) {
dropdown.style.left = lastPosition.x + 'px';
dropdown.style.top = lastPosition.y + 'px';
});
.canvas {
background-color: grey;
width: 100px;
height: 100px;
}
.dropdown {
background-color: red;
height: 40px;
position: absolute;
top: -100px;
left: -100px;
width: 20px;
}
<div class="canvas"></div>
<span class="position"></span>
<div class="dropdown"></div>

Related

How to let the coodinates of the cursor follow the cursor when hovering over a rectangle?

The following code always shows the coordinates of the cursor below the cursor:
function showCoords(e) {
var x = event.clientX;
var y = event.clientY;
var coor = "(" + x + ", " + y + ")";
document.getElementById("box").innerHTML = coor;
var bx = document.getElementById("box");
bx.style.left = e.pageX - 50;
bx.style.top = e.pageY + 20;
}
function clearCoords() {
document.getElementById("box").innerHTML = "";
}
div.relative {
position: relative;
width: 400px;
height: 300px;
border: 1px solid black;
}
div.abs {
position: absolute;
top: 100px;
right: 50px;
width: 200px;
height: 100px;
background-color: yellow;
}
<body onmousemove="showCoords(event)">
<div class="relative">
<div class="abs" onmousemove="showCoords(event)" onmouseout="clearCoords()"></div>
</div>
<div id="box" style="width:100px; height:30px; position:absolute"></div>
</body>
I only want the coordinates to be visible when the mouse pointer is hovering over the yellow rectangle.
If I change <body onmousemove="showCoords(event)"> to <body>, the coordinates are never visible.
How do I get the coordinates be visible only when hovering over the yellow rectangle?
Move the onmousemove listener from the body to the element you want to listen on - div.abs in this case.
I'd recommend not using the onmousemove attribute, in favour of using an entirely javascript solution - just to keep javascript-y things together. Something like (untested)
var listenOn = document.querySelector(".abs");
listenOn.addEventListener("mousemove", ShowCoords);

Javascript moving element to mouse click position, element not responding

I'm trying to get my png to move to the mouse click position when the user clicks within the container but I cant get the png to respond. I'm following this tutorial (https://www.youtube.com/watch?v=b4GwvdhrEQg), and stuck on the first test. my target doesnt respond to clicks at all.
Please help
var theGirl = document.querySelector("#girl");
var container = document.querySelector("#floor");
container.addEventListener("click", getClickPosition, false);
function getClickPosition(e) {
var xPosition = e.clientX - (theGirl.offsetWidth / 2);
var yPosition = e.clientY; - (theGirl.offsetHeight / 2)
var translate3dValue = "translate3d(" + xPosition + "px" + yPosition + "px, 0)";
theGirl.style.transform = translate3dValue;
}
#floor {
width: 700px;
height: 600px;
cursor: pointer;
overflow: visible;
border: 10px #EDEDED solid;
}
#girl {
height: 450px;
width: 200px;
border: 15px red solid;
transform: translate3d(50px, 50px, 0);
}
<body>
<div id="floor">
<div>
<img src="girl.png" id="girl"> </div>
</div>
Change #girl's position to absolute. I think it works after that.

Problems implementing dragging by mouse

I want to implement a draggable map containing certain elements.
--> See JSFiddle: https://jsfiddle.net/7ndx7s25/7/
By use of mousedown, mousemove and mouseup I achieved the dragging.
However I am facing problems:
When pressing the mouse button down and then moving outside the window I do not get a mouseup event. Reentering the window (having released the mouse button long ago) my map still thinks the button is down and misbehaves accordingly.
When there are objects on the map, I do not get mousemove events while moving through these objects. Therefore the map hangs and jumps as I enter and leave such an object.
While over such objects I still want to have a move mouse cursor. I could change the cursor style on each object (in the Fiddle I did this for Object 1 as an example), but this doesn't seem like a good way. Is there a more elegant solution?
You need e.g. mouseout to catch when leaving the canvas, though that event will also fire when the cursor move over the other elements.
One easy fix is to simply add a class to canvas, that set pointer-events: none on those.
With that class you can control the cursor as well, and avoid setting it with the script.
Stack snippet
updateInfo = function() {
document.getElementById('info').innerHTML =
'Position = ' + JSON.stringify(position) +
'<br />dragInfo = ' + JSON.stringify(dragInfo);
};
const canvas = document.getElementsByTagName('canvas')[0];
let position = { x: 0, y : 0 };
let dragInfo = null;
updateInfo();
canvas.addEventListener('mousedown', function(e) {
dragInfo = {
startEvent: {
x: e.clientX,
y: e.clientY,
},
startPosition: position
};
canvas.classList.add('dragging');
updateInfo();
});
canvas.addEventListener('mousemove', function(e) {
if (dragInfo === null) return;
position = {
x: dragInfo.startPosition.x - (e.clientX - dragInfo.startEvent.x),
y: dragInfo.startPosition.y - (e.clientY - dragInfo.startEvent.y)
};
updateInfo();
});
canvas.addEventListener('mouseup', function(e) {
dragInfo = null;
canvas.classList.remove('dragging');
updateInfo();
});
canvas.addEventListener('mouseout', function(e) {
dragInfo = null;
canvas.classList.remove('dragging');
updateInfo();
});
* {
user-select: none;
font-family: monospace;
}
canvas {
background: black;
border: 1px solid red;
}
.dragging {
cursor: move;
}
.obj {
position: absolute;
width: 50px;
height: 50px;
background: green;
color: white;
text-align: center;
line-height: 50px;
font-weight: bold;
}
.dragging ~ .obj {
pointer-events: none;
}
<div id="myMap-ish">
<canvas width="500" height="300"></canvas>
<div class="obj" style="left: 30px; top: 35px">1</div>
<div class="obj" style="left: 175px; top: 79px">2</div>
<div class="obj" style="left: 214px; top: 145px">3</div>
<div class="obj" style="left: 314px; top: 215px">4</div>
</div>
<div id="info"></div>
Another option could be to use mouseleave, on the outer wrapper, the myMap-ish element, which could be combined with the above added class to simply cursor handling.
The main difference between mouseout and mouseleave is that the latter won't fire when hovering children, as shown in below sample, so we don't need to toggle pointer-events as we did in the first sample.
Note, to simply use mouseleave in the first sample, on canvas, will have the same issue mouseout has, since the "other element" aren't children of the canvas.
Stack snippet
updateInfo = function() {
document.getElementById('info').innerHTML =
'Position = ' + JSON.stringify(position) +
'<br />dragInfo = ' + JSON.stringify(dragInfo);
};
const canvas = document.getElementById('myMap-ish');
let position = { x: 0, y : 0 };
let dragInfo = null;
updateInfo();
canvas.addEventListener('mousedown', function(e) {
dragInfo = {
startEvent: {
x: e.clientX,
y: e.clientY,
},
startPosition: position
};
canvas.style.cursor = 'move';
document.querySelectorAll('.obj')[0].style.cursor = 'move'; // TODO for all objects
updateInfo();
});
canvas.addEventListener('mousemove', function(e) {
if (dragInfo === null) return;
position = {
x: dragInfo.startPosition.x - (e.clientX - dragInfo.startEvent.x),
y: dragInfo.startPosition.y - (e.clientY - dragInfo.startEvent.y)
};
updateInfo();
});
canvas.addEventListener('mouseup', function(e) {
dragInfo = null;
canvas.style.cursor = 'default';
document.querySelectorAll('.obj')[0].style.cursor = 'default'; // TODO for all objects
updateInfo();
});
canvas.addEventListener('mouseleave', function(e) {
dragInfo = null;
canvas.style.cursor = 'default';
document.querySelectorAll('.obj')[0].style.cursor = 'default'; // TODO for all objects
updateInfo();
});
* {
user-select: none;
font-family: monospace;
}
canvas {
background: black;
border: 1px solid red;
}
.obj {
position: absolute;
width: 50px;
height: 50px;
background: green;
color: white;
text-align: center;
line-height: 50px;
font-weight: bold;
}
<div id="myMap-ish">
<canvas width="500" height="300"></canvas>
<div class="obj" style="left: 30px; top: 35px">1</div>
<div class="obj" style="left: 175px; top: 79px">2</div>
<div class="obj" style="left: 214px; top: 145px">3</div>
<div class="obj" style="left: 314px; top: 215px">4</div>
</div>
<div id="info"></div>

move a large div opposite to mouse movement

I have a table full of data that tends to be larger than the screen.
I put the table in a DIV and set the "overflow" to "auto" in CSS
div.scrolling-comps {
width : 970px;
height : 800px;
overflow : auto;
}
So the DIV can be scrolled up/down, left right using the browser's built-in scroll bars.
Problem is, the table can be WAAY bigger than the screen. And while the mousewheel will scroll it up/down, scrolling left/right is a pain in the hooch.
So, looking for a javascript/jquery or CSS way to scroll the div NATURALLY.
In other words, when someone viewing the huuuge table moves their mouse to the right, the DIV goes to the left (thus scrolling without using the scroll bars).
Something similar to this, but instead of following the mouse, the div would move opposite the mouse...
window.onload = function() {
var bsDiv = document.getElementById("box-shadow-div");
var x, y;
// On mousemove use event.clientX and event.clientY to set the location of the div to the location of the cursor:
window.addEventListener('mousemove', function(event) {
x = event.clientX;
y = event.clientY;
if (typeof x !== 'undefined') {
bsDiv.style.left = x + "px";
bsDiv.style.top = y + "px";
}
}, false);
}
#box-shadow-div {
position: fixed;
width: 1000px;
height: 800px;
border-radius: 0%;
background-color: black;
box-shadow: 0 0 10px 10px black;
top: 49%;
left: 48.85%;
}
<div id="box-shadow-div"></div>
The example you have about using the mouse position is interesting... But it is not what you need to achieve what you described.
In fact... What you need to know is the "ratio" between the div wrapping the table and its scrollWidth
Then, using the X position of the mouse, you can apply a scroll to the div in order to make it "move".
I used jQuery to do it using very few lines.
// Just to fake a big table
var fakeCell = $("<td>Some data</td>");
for(i=0;i<100;i++){
var fakeRow = $("<tr>");
for(k=0;k<50;k++){
fakeRow.append(fakeCell.clone().append(" "+k));
}
$("#test").append(fakeRow.clone());
}
// ---------------------------------------------------
// Calculate the "ratio" of the box-div width versus its scrollable width
var ratio = $("#box-div")[0].scrollWidth / $("#box-div").width();
console.log("Ratio: "+ratio);
// Scroll left/rigth based on mouse movement
$(window).on("mousemove", function(e){
var X = ratio * e.pageX;
// Scroll the div using the mouse position multiplyed by the ratio
$("#box-div").scrollLeft(X);
});
td{
white-space: nowrap;
border: 1px solid black;
}
#box-div{
overflow:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="box-div">
<table id="test">
</table>
</div>
</body>
So while the user moves the mouse over the div's width, you apply a scroll multiplied by the ratio... The effect is the user can scroll it all from the most left to most right ends easilly.
How about this?
wrap a table in div (i.e. parent-div) which is relatively positioned
Give position absolute to the target div.
And change left & top position of target div on mousemove event.
window.onload = function() {
var bsDiv = document.getElementById("box-shadow-div");
var x, y;
// On mousemove use event.clientX and event.clientY to set the location of the div to the location of the cursor:
window.addEventListener('mousemove', function(event) {
x = event.clientX;
y = event.clientY;
if (typeof x !== 'undefined') {
bsDiv.style.left = -x + "px";
bsDiv.style.top = -y + "px";
}
}, false);
}
.parent-div {
position: relative;
}
#box-shadow-div {
position: absolute;
width: 1000px;
height: 800px;
border-radius: 0%;
background-color: black;
box-shadow: 0 0 10px 10px black;
top: 0;
left: 0;
}
<div class="parent-div">
<div id="box-shadow-div"></div>
</div>
Have you tried changing x to -x? this will technically "invert" the effect.
window.onload = function() {
var bsDiv = document.getElementById("box-shadow-div");
var x, y;
// On mousemove use event.clientX and event.clientY to set the location of the div to the location of the cursor:
window.addEventListener('mousemove', function(event) {
x = event.clientX;
y = event.clientY;
if (typeof x !== 'undefined') {
bsDiv.style.left = -x + "px";
bsDiv.style.top = -y + "px";
}
}, false);
}
#box-shadow-div {
position: fixed;
width: 1000px;
height: 800px;
border-radius: 0%;
background-color: black;
box-shadow: 0 0 10px 10px black;
top: 49%;
left: 48.85%;
}
<div id="box-shadow-div"></div>

Why is clientX reset to 0 on last drag-event and how to solve it?

I'm trying to drag elements along a line. They should push each other, not cross over or under.
To avoid having a shady element float around on drag, I drag a sub-div which then affects the position of the outer one. Works fine except when you release the mouse which triggers the last drag-event with clientX equal to 0 (see CodePen)!
var b = document.querySelector('.box');
var bi = document.querySelector('.box-inner');
var b2 = document.querySelector('.box2');
bi.addEventListener('dragstart', function() {
console.log("dragstart")
}, false);
bi.addEventListener('drag', function(event) {
const bLeft = event.clientX;
const b2Left = b2.offsetLeft;
b.style.left = bLeft + "px";
if (b2Left - 50 <= bLeft) {
b2.style.left = (bLeft + 50) + "px";
}
console.log("drag", event.clientX, event.target.offsetParent.offsetLeft, b2.offsetLeft);
}, false);
bi.addEventListener('dragend', function() {
console.log("dragend")
}, false);
.box {
width: 50px;
height: 50px;
background-color: hotpink;
position: absolute;
top: 0;
left: 0;
}
.box-inner {
width: 100%;
height: 100%;
}
.box2 {
width: 50px;
height: 50px;
background-color: rebeccapurple;
position: absolute;
left: 200px;
top: 0;
}
<div class="box">
<div class="box-inner" draggable="true"></div>
</div>
<div class="box2"></div>
Why is this and what can I do to avoid resetting it?
By default, data/elements cannot be dropped in other elements. To allow a drop, you must prevent the default handling of the element when dragover.
document.addEventListener("dragover", function(event) {
// prevent default to allow drop
event.preventDefault();
}, false);
I just ignore the last event. I don't know why it emits.
// in `drag` event handler
if (event.screenX === 0) {
return;
}
Notice you should use screenX here. When the user zoom in the page, clientX would be a positive value but not zero.

Categories