2011-04-22 863 views
13

当鼠标移动到元素上时,我想要获取相对于元素内容区域左上角的鼠标坐标(这是不包括填充的区域,边框和轮廓)。听起来很简单,对吧?我至今是一个非常受欢迎的功能:获取鼠标相对于元素内容区域的位置

function element_position(e) { 
    var x = 0, y = 0; 
    do { 
     x += e.offsetLeft; 
     y += e.offsetTop; 
    } while (e = e.offsetParent); 
    return { x: x, y: y }; 
} 

而且我相对鼠标位置得到一个元素element

p = element_position(element); 
x = mouseEvent.pageX - p.x; 
y = mouseEvent.pageY - p.y; 

这是不完全正确的。由于offsetLeftoffsetTop是元素的“外部”左上角与其偏移父级的“内部”左上角之间的差异,因此总和位置将跳过层次结构中的边框和填充处的全部

下面是一个比较,应该(希望)澄清我的意思。

  • 如果我有距离的总和中的元素的“外部”左上角的偏移父母的“内部”左上角之间的位置(,外表面减去内部件;什么,我现在在做什么),我得到元素的内容区域的位置,减去偏移层次结构中的所有边框和填充。
  • 如果我得到元素的'外部'左上角和他们抵消父项的'外部'左上角之间的距离总和(外部减去外部),我得到元素的内容区域的位置,减去所需元素的边界和填充(关闭,但不是那里)。
  • 如果我得到元素的“内部”左上角与其父亲的内部左上角之间的距离总和(内部减号内部),则获取元素内容区域的位置。这就是我要的。
+0

我个人更喜欢不将CSS应用于画布本身,而是将画布包裹在用CSS装饰的元素中。带走很多PITA。 ;) – 2011-04-22 12:49:14

+0

这是真的,我不会在我的画布元素上应用填充/边框。只是一个理论问题,真的。 – 2011-04-22 12:52:00

+1

看起来'offsetLeft/Top'类型的获取元素位置的方法不仅不符合目标元素的边框和填充的大小,而且也包含所有偏移父元素的边框和填充。请查看我重写的问题,看看你是否可以考虑我的情况。 – 2011-04-22 13:30:27

回答

10

下面是一个使用element_position()功能是感知填充和边框的活生生的例子。我为您的原始示例添加了一些额外的填充和边距。

http://jsfiddle.net/Skz8g/4/

要使用它,将光标移动到棕色区域。由此产生的白色区域是实际的画布内容。棕色是填充,红色是边框,依此类推。在这个例子和稍后的例子中,canvas xcanvas y读数指示相对于画布内容的光标位置。

下面的代码为element_position()

function getNumericStyleProperty(style, prop){ 
    return parseInt(style.getPropertyValue(prop),10) ; 
} 

function element_position(e) { 
    var x = 0, y = 0; 
    var inner = true ; 
    do { 
     x += e.offsetLeft; 
     y += e.offsetTop; 
     var style = getComputedStyle(e,null) ; 
     var borderTop = getNumericStyleProperty(style,"border-top-width") ; 
     var borderLeft = getNumericStyleProperty(style,"border-left-width") ; 
     y += borderTop ; 
     x += borderLeft ; 
     if (inner){ 
      var paddingTop = getNumericStyleProperty(style,"padding-top") ; 
      var paddingLeft = getNumericStyleProperty(style,"padding-left") ; 
      y += paddingTop ; 
      x += paddingLeft ; 
     } 
     inner = false ; 
    } while (e = e.offsetParent); 
    return { x: x, y: y }; 
} 

代码应在IE9,FF和Chrome正常工作,虽然我注意到它是不完全正确的歌剧。

我最初的倾向是使用类似e.offsetX/Y属性的东西,因为它们更接近你想要的,并且不涉及循环嵌套元素。然而,他们的行为在不同浏览器之间变化很大,所以需要一些跨浏览器的讨论。在活生生的例子是在这里:

http://jsfiddle.net/xUZAa/6/

应该在所有现代浏览器的工作 - 歌剧,FF,Chrome浏览器,IE9。我个人比较喜欢它,但认为尽管你最初的问题只是“让鼠标位置相对于元素的内容区域而言”,但你确实在问如何使element_position()函数正常工作。

