How to know what elements are in current mouse position? - javascript

I need know what elements are in current mouse position and I'm using jQuery.

If I understood you correctly you need to find out the element over the mouse is currently on. If this is correct you can use
document.elementFromPoint ( x, y );
document.elementFromPoint
Returns the element from the document
whose elementFromPoint method is being
called which is the topmost element
which lies under the given point. The
point is specified via coordinates, in
CSS pixels, relative to the
upper-left-most point in the window or
frame containing the document.
$(document).ready(function(){
$(this).mousemove(function(e){
var elem = document.elementFromPoint ( e.pageX , e.pageY );
alert ( elem.id );
});
})

Related

Position tooltip above mouse when room in viewport, otherwise below mouse

I am creating a tooltip and am having some problems with positioning it.
The tooltip is set to position: absolute, and I have a handler for mouse events that modifies it's top and left CSS depending on the pageX and pageY.
Now, I know I can just set the top to pageY and left to pageX. That will make the tooltip pop up to the bottom-right. I'm trying to orient it where it pops up on the top-right when there is room, but if it would be out of the viewport on the Y-axis, drop to the bottom-right position again.
At the moment, I'm stuck trying to get the tooltip to show to the top-right of the mouse. I don't even know where to begin detecting if it would be in the viewport. Can anyone point me in the right direction?
$('p').on('mouseenter', function(e) {
$(tt).css('top', e.pageY - $(tt).css('height'));
$(tt).css('left', e.pageX);
$(tt).appendTo('body');
}).on('mousemove', function(e) {
$(tt).css('top', e.pageY - $(tt).css('height'));
$(tt).css('left', e.pageX);
}).on('mouseleave', function(e) {
$(tt).detach();
});
Example on JSFiddle
There are many different ways to handle tooltips, especially when using jQuery. This method probably would not have been my first choice. However, the following changes should work how you intended.
var tt = document.createElement('div');
tt.id = "tt";
$('p').on('mouseenter', function(e) {
var curPos = $( this ).offset().top - $( window ).scrollTop();
var inView = (curPos < 250) ? 0 : 250;
$(tt).css('top', e.pageY - inView);
$(tt).css('left', e.pageX);
$(tt).append($( this ).attr("data-myId"));
$(tt).appendTo('body');
}).on('mousemove', function(e) {
$(tt).css('top', e.pageY - $(tt).css('height'));
$(tt).css('left', e.pageX);
}).on('mouseleave', function(e) {
$(tt).empty($( this ).attr("data-myId"));
$(tt).detach();
});
Full changes in JSFiddle.
I am taking advantage of jQuery's offset() and scrollTop() methods to estimate the position of the current element within the viewable area of the document.
According to jQuery's API documentation, the .offset() method
allows us to retrieve the current position of an element relative to
the document. The documentation also states that the vertical
scroll position (.scrollTop()) is the same as the number of pixels that are hidden
from view above the scrollable area.
We use both of these methods to our advantage and subtract the number of pixels above the scrollable area from the current position of the element relative to the document. One important thing to note is that the offset method returns an object with the properties top and left.
var curPos = $( this ).offset().top - $( window ).scrollTop();
Since you had the #tt id set to a static 250px height, we can check if the current element position relative to the viewable portion of the window is less than 250. If it is, then we subtract nothing and let the tool tip sit below the mouse position. If it is greater than 250 then we subtract 250px and the tool tip will be above the current mouse position.
I am not sure how you were intending to pull in the content for the tool tips, but I also added $(tt).append($( this ).attr("data-myId")); to use the data-myId value as the tool tip content and $(tt).empty($( this ).attr("data-myId")); to clear it on mouseleave. I hope this helps!

Difference between offsetParent and parentElement or parentNode

I have a following DOM structure
<body>
<div>
<table>
<outerElement>
<innerElement />
</outerElement>
<table>
</div>
</body>
DIV has its overflow set to auto so if table grows bigger - it scrolls within the DIV.
In this scenario why table.offsetParent returns the body while both table.parentNode and parentElement return the Div?
I need to calculate current position of the innerElement within the window, so I traverse from it up thru all parent elements, collecting their offsetTop and offsetLeft values. Up until the DIV offsetParent works fine and then it skips it directly to the body. The problem if there's scrolling involved at some point, I need to account for scrollTop and scrollLeft as well - like in the DIV in the above example. The problem is if I use offsetParent I never encounter the DIV as one of the parents.
UPDATE
This is part of the code that does the traversing:
while (oElem && getStyle(oElem, 'position') != 'absolute' && getStyle(oElem, 'position') != 'relative') {
curleft += oElem.offsetLeft;
curtop += oElem.offsetTop;
oElem = oElem.offsetParent;
}
where getStyle is a custom function that in this case retrieves the position style.
offsetParent is the closest parent that has position:relative or position:absolute or the body of the page. parentNode is the direct parent, regardless of position.
Using getBoudingClientRect() is really a great help (thanks Ally for the hint!).
If you still need the position relative to the upper left corner of the document, here's a helpful snippet:
if (node.getBoundingClientRect) {
var rect = node.getBoundingClientRect();
var sx = -(window.scrollX ? window.scrollX : window.pageXOffset);
var sy = -(window.scrollY ? window.scrollY : window.pageYOffset);
return {
x: rect.left - sx,
y: rect.top - sy
}
}
Note: document.body.getBoundingClientRect() may return an unexpected value for topin Firefox under some circumstances. Therefore, the window scroll position is more robust.
For the client who do not yet support getBoundingClientRect(), we still must walk the offetParents and take care that every overflow: scroll (or auto) parent has position: relative.
Stay clear of offsetParent, you'll have to add lots of hacks and checks to ensure you get it right.
Try using getBoundingClientRect instead.
offsetParent is essentially the parent in UI
parentNode is actually the parent in DATA/HTML
offsetParent is included to deprecate traditional parentNode

Getting mouse position inside parent div with javascript/jQuery [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
jQuery get mouse position within an element
I have a page and inside that page I have a div.
If the user clicks inside that div it'll store the X/Y co-ordinates of where they clicked inside that div.
E.g. if I clicked in the top left corner of the div (no matter where the div was placed on the page) it'd return approximately 0, 0.
Is this even possible? and if so, could you tell me how - or even point me in the right direction?
Use pageX property of the event to get the x coordinate relative to the page and pageY to get the y coordinate, then substract the element's coordinates to get the position relative to the element.
$( '#target' ).on( 'click', function( e ) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
});​
Demo: http://jsfiddle.net/WhrFt/
Official tutorial on jquery.com: http://docs.jquery.com/Tutorials:Mouse_Position

offsetTop vs. jQuery.offset().top

I have read that offsetLeft and offsetTop do not work properly in all browsers. jQuery.offset() is supposed to provide an abstraction for this to provide the correct value xbrowser.
What I am trying to do is get the coordinates of where an element was clicked relative to the top-left of the element.
Problem is that jQuery.offset().top is actually giving me a decimal value in FFX 3.6 (in IE and Chrome, the two values match).
This fiddle exhibits the issue. If you click the bottom image, jQuery.offset().top returns 327.5, but offsetTop returns 328.
I would like to think that offset() is returning the correct value and I should use it because it will work across browsers. However, people obviously cannot click decimals of pixels. Is the proper way to determine the true offset to Math.round() the offset that jQuery is returning? Should I use offsetTop instead, or some other method entirely?
This is what jQuery API Doc says about .offset():
Get the current coordinates of the first element, or set the
coordinates of every element, in the set of matched elements, relative
to the document.
This is what MDN Web API says about .offsetTop:
offsetTop returns the distance of the current element relative to the
top of the offsetParent node
This is what jQuery v.1.11 .offset() basically do when getting the coords:
var box = { top: 0, left: 0 };
// BlackBerry 5, iOS 3 (original iPhone)
if ( typeof elem.getBoundingClientRect !== strundefined ) {
box = elem.getBoundingClientRect();
}
win = getWindow( doc );
return {
top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
};
pageYOffset intuitively says how much was the page scrolled
docElem.scrollTop is the fallback for IE<9 (which are BTW unsupported in jQuery 2)
docElem.clientTop is the width of the top border of an element (the document in this case)
elem.getBoundingClientRect() gets the coords relative to the document viewport (see comments). It may return fraction values, so this is the source of your bug. It also may cause a bug in IE<8 when the page is zoomed. To avoid fraction values, try to calculate the position iteratively
Conclusion
If you want coords relative to the parent node, use element.offsetTop. Add element.scrollTop if you want to take the parent scrolling into account. (or use jQuery .position() if you are fan of that library)
If you want coords relative to the viewport use element.getBoundingClientRect().top. Add window.pageYOffset if you want to take the document scrolling into account. You don't need to subtract document's clientTop if the document has no border (usually it doesn't), so you have position relative to the document
Subtract element.clientTop if you don't consider the element border as the part of the element
I think you are right by saying that people cannot click half pixels, so personally, I would use rounded jQuery offset...
Try this: parseInt(jQuery.offset().top, 10)
It is possible that the offset could be a non-integer, using em as the measurement unit, relative font-sizes in %.
I also theorise that the offset might not be a whole number when the zoom isn't 100% but that depends how the browser handles scaling.
You can use parseInt(jQuery.offset().top) to always use the Integer (primitive - int) value across all browsers.

Convert absolute position to relative

Is it possible to change DIV position from absolute to relative (and from relative to absolute)?
DIV should remain on same place.
Because formatting in comments is not work I will publish solution here
$(object).css({position: 'absolute',top: dy, left:dx});
// dy, dx - some coordinates
$(object).css({position: 'relative'});
Does not work: element position after changing to relative is different.
But when I stored offset and set it again after changing to relative, position is the same:
$(object).css({position: 'absolute',top: dy, left:dx});
var x = $(object).offset().left;
var y = $(object).offset().top;
$(object).css({position: 'relative'});
$(object).offset({ top: y, left: x });
you can change that attribute with
$(object).css({position: 'absolute'});
For instance:
You could use jQuery's methods .position() or .offset() to set "top" and "left"
css attribute aswell, that way your object should stay at it's position changing
from relative -> absolute.
I don't think that works vice versa.
demo code: http://jsbin.com/uvoka
If you really want to get the total top offset of an element that is a child of elements with absolute and relative positions you could use this function
function calcTotalOffsetTop(elm)
{
var totalOffsetTop = 0,
curr = elm;
while( curr.parent().is(':not(body)') )
{
curr = curr.parent();
totalOffsetTop += curr[0].offsetTop;
}
return totalOffsetTop;
}
this is the basically the code for the solution given by plodder above.
You can quite easily change it from relative to absolute by using it's offsetLeft and offsetTop values as left and top styles.
The other way around is harder. You would basically have to change it to relative and see where it ended up, then calculate new offset values from the current offset and the desired location.
Note that when the positioning is relative, the element is part of the page flow and may affect other elements. When the position is absolute, the element is outside the page flow and doesn't affect other elements. So, if you change between absolute and relative positioning, you may need to do changes to other elements also if you don't want them to move.
prototype.js has element.absolutize() and element.relativize which work very well.
The problem with going from relative to absolute is that
element.offsetTop and offsetLeft
only give the offset of your element to its parent.
You need to measure the cumualtive offset (i.e.
the offset of your element to its parent +
the offset of the parent to its parent +
the offset of its parent to its parent +
etc.)

Categories

Resources