jQuery get mouse position within an element

255,926

Solution 1

One way is to use the jQuery offset method to translate the event.pageX and event.pageY coordinates from the event into a mouse position relative to the parent. Here's an example for future reference:

$("#something").click(function(e){
   var parentOffset = $(this).parent().offset(); 
   //or $(this).offset(); if you really just want the current element's offset
   var relX = e.pageX - parentOffset.left;
   var relY = e.pageY - parentOffset.top;
});

Solution 2

To get the position of click relative to current clicked element
Use this code

$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 

Solution 3

I use this piece of code, its quite nice :)

    <script language="javascript" src="http://code.jquery.com/jquery-1.4.1.js" type="text/javascript"></script>
<script language="javascript">
$(document).ready(function(){
    $(".div_container").mousemove(function(e){
        var parentOffset = $(this).parent().offset();
        var relativeXPosition = (e.pageX - parentOffset.left); //offset -> method allows you to retrieve the current position of an element 'relative' to the document
        var relativeYPosition = (e.pageY - parentOffset.top);
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    }).mouseout(function(){
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    });
});
</script>

Solution 4

@AbdulRahim answer is almost correct. But I suggest the function below as substitute (for futher reference):

function getXY(evt, element) {
                var rect = element.getBoundingClientRect();
                var scrollTop = document.documentElement.scrollTop?
                                document.documentElement.scrollTop:document.body.scrollTop;
                var scrollLeft = document.documentElement.scrollLeft?                   
                                document.documentElement.scrollLeft:document.body.scrollLeft;
                var elementLeft = rect.left+scrollLeft;  
                var elementTop = rect.top+scrollTop;

                x = evt.pageX-elementLeft;
                y = evt.pageY-elementTop;

                return {x:x, y:y};
            }




            $('#main-canvas').mousemove(function(e){
                var m=getXY(e, this);
                console.log(m.x, m.y);
            });

Solution 5

This solution supports all major browsers including IE. It also takes care of scrolling. First, it retrieves the position of the element relative to the page efficiently, and without using a recursive function. Then it gets the x and y of the mouse click relative to the page and does the subtraction to get the answer which is the position relative to the element (the element can be an image or div for example):