+1

感谢您的回答,并感谢所有人的回答。我特别接受你的,因为它不使用外部库,并选择你的Aleadam's,因为你去创建代码和演示的麻烦(虽然Aleadam,你是完全正确的,所以感谢你的答案!)。这项任务似乎很简单,但必须手动实施;我真的认为,理想情况下,在规范中至少应该有本地属性,比如'offsetLeft'和'offsetTop',但对于内容区域位置。 – 2011-04-25 13:45:54

+0

我注意到,如果我把光标放在它注册的画布的左上角(2,1)不是(0,0)。我试过一个单独的方法,并运行相同的问题([这里])(http://stackoverflow.com/questions/29607924/click-in-canvas-is-three-pixels-off)) - 有没有人有修复? – 2015-04-13 15:16:38

+1

@Pi,只是一个疯狂的猜测,但它可能取决于光标图标的“来源”是什么。原点可能不在您期望的位置,即在箭头的顶端。您可能想尝试使用十字光标并查看您获得的结果。 – brainjam 2015-04-13 16:26:06

1

我不知道这是否是最好的方式,还是最有效利用资源......

不过,我会建议得到X/Y的canvas标签,边框宽度,并填充和使用他们一起作为抵消。

编辑:

使用offsetLeft和的offsetTop

参考:How to Use the Canvas and Draw Elements in HTML5

var x; 
var y; 
if (e.pageX || e.pageY) { 
    x = e.pageX; 
    y = e.pageY; 
} 
else { 
    x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 
    y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft; 
y -= gCanvasElement.offsetTop; 
+0

这是个好主意,但*我该怎么做? – 2011-04-22 12:36:03

+0

用我在http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-找到的一段代码更新了答案。元素由N4ppeL - 使用offsetLeft和offsetTop – 2011-04-22 12:44:32

+0

请检查我完全重写的问题,让我知道你是否可以衡量的情况。 ;) – 2011-04-22 13:28:55

2

在你element_position(e)功能,通过使用parentNode层次遍历,得到填充,偏移和使用getComputedStyle(e, null).getPropertyValue(each_css)边界,并在返回之前将它们总计为您的xy值。

有一个帖子提出的样式跨浏览器阅读此:使用jQuery

http://bytes.com/topic/javascript/answers/796275-get-div-padding

4

function posRelativeToElement(elem, ev){ 
    var $elem = $(elem), 
     ePos = $elem.offset(), 
    mousePos = {x: ev.pageX, y: ev.pageY}; 

    mousePos.x -= ePos.left + parseInt($elem.css('paddingLeft')) + parseInt($elem.css('borderLeftWidth')); 
    mousePos.y -= ePos.top + parseInt($elem.css('paddingTop')) + parseInt($elem.css('borderTopWidth')); 

    return mousePos; 
}; 

活生生的例子:http://jsfiddle.net/vGKM3/

这一现象的根本是简单:计算元素相对于文档的位置。然后,我放弃顶部&左填充&边框(边距包括在基本定位计算中)。这样做的内部jQuery代码基于getComputedStyleelement.currentStyle。不幸的是,我不认为还有另一种方式......

jQuery的.offset()功能,其位置相对元素的到达文件的核心:

if ("getBoundingClientRect" in document.documentElement) { 
    ... 
    try { 
     box = elem.getBoundingClientRect(); 
    } catch(e) {} 

    var body = doc.body, 
     win = getWindow(doc), 
     clientTop = docElem.clientTop || body.clientTop || 0, 
     clientLeft = docElem.clientLeft || body.clientLeft || 0, 
     scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop), 
     scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft), 
     top = box.top + scrollTop - clientTop, 
     left = box.left + scrollLeft - clientLeft; 

    return { top: top, left: left }; 
}else{ 
    // calculate recursively based on .parentNode and computed styles 
} 

从理论上说,另一种方式来做到这一点是,使用上面的定位代码:

  • 确保您的元素有position: relative(或绝对)设置
  • 追加了新的元素与position: absolute; top:0px; left:0px;
  • 获取相对于文档的新元素元素的位置。这将是同父的内容位置
  • 删除新元素
+0

非常好的...... – user960567 2012-05-11 15:31:36

相关问题