javascript - 如何获取具有 CSS3 转换的元素的 MouseEvent 坐标?

标签 javascript html css transform

我想检测哪里 MouseEvent 发生了,在相对于被点击元素的坐标。为什么?因为我想在点击的位置添加一个绝对定位的子元素。

我知道当不存在 CSS3 转换时如何检测它(见下面的描述)。但是,当我添加 CSS3 转换时,我的算法出现故障,我不知道如何修复它。

我没有使用任何 JavaScript 库,我想了解纯 JavaScript 的工作原理。所以,请不要回答“只使用 jQuery”。

顺便说一句,我想要一个适用于所有 MouseEvent 的解决方案,而不仅仅是“单击”。这并不重要,因为我相信所有鼠标事件都共享相同的属性,因此相同的解决方案应该适用于所有鼠标事件。


背景资料

根据 DOM Level 2 specification , 一个 MouseEvent具有与获取事件坐标相关的几个属性:

  • screenXscreenY 返回屏幕坐标(原点是用户显示器的左上角)
  • clientXclientY 返回相对于文档视口(viewport)的坐标。

因此,为了找到 MouseEvent 相对于被单击元素内容的位置,我必须进行以下计算:

ev.clientX - this.getBoundingClientRect().left - this.clientLeft + this.scrollLeft
  • ev.clientX是相对于文档视口(viewport)的坐标
  • this.getBoundingClientRect().left是元素相对于文档视口(viewport)的位置
  • this.clientLeft 是元素边界和内部坐标之间的边框(和滚动条)数量
  • this.scrollLeft 是元素内部的滚动量

getBoundingClientRect() , clientLeftscrollLeftCSSOM View Module 指定.

没有 CSS 转换的实验(它有效)

令人困惑? Try the following piece of JavaScript and HTML .单击后,一个红点应该正好出现在单击发生的位置。这个版本“非常简单”并且按预期工作。

function click_handler(ev) {
    var rect = this.getBoundingClientRect();
    var left = ev.clientX - rect.left - this.clientLeft + this.scrollLeft;
    var top = ev.clientY - rect.top - this.clientTop + this.scrollTop;

    var dot = document.createElement('div');
    dot.setAttribute('style', 'position:absolute; width: 2px; height: 2px; top: '+top+'px; left: '+left+'px; background: red;');
    this.appendChild(dot);
}

document.getElementById("experiment").addEventListener('click', click_handler, false);

<div id="experiment" style="border: 5px inset #AAA; background: #CCC; height: 400px; position: relative; overflow: auto;">
    <div style="width: 900px; height: 2px;"></div> 
    <div style="height: 900px; width: 2px;"></div>
</div>

尝试添加 CSS 转换(失败)

现在,try adding a CSS transform :

#experiment {
    transform: scale(0.5);
    -moz-transform: scale(0.5);
    -o-transform: scale(0.5);
    -webkit-transform: scale(0.5);
    /* Note that this is a very simple transformation. */
    /* Remember to also think about more complex ones, as described below. */
}

该算法不知道转换,因此计算出错误的位置。此外,Firefox 3.6 和 Chrome 12 的结果不同。Opera 11.50 的行为与 Chrome 一样。

在这个例子中,唯一的变换是缩放,所以我可以乘以缩放因子来计算正确的坐标。但是,如果我们考虑任意变换(缩放、旋转、倾斜、平移、矩阵),甚至嵌套变换(一个变换元素在另一个变换元素中),那么我们确实需要一种更好的方法来计算坐标。

最佳答案

您遇到的行为是正确的,并且您的算法没有中断。首先,CSS3 Transforms 的设计不会干扰盒子模型。

试图解释...

当您在元素上应用 CSS3 转换时。元素采用一种相对定位。因为周围的元素不受转换元素的影响。

例如想象水平行中的三个 div。如果应用缩放变换来减小中心 div 的大小。周围的 div 不会向内移动以占据曾经占据转换元素的空间。

示例:http://jsfiddle.net/AshMokhberi/bWwkC/

所以在盒子模型中,元素实际上并没有改变大小。只有它的渲染尺寸发生变化。

您还必须记住,您正在应用缩放变换,因此您的元素“实际”大小实际上与其原始大小相同。您只是在改变它的感知大小。

解释..

假设您创建了一个宽度为 1000 像素的 div 并将其缩小到原来的 1/2。 div 的内部大小仍然是 1000px,而不是 500px。

所以你的点的位置相对于 div 的“真实”大小是正确的。

我修改了你的例子来说明。

说明

  1. 单击 div 并将鼠标保持在同一位置。
  2. 找到错误位置的点。
  3. 按 Q,div 将变成正确的大小。
  4. 将鼠标移动到您点击的正确位置上的点。

http://jsfiddle.net/AshMokhberi/EwQLX/

因此,为了使鼠标点击坐标与 div 上的可见位置相匹配,您需要了解鼠标基于窗口返回坐标,并且您的 div 偏移量也基于其“真正的"尺寸。

由于您的对象大小是相对于窗口的,因此唯一的解决方案是使用与您的 div 相同的比例值来缩放偏移坐标。

然而,根据您设置 div 的 Transform-origin 属性的位置,这可能会变得棘手。因为这会影响偏移量。

看这里。

http://jsfiddle.net/AshMokhberi/KmDxj/

希望这对您有所帮助。

关于javascript - 如何获取具有 CSS3 转换的元素的 MouseEvent 坐标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6773481/

相关文章:

html - Button 中的图像大小在 Internet Explorer 中格式不正确

javascript - 样式化 SelectedRow in Rich :dataTable

javascript - 移动 Safari 独立模式下的可见性变化

javascript - 使用ajax url调用函数

html - 如何仅在CSS中模糊背景图像

javascript - 调整矩形 HTML5 Canvas

html - 如何在垂直线上创建阴影效果

javascript - 这段 Javascript 是怎么回事?

javascript - WebGL 中的 texImage2D 需要多少数据?

html - 两个相同大小的元素显示不同的宽度