Get element within clicked pixel? - javascript

I'm not sure where to start on this, I've already Googled for a few days trying to find out how to get the element that is within a selected/clicked pixel on the page. I came across this function from a co-worker but I have no idea what it does:
function onclick(e){
var x = e.clientX,
y = e.clientY;
$("*").filter(function(){
position.left > x && position.left + width < x;
/*same for height*/;
});
}
Put simply, I need to be able to click a pixel and get the div/element that is within that pixel. It's not as simple for my app as just saying div .class for example because elements overlap one another with opacity and z-index.

The code as shown in the question won't work because variables position, width are not defined, however its basic idea is correct — loop through all the elements and compare the coordinates of a click to each element's box.
Wanted to try it myself. Moved the working demo here instead of a snippet.

Clicking wherever in the document will log the clicked element.
$(document).click(function(e) {
console.log(e.target);
});
.box {
width: 50px;
height: 50px;
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='box'></div>

You could use document.elementFromPoint(x, y); if you want to get an element by x and y coords.
See here for docs.
function onclick(e){
var x = e.clientX,
y = e.clientY,
el = document.elementFromPoint(x, y);
}
Fiddle here

Related

Jquery set div at mouse position

I want to have an div under my mouse at all times, this div I want to use to display tool-tips.
This is the code i'm trying to use. But this code gives an error:
" Cannot read property 'pageX' of undefined"
My question is why is pageX undefined, and how do I fix this problem?
$( document ).ready(function() {
AppentMouse(); //Setup div that is used for mouse icon
window.setInterval(function(){
SetMouse(); //Set div that is used for mouse icon at mouse location
}, 5);
});
function AppentMouse(){
$( 'Body' ).append( "<div id='Mouse'>Mouse</div>");
}
function SetMouse(){
var e = window.event || e;
var left = e.pageX + "px";
var top = e.clientY + "px";
var div = document.getElementById('Mouse');
div.style.left = left;
div.style.top = top;
}
Considering this is your html code:
<body>
<div>Your content</div>
</body>
And you have these styles for the div:
div {
position: absolute;
border: solid 1px #fc0;
}
Using jQuery, attach mousemove event listener to the document and make the div to have top and left styles changed on every move:
$(document).on('mousemove', function(e){
$('div').css('top', e.pageY);
$('div').css('left', e.pageX);
});
See this JSFiddle
EDIT:
Considering your code, variable e is undefined. And the error says that an undefined value does not have a pageX property.
That is because you need an mouse event (for your case) to have object event defined. And that object is received by the event listener that we add in the code that I provided.
As for your code, you will have to bind the event to the div.
An easy way to do this would be to not dynamically generate the div, just show and hide it. (As in my example). This is faster as well.
Alternatively, each time you generate the div, define and trigger the set mouse event from within the function that generates it.
Providing an alternate way of doing this:
Firstly, the HTML. Add the following anywhere inside the body.
<div id="tooltip"></div>
Now the CSS (add more to make it look pretty):
#tooltip {
position: absolute;
display: inline-block;
opacity: 0;
}
Make a class called tips and have all elements that you wish to provide tool tips for, belong to that class.
And then the jQuery:
//For every element in ".tips" have an attribute "tooltiptext"
$('.tips').mouseenter(function(e) {
$("#tooltip").css("left", e.pageX + 10);
$("#tooltip").css("top", e.pageY+ 10);
$("#tooltip").html($(this).attr("tooltiptext"));
$("#tooltop").show();
});
$('.tips').mouseout(function() {
$("#tooltip").hide();
});
Do tell me if this works.

Can you get ClientX && ClientY in reference to a selector instead of the window?

