Я хочу определить , где a MouseEvent
, в координатах относительно элемента, по которому щелкнули .Зачем?Потому что я хочу добавить абсолютно позиционированный дочерний элемент в выбранном месте.
Я знаю, как его обнаружить, когда нет преобразований CSS3 (см. Описание ниже).Однако, когда я добавляю CSS3 Transform, мой алгоритм ломается, и я не знаю, как это исправить.
Я не использую какую-либо библиотеку JavaScript, и я хочу понять, как все работает в простом видеJavaScript.Поэтому, пожалуйста, не отвечайте «просто используйте jQuery».
Кстати, я хочу решение, которое работает для всех MouseEvents, а не просто «щелкает».Это не имеет значения, потому что я считаю, что все события мыши имеют одинаковые свойства, поэтому для всех них должно работать одно и то же решение.
Справочная информация
Согласно DOMСпецификация уровня 2 , a MouseEvent
имеет несколько свойств, связанных с получением координат события:
screenX
и screenY
возвращают координаты экрана (источникявляется верхним левым углом монитора пользователя) clientX
и clientY
возвращают координаты относительно области просмотра документа.
Таким образом, чтобы найти положениеMouseEvent
относительно содержимого элемента, по которому щелкнули, я должен сделать следующее:
ev.clientX - this.getBoundingClientRect().left - this.clientLeft + this.scrollLeft
ev.clientX
- это координата относительно окна просмотра документа this.getBoundingClientRect().left
- этопозиция элемента относительно области просмотра документа this.clientLeft
- это величина границы (и полосы прокрутки) между границей элемента и внутренними координатами this.scrollLeft
- это величина прокрутки внутриэлемент
getBoundingClientRect()
, clientLeft
и scrollLeft
указаны в CSSOM View Module .
Эксперимент без CSS Transform (работает)
Запутываетесь? Попробуйте следующий фрагмент JavaScript и 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-преобразования (он не работает)
Теперь попробуйте добавить 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.
В этом примере единственным преобразованием было масштабирование, поэтому я мог умножить коэффициент масштабирования для вычисления правильной координаты.Однако, если мы думаем о произвольных преобразованиях (масштабирование, поворот, наклон, преобразование, матрица) и даже о вложенных преобразованиях (преобразованный элемент внутри другого преобразованного элемента), то нам действительно нужен лучший способ для вычисления координат.