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:

  1. 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.

  1. function click_handler(ev) {
  2. var rect = this.getBoundingClientRect();
  3. var left = ev.clientX - rect.left - this.clientLeft + this.scrollLeft;
  4. var top = ev.clientY - rect.top - this.clientTop + this.scrollTop;
  5. var dot = document.createElement('div');
  6. dot.setAttribute('style', 'position:absolute; width: 2px; height: 2px; top: '+top+'px; left: '+left+'px; background: red;');
  7. this.appendChild(dot);
  8. }
  9. document.getElementById("experiment").addEventListener('click', click_handler, false);
  10. <div id="experiment" style="border: 5px inset #AAA; background: #CCC; height: 400px; position: relative; overflow: auto;">
  11. <div style="width: 900px; height: 2px;"></div>
  12. <div style="height: 900px; width: 2px;"></div>
  13. </div>

Experiment adding a CSS Transform (it fails)

Now, try adding a CSS transform:

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

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.

How to get the MouseEvent coordinates for an element that has CSS3 Transform?的更多相关文章

  1. Why AlloyFinger is so much smaller than hammerjs?

    AlloyFinger is the mobile web gesture solution at present inside my company, major projects are in u ...

  2. OpenSceneGraph控制模型

    OpenSceneGraph控制模型 转自:http://www.cppblog.com/eryar/archive/2012/05/28/176538.html 一.简介 对模型的控制就是修改模型的 ...

  3. 【RobotFramework】Selenium2Library类库关键字使用说明

    Add CookieArguments:[ name | value | path=None | domain=None | secure=None | expiry=None ]Adds a coo ...

  4. pageX/Y, offset(), position(), scrollTop(), screenX/Y, clientX/Y, pageX/Y

    event.pageX get mouse position Description: The mouse position relative to the left edge of the docu ...

  5. cocos2d中的可见性检测

    游戏的在进行一次渲染的时候,通常会提交大量的渲染对象给gpu.在这些需要渲染的对象中,并不是所有对象都会出现镜头中,即有一部分对象是不可见的. 通常有两种方式来完成不可见对象的剔除工作: (1)直接交 ...

  6. js 导出Excel

    最近从Silverlight这边转到javascript过来,现在要导出一个导出excel的功能.上级领导指示当页显示多少数据,就导出多少数据,没有必要从后台在去数据.以前也没有接触过这方面的,在网上 ...

  7. Easy Multiple Copy to Clipboard by ZeroClipboard

    要实现在多个复制按钮复制的功能(具体代码在附件中,路径修改一下就行了): <%@ page language="java" import="java.util.*& ...

  8. 转:VS2008 vs2010中JQUERY智能提醒

    第一步: 安装VS 2008 SP1 VS 2008 SP1 在Visual Studio中加了更丰富的JavaScript intellisense支持,对很大部分的JavaScript库加了代码完 ...

  9. appium点击屏幕(手势)

    在android测试过程中,会遇到要点击一下屏幕的需求. 在appium旧版本使用下面代码点击android屏幕,没有报错.Map tap = new HashMap(); tap.put(" ...

随机推荐

  1. VM网络连接设置具体解释

    參考http://zhidao.baidu.com/link? url=NU8UcLsp6CCgRZzeMgnb7v0p7Z78eLYloYW355Z9fQa__pm_lFBtpfSs61ZR2Wq2 ...

  2. 2017-3-3 leetcod 1 35 448

    ACM退役了,接下来是考研的准备,刷刷leetcode保证不会生手,也算是调剂生活,初步计划是每天三题吧,希望可以坚持下去. 打算按照专题来做,先是Array....本来以为特别水,结果.... == ...

  3. 30.QT IDE编写

    mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QTe ...

  4. vue项目中遇到的打印,以及处理重新排版后不显示echarts图片问题。

    1. 项目中用到的打印 页面: css: 控制好宽度一般A4 我调试的是794px多了放不下,小了填不满.当时多页打印的时候,一定要控制好每一个页面内容显示的高度不要超过一个页面,当然根据自己项目来. ...

  5. infludb语法--官网

    https://docs.influxdata.com/influxdb/v0.8/api/query_language/ InfluxDB features a SQL like query lan ...

  6. 微信小程序面试题

    小程序与原生App哪个好? 答: 小程序除了拥有公众号的低开发成本.低获客成本低以及无需下载等优势,在服务请求延时与用户使用体验是都得到了较大幅度  的提升,使得其能够承载跟复杂的服务功能以及使用户获 ...

  7. Android WebView回退

    在使用webView时,会出现点击按钮让网页页面回到上一个页面的需求,这时可以使用goBack方法. 但是有的安卓用户会习惯点击手机自带的返回按钮,这时会直接关闭当前的activity,而不是网页页面 ...

  8. jQuery $.ajax跨域-JSONP获取JSON数据(转载)

    Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术.Ajax 允许在不干扰 Web 应用程序的显示 ...

  9. 使用Eclipse将项目上传至远程GitLab

    一.先将项目提交至本地仓库 1.  右击项目——Team——Share Project… 2.在弹出框中,选择Git——Next 3.在弹出框中进行如下步骤操作 4.至此,我们已经成功创建了本地GIT ...

  10. Java之Object类

    0 引言 Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类.Object类是Java中唯一没有父类的类. 其他所有的类,包括标准容器类,比如数组,都继承了Object类中的方法 ...