when i call a function, i get: window.event.clientX and window.event.clientY from a global function, paste.
Im trying to paste at the coordinates, but they are off by some info i am working to resolve.
i was just going to take:
window_data: {top,left}
and substract:
stage_div_offset: {top,left}
to get the actual offset but that seems to also be off by a bit. Around 40 pixels in both X and Y directions. I assumed this is due to maybe margin or padding or something like that.
What i was really curious of is, Is there a way to get the X and Y of the mouse in reference to a div or other htmlElement?
I wasnt sure if there was a function which i could pass in a selector, or if using something like jquery, there would actually be a function or something for the selector called: mouse.
I do feel this following Topic is relevant, though not sure if it makes mine a dup:
jQuery get mouse position within an element
Edit: Originally i was doing the following code:
var stage = $("#stage").offset(),
results = {
left: window.event.clientX - stage.left,
top: window.event.clientY - stage.top
};
Edit 2: none of the current answers seem to be working, partially because my browser is not recognizing the mouseEvent, so it cant get the screens location.
I wrote the following to try to get the mouselocation
var MouseLocation = {};
MouseLocation.Left = 0;
MouseLocation.Top = 0;
MouseLocation._event;
MouseLocation.get_position = function () { return { left: MouseLocation.Left, top: MouseLocation.Top }; }
MouseLocation.attach = function () {
MouseLocation._event = function (e) {
var loc = { left: e.clientX, top: e.clientY }
MouseLocation.Left = loc.left;
MouseLocation.Top = loc.top;
};
$("#stage").on("mousemove", MouseLocation._event);
}
MouseLocation.detach = function () {
$("#stage").off("mousemove", MouseLocation._event);
}
MouseLocation.ping = function () {
MouseLocation.attach();
$("#stage").mousemove();
MouseLocation.detach();
}
so that way, inside of my event, i can just say:
MouseLocation.ping();
MouseLocation.get_position();
but it doesnt seem to like: $("#stage").on("mousemove")
You can use postion() to:
Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.
You can just take the document coordinates of the mouse and substract the coordinates of the element:
relX = e.clientX-element.offset().left;
relY = e.clientY-element.offset().top;
http://jsfiddle.net/4scbu/1/
The advantage to offset() is that margin and paddings are included into the calculations.

