clientX/clientY
Attempting to use clientX/clientY using root as the origin of coordinates.
by David Iglesias
HTML
<div id="transform">
<div id="root">
Root
<div id="wrapper">
<div id="content">
Content!<br />
300 x 300<br />
(after scale(1.5))<br/>
<br/>
<tti><tt>INLINE</tt></tti>
<tti><tt>INLINE</tt></tti>
<ttb><tt>BLOCK</tt></ttb>
<ttib><tt>INLINE-BLOCK</tt></ttib>
<tti><tt>INLINE</tt></tti>
</div>
</div>
</div>
<div id="out"></div>
CSS
* {
box-sizing: border-box;
font-family: sans-serif;
}
body {
margin: 0;
padding: 0;
}
ttb,
ttib,
tti {
font-family: monospace;
font-style: italic;
cursor: default;
}
#content ttb {
display: block;
background: red;
transform-origin: 0 0 0;
transform: translate(60px, 130px) rotateX(60deg) rotateZ(-45deg);
}
#content ttib {
display: inline-block;
background: yellow;
transform-origin: 0 0 0;
transform: translate(60px, 130px) rotateX(60deg) rotateZ(-45deg);
}
#content tti {
display: inline;
background: green;
transform-origin: 0 0 0;
transform: translate(60px, 130px) rotateX(60deg) rotateZ(-45deg);
}
#transform {
transform-origin: 20 50;
transform: translate(120px, 20px) rotate(30deg);
}
#root {
position: relative;
width: 500px;
height: 300px;
border: 1px solid black;
background: #eee;
}
#wrapper {
background: rgba(255, 127, 0, 0.5);
pointer-events: none;
}
#content {
position: absolute;
top: 0;
left: 0;
pointer-events: auto;
transform-origin: 0 0;
transform: translate(90px, 10px) rotate(10deg) scale(1.5);
background: #fabada;
border: 1px solid red;
width: 200px;
height: 200px;
}
#out {
padding: 0;
position: absolute;
pointer-events: none;
width: 20px;
height: 20px;
background: #09f;
font-size: 20px;
}
JavaScript
function log(n, x, y) {
out.style.left = `${x}px`;
out.style.top = `${y}px`;
}
let originEl = root; // origin of coordinates (glassPane).
root.addEventListener("pointermove", function (e) {
console.log("===========================");
console.log("===========================");
console.log("===========================");
console.log(`EVENT: [${e.offsetX}, ${e.offsetY}]`);
const matrix = getElementTransformUpTo(e.target, originEl);
const transformedOffset = matrix.transformPoint(
new DOMPoint(e.offsetX, e.offsetY)
);
log(e.target.id, transformedOffset.x, transformedOffset.y);
});
function getElementTransformUpTo(element, upto) {
let matrix = createIdentity();
while (element != null && element !== upto && upto.contains(element)) {
if (doesTransformApply(element)) {
const currentMatrix = new DOMMatrix(window.getComputedStyle(element).transform);
// Apply element offsets that are not part of transform.
currentMatrix.e += element.offsetLeft;
currentMatrix.f += element.offsetTop;
console.log(getOpeningHtml(element));
console.log(`offset: {${element.offsetLeft}, ${element.offsetTop}}`);
console.log("transform:", window.getComputedStyle(element).transform);
console.log("matrix:", currentMatrix.toString());
console.log("-------------------------");
if (!currentMatrix.isIdentity) {
matrix.preMultiplySelf(currentMatrix);
}
}
element = element.offsetParent;
}
return matrix;
}
function createIdentity() {
return new DOMMatrix([1, 0, 0, 1, 0, 0]);
}
function doesTransformApply(element) {
// Transforms don't affect inline elements, so we shouldn't take them
// into account.
return window.getComputedStyle(element).display !== "inline";
}
function getOpeningHtml(element) {
const outer = element.outerHTML;
const end = outer.indexOf(">");
// Use {} instead of <> because jsfiddle console escapes them into > and <
return "{" +...