您的位置:首页 > Web前端 > CSS

How to get the MouseEvent coordinates for an element that has CSS3 Transform?

2017-06-18 13:15 465 查看
I want to detect where a
MouseEvent
has
occurred, in coordinates relative to the clicked element. Why? Because I want to add an absolutely positioned child element
at the clicked location.

I know how to detect it when no CSS3 transformations exist (see description below). However, when I add a CSS3 Transform, then my algorithm breaks, and I don't know how to fix it.

I'm not using any JavaScript library, and I want to understand how things work in plain JavaScript. So, please, don't answer with "just use jQuery".

By the way, I want a solution that works for all MouseEvents, not just "click". Not that it matters, because I believe all mouse events share the same properties, thus the same solution should work for all of them.


Background information

According to DOM
Level 2 specification, a
MouseEvent
has
few properties related to getting the event coordinates:

screenX
and
screenY
return
the screen coordinates (the origin is the top-left corner of user's monitor)

clientX
and
clientY
return
the coordinates relative the document viewport.

Thus, in order to find the position of the
MouseEvent
relative
to the clicked element content, I must do this math:

ev.clientX - this.getBoundingClientRect().left - this.clientLeft + this.scrollLeft


ev.clientX
is
the coordinate relative to the document viewport

this.getBoundingClientRect().left
is
the position of the element relative to the document viewport

this.clientLeft
is
the amount of border (and scrollbar) between the element boundary and the inner coordinates

this.scrollLeft
is
the amount of scrolling inside the element

getBoundingClientRect()
,
clientLeft
and
scrollLeft
are
specified at CSSOM
View Module.


Experiment without CSS Transform (it works)

Confusing? Try the following piece
of JavaScript and HTML. Upon clicking, a red dot should appear exactly where the click has happened. This version is "quite simple" and works as expected.

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>


Experiment adding a CSS Transform (it fails)

Now, 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. */
}


The algorithm doesn't know about the transformations, and thus calculates a wrong position. What's more, the results are different between Firefox 3.6 and Chrome 12. Opera 11.50 behaves just like Chrome.

In this example, the only transformation was scaling, so I could multiply the scaling factor to calculate the correct coordinate. However, if we think about arbitrary transformations (scale, rotate, skew, translate, matrix), and even nested transformations
(a transformed element inside another transformed element), then we really need a better way to calculate the coordinates.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