without jquery i need to find out if the mouse is over an element, not determine when it becomes over (in case it doesn't move to trigger onmouseover)

without jquery
basically what I am looking for is the ability to see if the mouse is over a div when a countdown finishes
if the user is over the div then perform action for that div
onmouseover only triggers when the mouse crosses the threshold of the div, if the mouse hasn't moved it wouldn't trigger, so that wouldn't work
I need to determine if the mouse is currently over a div at a specific point in time, if it has moved or not from the starting point
all of my hunting has only found onmousover, and nothing to see if the mouse just happens to be there to begin with
I don't have the javascript skills to determine overall coords of div, then map mouse coords and see if it fits there... which is what I believe I need to do
After reading the second answer (the one with millions of a elements) on this SO question, I've came up with this method works without moving the mouse on page load, without involving millions of elements.
HTML
<div id=t></div>
CSS
#t {
/* for illustrative purposes */
width: 10em;
height: 5em;
background-color: #0af;
}
#t:hover {
border-top-style: hidden;
}
JavaScript
document.addEventListener('click', function () {
var c = window.getComputedStyle(document.getElementById('t')).getPropertyValue('border-top-style');
if (c === 'hidden') {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
As stated earlier, bind to the finish event of your countdown instead of the click event on the document.
You may also use any CSS style that's changed on :hover, I chose border-top-style as it is conspicuous. If you're using a border, choose something else.
Here's a jsFiddle.
set a flag to true onmouseover and to false onmouseleave. when countdown finishes if flag is true then it is over element.
HTML
<div id="div-name">the section of the code i am working with has a countdown timer, when it reaches 0 i need to know if the mouse is over a specific box</div>
<button id="notification" onclick="javascript: letsCountIt(5);">click to start countdown</button>
JS
window.ev = false;
document.getElementById('div-name').onmouseover = function () {
window.ev = true;
console.log(window.ev);
}
document.getElementById('div-name').onmouseout = function () {
window.ev = false;
console.log(window.ev);
}
window.letsCountIt = function (cdtimer) {
cdtimer--;
document.getElementById('notification').innerHTML = cdtimer;
if (cdtimer == 0) {
if (window.ev === true) {
alert('over');
} else {
alert('not over');
}
} else {
setTimeout(function(){letsCountIt(cdtimer);}, 1000);
}
}
Look into document.elementFromPoint . When you pass an x,y to elementFromPoint, it will return whatever element (or <body>, if no other specific element) is at that point. You can easily check if this element is the element you want.
The problem then is finding out what point your mouse is at. How to get the mouse position without events (without moving the mouse)? seems to say - don't. At least use mouseMove to track the cursor. The linked question gives examples of how to do so. (Look to the lower scoring answers, as the higher ones only got points for being snarky.)
Just want to say that, I think jQuery's mouseenter and mouseleave events would make this a lot easier, but if you can't use them, maybe this will help you.
Depending on how your page is laid out, this may not be too difficult. You can get the position of your element using the following. Quoting from another answer
element.offsetLeft and element.offsetTop are the pure javascript
properties for finding an element's position with respect to its
offsetParent; being the nearest parent element with a position of
relative or absolute
So, if your element is positioned relatively to the body, so far so good (We don't need to adjust anything).
Now, if we attach an event to the document mousemove event, we can get the current coordinates of the mouse:
document.addEventListener('mousemove', function (e) {
var x = e.clientX;
var y = e.clientY;
}, false);
Now we just need to determine if the mouse falls within the element. To do that we need the height and width of the element. Quoting from another answer
You should use the .offsetWidth and .offsetHeight properties. Note
they belong to the element, not .style.
For example:
var element = document.getElementById('element');
var height = element.offsetHeight;
var width = element.offsetWidth;
Now we have all the information we need, and just need to determine if the mouse falls within the element. We might use something like this:
var onmove = function(e) {
var minX = element.offsetLeft;
var maxX = minX + element.offsetWidth;
var minY = element.offsetTop;
var maxY = minY + element.offsetHeight;
if(e.clientX >= minX && e.clientX <= maxX)
//good horizontally
if(e.clientY >= minY && e.clientY <= maxY)
//good vertically
}
This code works, but the mouse has to be moved once after page load.
var coords;
var getMouseCoordinates = function (e) {
'use strict';
return {
x: e.clientX,
y: e.clientY
};
};
document.addEventListener('mousemove', function (e) {
coords = getMouseCoordinates(e);
}, false);
document.addEventListener('click', function () {
var divCoords = document.getElementById('t').getBoundingClientRect();
if (coords.x >= divCoords.left && coords.x <= divCoords.right && coords.y >= divCoords.top && coords.y <= divCoords.bottom) {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
You wouldn't bind to the click event of document, but rather the finish event of your countdown.
Here's an example. Try clicking in the output window.
You don't need any coordinates or mouse events, if you know a selector for that element:
if (document.querySelector('#elementSelector:hover')) {
alert('I like it when you touch me!');
}

Using jQuery .on() when selector element is obscured by another element

I'm trying to get my jQuery event callback to trigger correctly, but I can't seem to get around the fact the element I am interested in not receiving the event because of another element that covers it on the page. I can summarise it as follows (I've styled the elements so they show up in a jsfiddle):
<div id='mydiv'>
<div style="border: 1px solid; border-color: red; position: absolute; left: 0px; top: 0px; width: 200px; height: 200px; z-index: 100">Hello</div>
<canvas style="border: 1px solid; border-color: yellow; position: absolute; left: 50px; top: 50px; width: 150px; height: 150px"></canvas>
</div>​
With the segment above, if I try to listen to mouse clicks on the <canvas>, the event never gets called:
$('#mydiv').on('mousedown', 'canvas', this, function(ev) {
console.log(ev.target);
});
However, if I modify my event handler to listen to the <div> element instead, the callback is triggered as expected:
$('#mydiv').on('mousedown', 'div', this, function(ev) {
console.log(ev.target);
});
How can I coerce my <canvas> to receive events, whilst leaving the offending <div> block in the fore-front?
This should be the simplest solution, as already proposed:
http://jsfiddle.net/CUJ68/4/
$('canvas').on('mousedown', function(ev) {
console.log(ev.target);
});
$('ul').on('mousedown', function(ev){
$('canvas').mousedown();
});
if you need the original eventdata:
$('canvas').bind('mousedown', function(ev, parentEV) {
if(parentEV){
console.log(parentEV);
alert("Canvas INdirectly clicked!");
}else{
console.log(ev);
alert("Canvas directly clicked!");
}
});
$('ul').on('mousedown', function(ev){
$('canvas').trigger('mousedown', ev);
});
You can't. Objects on top get the click events. That's how the DOM works.
If you want to handle that click event, you will need to handle in the object that is on top or use bubbling and handle it in a parent object. You can handle it in the top object and "forward" it to the other object if you want by triggering a click on that other object or by just calling a click handler directly.
Or, you can move the canvas element above the ul by setting it's z-index to a higher value and it will then get the click event.
Or, you can make a new transparent canvas object that is on top that gets the event, leaving the other two objects where they are for the desired visual effect.
You can bind the element to the closest common parent, and check whether the X and Y coordinates of the mouse are within the range of the canvas.
In the example below, I have cached the dimensions (height and width) of the canvas, because I assume these to be constant. Move this inside the function if the dimensions are not constant.
I use the .offset() method to calculate the real X and Y coordinates of the <canvas>s top-left corner. I calculate the coordinates of the bottom-right corner by adding the values of outerWidth() and .outerHeight().
Basic demo: http://jsfiddle.net/75qbX/2/
var $canvas = $('canvas'), /* jQuery reference to the <canvas> */
$canvasWidth = $canvas.outerWidth(), /* assuming height and width to be constant */
$canvasHeight = $canvas.outerHeight();
function isCanvasClicked(x, y, target) {
if (target.tagName === 'CANVAS') return true;
var offset = $canvas.offset(),
left = offset.left,
top = offset.top;
return x >= left && x <= left + $canvasWidth &&
y >= top && y <= top + $canvasHeight;
}
$('#mydiv').on('mousedown', '*', this, function(ev) {
if (isCanvasClicked(ev.pageX, ev.pageY, ev.target)) {
$canvas.fadeOut().fadeIn();
}
});
Here you have a solution that consists in capture click event on above element, and triggering the event on the other: registering clicks on an element that is under another element

Get position of map area(html)?

Is this possible? I'm trying to find the x and y coordinates of the element in relation to the browser.
var position = $(this).position();
x = position.left;
y = position.right;
Doesn't work.
Is there any way to do this?
http://adamsaewitz.com/housing/
highlight the blue room 070
The problem lies in the fact that you are accessing the top/left of an area element.
The area element is not positioned where its coords say. This is handled behind the scenes by the dom/browser.
So you need to find the image that the area relates to and grab its offset.
var imgId = $(this).closest('map').attr('name');
var imgPos = $('#' + imgId).offset();
Then, you grab the coords attribute of the area and split it to get left/top/width and use those to pinpoint the location inside the image.
var coords = $(this).attr('coords').split(',');
var box = {
left: parseInt(coords[0],10),
top: parseInt(coords[1],10),
width: parseInt(coords[2],10)-parseInt(coords[0],10),
height: parseInt(coords[3],10)-parseInt(coords[1],10)
};
Take into consideration the width/height of the info box that appears (and since you animate it, take that into consideration as well) and you get to
x = imgPos.left + box.left + box.width/2 - 65; // 65 is the info width/2
y = imgPos.top + box.top -20 -160 -1; // 20 is the animation, 160 is the info height, 1 is a safe distance from the top
demo: http://www.jsfiddle.net/XBjwN/
Edit for updated question: Since you're using <area> it's a different story, and fetching from the coords attribute is much easier, like this:
var position = $(this).attr('coords').split(',');
x = +position[0] - 50;
y = +position[1] - 170;
The offsets are just to account for the hard-coded width/height of the tooltip itself. In addition to the above, you want to use top and left rather than margin-top and margin-left. Also to account for the #content <div>'s position in the page, give it a relative position for the tooltip to sit in, like this:
#content { position: relative; }
Then...instead of .after(), use .append() so it gets added inside that parent.
You can test the result here.
For original question:
The object .position() returns has top and left properties...but you want .offset() here anyway (it's relative to the document, where .position() is relative to the offset parent), so it should look like this:
var position = $(this).offset(),
x = position.left,
y = position.top; //not right!
Or this:
var position = $(this).offset();
var x = position.left;
var y = position.top;
...but without a single var comma-separated statement, or a var on each line, you're also creating (or trying to) global variables, which will blow up in IE.
$(document).ready(function () {
$('map').imageMapResize();
$('area').hover(function () {
$('.imgpopover').css({ "display": "block", "top": $(this).attr("coords").split(',')[1]+"px", "left": $(this).attr("coords").split(',')[0]+"px" })
$('.imgpopover label').text($(this).attr("title"))
}, )
});

Categories

Resources