代码之家  ›  专栏  ›  技术社区  ›  Ben Shelock

查找相对于元素的鼠标位置

  •  165
  • Ben Shelock  · 技术社区  · 16 年前

    我想做一个小的绘画应用程序使用画布。所以我需要在画布上找到鼠标的位置。

    19 回复  |  直到 16 年前
        1
  •  195
  •   Jeff Ward    5 年前

    对于使用JQuery的用户:

    有时,当您有嵌套的元素时,其中一个元素附加了事件,要理解浏览器视为父元素的内容可能会很混乱。在这里,您可以指定哪个父级。

    获取鼠标位置,然后从父元素的偏移位置减去鼠标位置。

    var x = evt.pageX - $('#element').offset().left;
    var y = evt.pageY - $('#element').offset().top;
    

    如果要在滚动窗格内的页面上获取鼠标位置:

    var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
    var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
    

    或相对于页面的位置:

    var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
    var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
    

    注意以下性能优化:

    var offset = $('#element').offset();
    // Then refer to 
    var x = evt.pageX - offset.left;
    

    #element 每行。

    有一个更新的,只使用JavaScript的版本 an answer 由@anytimecoder编写--另请参见 browser support for getBoundingClientRect()

        2
  •  437
  •   HoldOffHunger Lux    5 年前

    由于我没有找到可以复制/粘贴的jQuery免费答案,因此我使用了以下解决方案:

    document.getElementById('clickme').onclick = function clickEvent(e) {
          // e = Mouse click event.
          var rect = e.target.getBoundingClientRect();
          var x = e.clientX - rect.left; //x position within the element.
          var y = e.clientY - rect.top;  //y position within the element.
          console.log("Left? : " + x + " ; Top? : " + y + ".");
        }
    #clickme {
      margin-top: 20px;
      margin-left: 100px;
      border: 1px solid black;
      cursor: pointer;
    }
    <div id="clickme">Click Me -<br>
    (this box has margin-left: 100px; margin-top: 20px;)</div>

    JSFiddle of full example

        3
  •  63
  •   Lee Goddard    8 年前

    下面计算鼠标相对于画布元素的位置关系:

    var example = document.getElementById('example'); 
    example.onmousemove = function(e) { 
        var x = e.pageX - this.offsetLeft; 
        var y = e.pageY - this.offsetTop; 
    }
    

    在这个例子中, this example e onmousemove

        4
  •  44
  •   Patrick Boos Luis    6 年前

    在纯javascript中,当引用元素嵌套在其他元素(可以使用绝对定位)中时,没有返回相对坐标的答案。以下是此场景的解决方案:

    function getRelativeCoordinates (event, referenceElement) {
    
      const position = {
        x: event.pageX,
        y: event.pageY
      };
    
      const offset = {
        left: referenceElement.offsetLeft,
        top: referenceElement.offsetTop
      };
    
      let reference = referenceElement.offsetParent;
    
      while(reference){
        offset.left += reference.offsetLeft;
        offset.top += reference.offsetTop;
        reference = reference.offsetParent;
      }
    
      return { 
        x: position.x - offset.left,
        y: position.y - offset.top,
      }; 
    
    }
    
        5
  •  23
  •   Fabian von Ellerts    6 年前

    我尝试了所有这些解决方案,由于我的矩阵转换容器(panzoom库)的特殊设置,没有一个奏效。即使缩放和平移,也会返回正确的值:

    mouseevent(e) {
     const x = e.offsetX,
           y = e.offsetY
    }
    

    但前提是没有子元素。这可以通过使用CSS使它们对事件“不可见”来避免:

    .child {
       pointer-events: none;
    }
    
        6
  •  20
  •   pid    6 年前

    关于这个问题的难度,可以在这里找到一个很好的描述: http://www.quirksmode.org/js/events_properties.html#position

    element.getBoundingClientRect() 将返回具有以下属性的对象: { bottom, height, left, right, top, width } . 从这里可以很容易地判断出事件是否发生在元素内部。

        7
  •  10
  •   John    8 年前

    我遇到了这个问题,但是为了使它适用于我的案例(在DOM元素上使用dragover(在我的案例中不是canvas)),我发现您只需要使用 offsetX offsetY 关于dragover鼠标事件。

    onDragOver(event){
     var x = event.offsetX;
     var y = event.offsetY;
    }
    
        8
  •  7
  •   Matt    13 年前

    我+1'马克范怀克的答案,因为它让我在正确的方向,但没有完全解决它为我。我仍然有一个抵消绘画中的元素包含在另一个元素。

    下面是我的答案:

            x = e.pageX - this.offsetLeft - $(elem).offset().left;
            y = e.pageY - this.offsetTop - $(elem).offset().top;
    

    换句话说,我只是简单地将所有嵌套元素的所有偏移叠加起来

        9
  •  5
  •   FlorianB    9 年前

    // Cross-browser AddEventListener
    function ael(e, n, h){
        if( e.addEventListener ){
            e.addEventListener(n, h, true);
        }else{
            e.attachEvent('on'+n, h);
        }
    }
    
    var touch = 'ontouchstart' in document.documentElement; // true if touch device
    var mx, my; // always has current mouse position IN WINDOW
    
    if(touch){
        ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
    }else{
        ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
    }
    
    // local mouse X,Y position in element
    function showLocalPos(e){
        document.title = (mx - e.getBoundingClientRect().left)
            + 'x'
            + Math.round(my - e.getBoundingClientRect().top);
    }
    

    如果您需要知道当前页面的Y滚动位置:

    var yscroll = window.pageYOffset
            || (document.documentElement && document.documentElement.scrollTop)
            || document.body.scrollTop; // scroll Y position in page
    
        10
  •  4
  •   Jonathan H    9 年前

    取自 this tutorial

    function getMousePos( canvas, evt ) {
        var rect = canvas.getBoundingClientRect();
        return {
            x: Math.floor( ( evt.clientX - rect.left ) / ( rect.right - rect.left ) * canvas.width ),
            y: Math.floor( ( evt.clientY - rect.top ) / ( rect.bottom - rect.top ) * canvas.height )
        };
    }
    

    在画布上使用,如下所示:

    var canvas = document.getElementById( 'myCanvas' );
    canvas.addEventListener( 'mousemove', function( evt ) {
        var mousePos = getMousePos( canvas, evt );
    } );
    
        11
  •  4
  •   kungfooman    8 年前
    canvas.onmousedown = function(e) {
        pos_left = e.pageX - e.currentTarget.offsetLeft;
        pos_top = e.pageY - e.currentTarget.offsetTop;
        console.log(pos_left, pos_top)
    }
    

    这个 HTMLElement.offsetLeft 只读属性返回当前元素的左上角在 HTMLElement.offsetParent

    对于块级元素, offsetTop offsetLeft , offsetWidth ,和 offsetHeight 描述元素相对于 offsetParent

    但是,对于内联级别的元素(例如 span 偏置 偏移左侧 描述第一个边框框的位置(使用 Element.getClientRects() 得到它的宽度和高度),而 远视 描述边界框的尺寸(使用 Element.getBoundingClientRect() 得到它的位置)。因此,一个盒子的左,顶,宽和高 , 偏置 , 网外宽度

    HTMLElement.offsetop文件

    HTMLElement.offsetTop 只读属性返回当前元素相对于对象顶部的距离 抵销母公司 节点。

    鼠标事件.pageX

    pageX 只读属性返回事件相对于整个文档的X(水平)坐标(以像素为单位)。此属性考虑页面的任何水平滚动。

    MouseEvent.pageY

    有关更多说明,请参见Mozilla开发者网络:

    https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop

        12
  •  4
  •   John T.    8 年前

    只有3条规则:

    1. 在工作中尽量少做 mousemove touchmove 事件。
    2. 在工作中尽可能多地做 mousedown touchstart 事件。
    3. 取消传播并防止触摸事件的默认值,以防止鼠标事件也在混合设备上触发。

    不用说,事情更复杂 touch 因为可以有多个事件,而且它们比鼠标事件更灵活(复杂)。我只讲一点。是的,我很懒,但这是最常见的接触方式,所以就这样。

    var posTop;
    var posLeft;
    function handleMouseDown(evt) {
      var e = evt || window.event; // Because Firefox, etc.
      posTop = e.target.offsetTop;
      posLeft = e.target.offsetLeft;
      e.target.style.background = "red";
      // The statement above would be better handled by CSS
      // but it's just an example of a generic visible indicator.
    }
    function handleMouseMove(evt) {
      var e = evt || window.event;
      var x = e.offsetX; // Wonderfully
      var y = e.offsetY; // Simple!
      e.target.innerHTML = "Mouse: " + x + ", " + y;
      if (posTop)
        e.target.innerHTML += "<br>" + (x + posLeft) + ", " + (y + posTop);
    }
    function handleMouseOut(evt) {
      var e = evt || window.event;
      e.target.innerHTML = "";
    }
    function handleMouseUp(evt) {
      var e = evt || window.event;
      e.target.style.background = "yellow";
    }
    function handleTouchStart(evt) {
      var e = evt || window.event;
      var rect = e.target.getBoundingClientRect();
      posTop = rect.top;
      posLeft = rect.left;
      e.target.style.background = "green";
      e.preventDefault(); // Unnecessary if using Vue.js
      e.stopPropagation(); // Same deal here
    }
    function handleTouchMove(evt) {
      var e = evt || window.event;
      var pageX = e.touches[0].clientX; // Touches are page-relative
      var pageY = e.touches[0].clientY; // not target-relative
      var x = pageX - posLeft;
      var y = pageY - posTop;
      e.target.innerHTML = "Touch: " + x + ", " + y;
      e.target.innerHTML += "<br>" + pageX + ", " + pageY;
      e.preventDefault();
      e.stopPropagation();
    }
    function handleTouchEnd(evt) {
      var e = evt || window.event;
      e.target.style.background = "yellow";
      // Yes, I'm being lazy and doing the same as mouseout here
      // but obviously you could do something different if needed.
      e.preventDefault();
      e.stopPropagation();
    }
    div {
      background: yellow;
      height: 100px;
      left: 50px;
      position: absolute;
      top: 80px;
      user-select: none; /* Disable text selection */
      -ms-user-select: none;
      width: 100px;
    }
    <div 
      onmousedown="handleMouseDown()" 
      onmousemove="handleMouseMove()"
      onmouseout="handleMouseOut()"
      onmouseup="handleMouseUp()" 
      ontouchstart="handleTouchStart()" 
      ontouchmove="handleTouchMove()" 
      ontouchend="handleTouchEnd()">
    </div>
    Move over box for coordinates relative to top left of box.<br>
    Hold mouse down or touch to change color.<br>
    Drag to turn on coordinates relative to top left of page.

    Vue.js ? 我愿意!那么您的HTML将如下所示:

    <div @mousedown="handleMouseDown"
         @mousemove="handleMouseMove"
         @mouseup="handleMouseUp"
         @touchstart.stop.prevent="handleTouchStart"
         @touchmove.stop.prevent="handleTouchMove"
         @touchend.stop.prevent="handleTouchEnd">
    
        13
  •  3
  •   rob waminal    16 年前

    你能搞定的

    var element = document.getElementById(canvasId);
    element.onmousemove = function(e) {
        var xCoor = e.clientX;
        var yCoor = e.clientY;
    }
    
        14
  •  3
  •   FutureSci    9 年前

    我意识到我有点晚了,但这是纯javascript的工作原理,如果元素大于视口并且用户已经滚动,它甚至会给出元素中指针的坐标。

    var element_offset_x ; // The distance from the left side of the element to the left of the content area
    
    
    ....// some code here (function declaration or element lookup )
    
    
    
    element_offset_x = element.getBoundingClientRect().left  -  document.getElementsByTagName("html")[0].getBoundingClientRect().left  ;
    
    ....// code here 
    
    
    
    
    function mouseMoveEvent(event) 
    {
       var pointer_location = (event.clientX + window.pageXOffset) - element_offset_x ; 
    }
    

    工作原理。

    getBoundingClientRect().left 因为html标记将是负数。然后我们使用这个数字来计算元素和内容区域左侧之间的距离。与 element_offset_x = element.getBoundingClientRect().left......;

    知道元素与内容区域的距离。 event.clientX

    为了补偿这一点,我们需要将指针的x位置(相对于视口)添加到视口的x位置(相对于内容区域)。视口的X位置可以通过 window.pageXOffset.

        15
  •  3
  •   Letokteren    8 年前

    // Get the container element's bounding box
    var sides = document.getElementById("container").getBoundingClientRect();
    
    // Apply the mouse event listener
    document.getElementById("canvas").onmousemove = (e) => {
      // Here 'self' is simply the current window's context
      var x = (e.clientX - sides.left) + self.pageXOffset;
      var y = (e.clientY - sides.top) + self.pageYOffset;
    }
    

    这既适用于滚动,也适用于缩放(在这种情况下,有时它会返回浮动)。

        16
  •  2
  •   Artem Bochkarev    6 年前
    
    const findMousePositionRelativeToElement = (e) => {
        const xClick = e.clientX - e.currentTarget.offsetLeft;
        const yClick = e.clientY - e.currentTarget.offsetTop;
        console.log(`x: ${xClick}`);
        console.log(`y: ${yClick}`);
    
        // or
        const rect = e.currentTarget.getBoundingClientRect();
        const xClick2 = e.clientX - rect.left;
        const yClick2 = e.clientY - rect.top;
        console.log(`x2: ${xClick2}`);
        console.log(`y2: ${yClick2}`);
    }
    
    
        17
  •  2
  •   Kohill Yang    5 年前

    let bbox_rect = document.getElementById("dom-ID").getBoundingClientRect()
    let layerX = e.clientX-bbox_rect.left
    let layerY = e.clientY-bbox_rect.top
    
        18
  •  1
  •   Nino Filiu    9 年前

    借助event.offsetX和event.offsetY,可以获得画布中的鼠标坐标。这里有一个小片段来证明我的观点:

    c=document.getElementById("c");
    ctx=c.getContext("2d");
    ctx.fillStyle="black";
    ctx.fillRect(0,0,100,100);
    c.addEventListener("mousemove",function(mouseEvt){
      // the mouse's coordinates on the canvas are just below
      x=mouseEvt.offsetX;
      y=mouseEvt.offsetY;
      // the following lines draw a red square around the mouse to prove it
      ctx.fillStyle="black";
      ctx.fillRect(0,0,100,100);
      ctx.fillStyle="red";
      ctx.fillRect(x-5,y-5,10,10);
    });
      
    body {
      background-color: blue;
    }
    
    canvas {
      position: absolute;
      top: 50px;
      left: 100px;
    }
    <canvas id="c" width="100" height="100"></canvas>
        
        19
  •  1
  •   Athinodoros Sgouromallis    7 年前

    我实现了另一个我认为非常简单的解决方案,所以我想和你们分享一下。

    0,0 用于鼠标光标。所以我需要捕捉鼠标在div上的位置来调整div的新位置。

    示例代码:

     onDrag={(e) => {
              let newCoords;
              newCoords = { x: e.pageX - this.state.correctionX, y: e.pageY - this.state.correctionY };
              this.props.onDrag(newCoords, e, item.id);
            }}
            onDragStart={
              (e) => {
                this.setState({
                  correctionX: e.nativeEvent.layerX,
                  correctionY: e.nativeEvent.layerY,
                });
              }
    

        20
  •  1
  •   MbPCM    6 年前
    function myFunction(e) {
        var x =  e.clientX - e.currentTarget.offsetLeft ; 
        var y = e.clientY - e.currentTarget.offsetTop ;
    }
    

    这工作正常!

        21
  •  1
  •   BrieucKyo    6 年前

    你可以用 getBoudingClientRect() relative

    document.addEventListener("mousemove", (e) => {
      let xCoord = e.clientX - e.target.getBoundingClientRect().left + e.offsetX
      let yCoord = e.clientY - e.target.getBoundingClientRect().top + e.offsetY
      console.log("xCoord", xCoord, "yCoord", yCoord)
    })
    
        22
  •  1
  •   thomas    5 年前

    您可以简单地使用jQuerys event.pageX event.pageY 用这个方法 以获取鼠标相对于元素的位置。

      $(document).ready(function() {
        $("#myDiv").mousemove(function(event){            
          var X = event.pageX - $(this).offset().left;
          var Y = event.pageY - $(this).offset().top;
          $(".cordn").text("(" + X + "," + Y + ")");
        });
      });
    

    How to find mouse position relative to element

        23
  •  0
  •   Eli Mashiah    9 年前

    你必须知道你的页面的结构,因为如果你的画布是一个div的孩子,而这个div又是另一个div的孩子。。。然后故事就变得更复杂了。下面是我在2层div s中的画布代码:

    canvas.addEventListener("click", function(event) {
    var x = event.pageX - (this.offsetLeft + this.parentElement.offsetLeft);
    var y = event.pageY - (this.offsetTop + this.parentElement.offsetTop);
    console.log("relative x=" + x, "relative y" + y);
    

    });

        24
  •  0
  •   Smertrios2007    9 年前

    <html>
    <body>
    <script>
    
    var main=document.createElement('canvas');
    main.width="200";
    main.height="300";
    main.style="padding:0px;margin:30px;border:thick dashed red";
    document.body.appendChild(main);
    
    // adding event listener
    
    main.addEventListener('mousemove',function(e){
        var ctx=e.target.getContext('2d');
        var c=Math.floor(Math.random()*0xFFFFFF);
        c=c.toString(16); for(;c.length<6;) c='0'+c;
        ctx.strokeStyle='#'+c;
        ctx.beginPath();
        ctx.arc(e.offsetX,e.offsetY,3,0,2*Math.PI);
        ctx.stroke();
        e.target.title=e.offsetX+' '+e.offsetY;
        });
    
    // it worked! move mouse over window
    
    </script>
    </body>
    </html>
    
        25
  •  0
  •   Emanuele Pavanello    5 年前

    基于 @Patrick Boos solution 但解决了中间滚动条的潜在问题。

    export function getRelativeCoordinates(event: MouseEvent, referenceElement: HTMLElement) {
      const position = {
        x: event.pageX,
        y: event.pageY,
      };
    
      const offset = {
        left: referenceElement.offsetLeft,
        top: referenceElement.offsetTop,
      };
    
      let reference = referenceElement.offsetParent as HTMLElement;
    
      while (reference) {
        offset.left += reference.offsetLeft;
        offset.top += reference.offsetTop;
        reference = reference.offsetParent as HTMLElement;
      }
    
      const scrolls = {
        left: 0,
        top: 0,
      };
    
      reference = event.target as HTMLElement;
      while (reference) {
        scrolls.left += reference.scrollLeft;
        scrolls.top += reference.scrollTop;
        reference = reference.parentElement as HTMLElement;
      }
    
      return {
        x: position.x + scrolls.left - offset.left,
        y: position.y + scrolls.top - offset.top,
      };
    }
    
        26
  •  0
  •   ahwelp    5 年前

    我必须用滚动条把光标放在一个很宽的div中。目标是将元素拖到div的任何位置。

    $('.canvas').on('mousemove', function(e){
        $(dragElement).parent().css('top', e.currentTarget.scrollTop + e.originalEvent.clientY );
        $(dragElement).parent().css('left', e.currentTarget.scrollLeft + e.originalEvent.clientX )
    });
    
        27
  •  -1
  •   ChrisF    7 年前

    这是我得到的。

        $(".some-class").click(function(e) {
    
        var posx = 0;
        var posy = 0;
    
        posx = e.pageX;
        posy = e.pageY;
    
        alert(posx);
        alert(posy);
    });