Last active
April 30, 2024 03:50
-
-
Save Yaffle/1145197 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 p1 = new Point(0, 0, 0).transformBy(transformationMatrix); | |
var p2 = new Point(w, 0, 0).transformBy(transformationMatrix); | |
var p3 = new Point(w, h, 0).transformBy(transformationMatrix); | |
var p4 = new Point(0, h, 0).transformBy(transformationMatrix); | |
var left = Math.min(p1.x, p2.x, p3.x, p4.x); | |
var top = Math.min(p1.y, p2.y, p3.y, p4.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> |
@Yaffle thanks for this, though I had to do this:
var I = new WebKitCSSMatrix([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
//Identity;
I.m11 = 1;
I.m22 = 1;
I.m33 = 1;
I.m44 = 1;
to make it work exactly as former native implementation
@marchant, hm.... why?
Is there some ready-to-use npm library for this? Or maybe even some polyfill to implement what was mentioned in https://gist.github.com/Yaffle/1145197?permalink_comment_id=1243925#gistcomment-1243925 (GeometryUtils)?
In line 49 and 50 you are using p4
which does not exist, however, p0
remains unused. Probably just an off-by-one error.
@JannikGM , right, thanks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@acterhd, https://stackoverflow.com/questions/24765227/how-do-i-traverse-up-out-of-shadow-dom - ?