Skip to content

Instantly share code, notes, and snippets.

@ccpu
Forked from Yaffle/convertPointFromPageToNode.js
Created February 6, 2017 10:56
Show Gist options
  • Save ccpu/5e6e485ad16a908b34aef6e42f27de34 to your computer and use it in GitHub Desktop.
Save ccpu/5e6e485ad16a908b34aef6e42f27de34 to your computer and use it in GitHub Desktop.
function to get the MouseEvent coordinates for an element that has CSS3 Transforms
/*jslint plusplus: true, vars: true, indent: 2 */
/*
convertPointFromPageToNode(element, event.pageX, event.pageY) -> {x, y}
returns coordinate in element's local coordinate system (works properly with css transforms without perspective projection)
convertPointFromNodeToPage(element, offsetX, offsetY) -> {x, y}
returns coordinate in window's coordinate system (works properly with css transforms without perspective projection)
*/
(function () {
"use strict";
var I = new WebKitCSSMatrix();
function Point(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
Point.prototype.transformBy = function (matrix) {
var tmp = matrix.multiply(I.translate(this.x, this.y, this.z));
return new Point(tmp.m41, tmp.m42, tmp.m43);
};
// new WebKitCSSMatrix(), new WebKitCSSMatrix(string)
// WebKitCSSMatrix#m41, WebKitCSSMatrix#m42, WebKitCSSMatrix#m43
// WebKitCSSMatrix#multiply, WebKitCSSMatrix#translate, WebKitCSSMatrix#inverse
function getTransformationMatrix(element) {
var transformationMatrix = I;
var x = element;
while (x != undefined && x !== x.ownerDocument.documentElement) {
var computedStyle = window.getComputedStyle(x, undefined);
var transform = computedStyle.transform || "none";
var c = transform === "none" ? I : new WebKitCSSMatrix(transform);
transformationMatrix = c.multiply(transformationMatrix);
x = x.parentNode;
}
var w = element.offsetWidth;
var h = element.offsetHeight;
var i = 4;
var left = +Infinity;
var top = +Infinity;
while (--i >= 0) {
var p = new Point(i === 0 || i === 1 ? 0 : w, i === 0 || i === 3 ? 0 : h, 0).transformBy(transformationMatrix);
if (p.x < left) {
left = p.x;
}
if (p.y < top) {
top = p.y;
}
}
var rect = element.getBoundingClientRect();
transformationMatrix = I.translate(window.pageXOffset + rect.left - left, window.pageYOffset + rect.top - top, 0).multiply(transformationMatrix);
return transformationMatrix;
}
window.convertPointFromPageToNode = function (element, pageX, pageY) {
return new Point(pageX, pageY, 0).transformBy(getTransformationMatrix(element).inverse());
};
window.convertPointFromNodeToPage = function (element, offsetX, offsetY) {
return new Point(offsetX, offsetY, 0).transformBy(getTransformationMatrix(element));
};
}());
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>demo</title>
<script src="convertPointFromPageToNode.js"></script>
</head>
<body>
<div id='log' style="position:fixed;right:0;top:0;"></div>
<div style="height: 19em;"></div>
<div style="
-o-transform:translate(130px, -200px) skew(60deg, 0);
-webkit-transform:translate(130px, -200px) skew(60deg, 0);
-ms-transform:translate(130px, -200px) skew(60deg, 0);
-moz-transform:translate(130px, -200px) skew(60deg, 0);
transform:translate(130px, -200px) skew(60deg, 0);
">
<div id="clickMe" style="outline:1px solid silver;
padding: 0px;
-o-transform:rotate(25deg);
-webkit-transform:rotate(25deg);
-ms-transform:rotate(25deg);
-moz-transform:rotate(25deg);
transform:rotate(25deg);
left:0;top:0;
width:120px;
height:70px;
background: ghostwhite;
" >120x70</div>
</div>
<script>
var log = document.getElementById('log');
var element = document.getElementById('clickMe');
function a0(element, pageX, pageY) {
return window.webkitConvertPointFromPageToNode != undefined ? window.webkitConvertPointFromPageToNode(element, new WebKitPoint(pageX, pageY)) : {x: undefined, y: undefined};
}
function a1(element, pageX, pageY) {
return {x: pageX, y: pageY};
}
function a2(element, pageX, pageY) {
return window.convertPointFromPageToNode != undefined ? window.convertPointFromPageToNode(element, pageX, pageY) : {x: undefined, y: undefined};
}
function b0(element, offsetX, offsetY) {
return window.webkitConvertPointFromNodeToPage != undefined ? window.webkitConvertPointFromNodeToPage(element, new WebKitPoint(offsetX, offsetY)) : {x: undefined, y: undefined};
}
function b1(element, offsetX, offsetY) {
return {x: offsetX, y: offsetY};
}
function b2(element, offsetX, offsetY) {
return window.convertPointFromNodeToPage != undefined ? window.convertPointFromNodeToPage(element, offsetX, offsetY) : {x: undefined, y: undefined};
}
function test(name, point) {
return "<div>" +
"<div>" + name + ": " + "</div>" +
"<div>" +
(point.x == undefined ? "undefined" : point.x.toFixed(1)) + ", " +
(point.y == undefined ? "undefined" : point.y.toFixed(1)) +
"</div>" +
"</div>";
}
function onMouseMove(event) {
log.innerHTML = (event.target !== element ? "<div style=\"color: red\">The element should be under the mouse pointer</div>" : "") +
test("offsetX/offsetY", event.target === element ? b1(element, event.offsetX, event.offsetY) : {x: undefined, y: undefined}) +
test("webkitConvertPointFromPageToNode", a0(element, event.pageX, event.pageY)) +
test("convertPointFromPageToNode", a2(element, event.pageX, event.pageY)) +
test("pageX/pageY", a1(element, event.pageX, event.pageY)) +
test("webkitConvertPointFromNodeToPage", event.target === element ? b0(element, event.offsetX, event.offsetY) : {x: undefined, y: undefined}) +
test("convertPointFromNodeToPage", event.target === element ? b2(element, event.offsetX, event.offsetY) : {x: undefined, y: undefined});
}
document.addEventListener("mousemove", onMouseMove, false);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment