-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*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)); | |
}; | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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