function getXY(evt) {
    var element = document.getElementById('elementId');  //replace elementId with your element's Id.
    var rect = element.getBoundingClientRect();
    var scrollTop = document.documentElement.scrollTop?
                    document.documentElement.scrollTop:document.body.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft?                   
                    document.documentElement.scrollLeft:document.body.scrollLeft;
    var elementLeft = rect.left+scrollLeft;  
    var elementTop = rect.top+scrollTop;

        if (document.all){ //detects using IE   
            x = event.clientX+scrollLeft-elementLeft; //event not evt because of IE
            y = event.clientY+scrollTop-elementTop;
        }
        else{
            x = evt.pageX-elementLeft;
            y = evt.pageY-elementTop;
    }
Share:
255,926

Related videos on Youtube

Chris Dutrow
Author by

Chris Dutrow

Creator, EnterpriseJazz.com Owner, SharpDetail.com LinkedIn

Updated on March 15, 2020

Comments

  • Chris Dutrow
    Chris Dutrow over 4 years

    I was hoping to craft a control where a user could click inside a div, then drag the mouse, then let up on the mouse in order to indicate how long they want something to be. (This is for a calendar control, so the user will be indicating the length, in time, of a certain event)

    It looks like the best way to do this would be to register a "mousedown" event on the parent div that in turn registers a "mousemove" event on the div until a "mouseup" event is triggered. The "mousedown" and "mouseup" events will define the start and end of the time range and as I follow "mousemove" events, I can dynamically change the size of the range so that the user can see what they are doing. I based this off of how events are created in google calendar.

    The issue I'm having is that the jQuery event seems to only provide reliable mouse coordinate information in reference to the whole page. Is there any way to discern what the coordinates are in reference to the parent element?

    Edit:

    Heres a picture of what I'm trying to do: alt text

  • Pointy
    Pointy over 13 years
    Yes this is a great idea if the parent element's layout can't/shouldn't be changed!
  • Chris Dutrow
    Chris Dutrow over 13 years
    Hey Pointy, thanks for your response. Based on your wording, it sounds like what you are suggesting is different than what jball suggested, but I'm not understanding how, can you elaborate? Thanks again
  • jball
    jball over 13 years
    @DutrowLLC, Pointy is suggesting changing the style of the parent element to have "position:relative". The jQuery position would then report its positions relative to the parent element, not the page. The wording on my answer is poor, it implies that it is directly related to Pointy's solution, but it is a way of calculating the offset when you can't or don't want to depend on the style attributes of the parent element.
  • Chris Dutrow
    Chris Dutrow over 13 years
    So if I set "position:relative" jQuery will report the relatiove position correctly in all browsers? The reason I ask is because the jQuery documentation seemed to imply that the only dependable mouse position in all browsers was the one in relation to the browser window itself.
  • Pointy
    Pointy over 13 years
    A box with "position: relative" will make the "top" and "left" (etc.) setting for child boxes by relative to the relative parent box's content rectangle.
  • Chris Dutrow
    Chris Dutrow over 13 years
    I may be doing something wrong, but this does not appear to work in firefox. I have "position:relative;" set in the parent, firefox reports event.pageX and event.clientX identically (with respect to the top, left of the page) and reports event.offsetX as undefined
  • Pointy
    Pointy over 13 years
    I think there's a misunderstanding - what I was writing about was the returned results of the jQuery ".position()" function, which one might call for an element on the page. Have you checked the "clientX" and "clientY" values in the event?
  • Gayan Hewa
    Gayan Hewa over 12 years
    Great , i was looking for this. I have being tring to do something similar to remember the scroll bar position with the tiny scrollbar jquery plugin.
  • jcfrei
    jcfrei almost 12 years
    I tried jquerys offsetX properties, but they displayed some wierd behaviour when moving over another element. your solution however worked!
  • Lee Goddard
    Lee Goddard about 11 years
    Does this answer take into account padding/borders?
  • jball
    jball about 11 years
    According to the docs, offset does not account "for borders, margins, or padding set on the body element." I haven't encountered a problem with my posted answer in use, but it might be good to check for those being set.
  • Flash Thunder
    Flash Thunder over 10 years
    This doesn't have to work. offset() is relative too, so if the parent is a child of other element, this will give wrong result. Use position() instead.
  • Dex
    Dex over 10 years
    This doesn't work for something centered with text-align:center
  • Michael Scheper
    Michael Scheper over 9 years
    @FlashThunder: position() always returns (0,0) for me. But the problem with offset() is that it can return floats, because of this: stackoverflow.com/a/4626568/1450294
  • James Watkins
    James Watkins over 8 years
    The question is about how to get the position of the mouse relative to the element, not how to get the position of an element relative to its parent, so the jQuery position() function isn't useful here.
  • James Watkins
    James Watkins over 8 years
    @FlashThunder offset() is not relative, at least not according to the docs. Also it should be standard practice to not have any margins or padding on the body element.
  • Pointy
    Pointy over 8 years
    @JamesWatkins Is there any way to discern what the coordinates are in reference to the parent element? The point of my answer that using relative positioning of the element in question (or an appropriate parent) makes it possible to interpret the mouse position and the element position on the same terms.
  • James Watkins
    James Watkins over 8 years
    Then you should be using offset(), not position(). And "position: relative" on the parent element is completely irrelevant, except maybe in very specific circumstances. I don't see any reason why this answer is helpful.
  • James Watkins
    James Watkins over 8 years
    This about this mathematically. I have a cursor position (cpx, cpy) global to the page, and I want to find the position of said cursor within parent element located at (px, py) relative to its parent. So I do (cpx-px, cpy-py) but this is wrong, because the parent's parent may have a position. Offset() is the only solution here.
  • Solomon Closson
    Solomon Closson almost 8 years
    relY is returning NaN, I just want to know if a click occurred from within the element Y axis, 0 - 30 pixels from the very top of the element. But this approach does not work at all, since it returns NaN.
  • Solomon Closson
    Solomon Closson almost 8 years
    Your answer helped me BTW, the accepted answer did not. Thanks :) What I actually used is this, instead: var y = e.pageY - $(this).offset().top; But your answer led me on the right path.
  • Bud Damyanov
    Bud Damyanov over 7 years
    Brilliant improvement, saved my day.
  • Sanjay Manohar
    Sanjay Manohar over 7 years
    If the event is within an SVG, then you will need to use getScreenCTM().inverse(). See the wizardry at stackoverflow.com/a/10298843/93910
  • Benn
    Benn about 7 years
    almost , add margin to the canvas and you are off by the margin
  • Jesper
    Jesper over 6 years
    Saved my day! Thanks!
  • Stefan
    Stefan almost 6 years
    This is some great piece of code, thank you so much!