Skip to content

Instantly share code, notes, and snippets.

@andreiglingeanu
Last active January 30, 2024 22:17
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andreiglingeanu/aa3aef6c8dffb2105736148b2cab3617 to your computer and use it in GitHub Desktop.
Save andreiglingeanu/aa3aef6c8dffb2105736148b2cab3617 to your computer and use it in GitHub Desktop.
A nice way to nullify CSS transforms and get original positions of the un-modified rect
// Nullify the transforms of the element
//
// This is all behaving just like getBoundingClientRect() but it nullifies all the transforms
// and kinds _reverts_ the element onto its original position.
// This will work even with complex translations, rotations.
// The beauty is in the way it applies matrix inverse onto the transformation
// matrix and mutates the getboundingclientrect along the way.
//
// Usage:
// let { top, left } = nullifyTransforms(el);
//
// TODO:
// can probably be extended to be having width/height support too but
// that is not mandatory, I only needed top/left for my use case
//
// Props to that awesome answer on StackOverflow
// https://stackoverflow.com/questions/27745438/how-to-compute-getboundingclientrect-without-considering-transforms
function nullifyTransforms(el) {
//add sanity checks and default values
let {top, left, width, height} = el.getBoundingClientRect()
let transformArr = parseTransform(el)
if (transformArr.length == 6) {
// 2D matrix
// need some math to apply inverse of matrix
// That is the matrix of the transformation of the element
// a scale x
// b shear y
// c shear x
// d scale y
// e translate x
// f translate y
var t = transformArr
let det = t[0] * t[3] - t[1] * t[2]
return {
width: width / t[0],
height: height / t[3],
left:
(left * t[3] - top * t[2] + t[2] * t[5] - t[4] * t[3]) /
det,
top:
(-left * t[1] + top * t[0] + t[4] * t[1] - t[0] * t[5]) /
det,
}
} else {
/*if (transformArr.length > 6)*/
//3D matrix
//haven't done the calculation to apply inverse of 4x4 matrix
return {top, left, width, height}
}
function parseTransform(el) {
let transform = window.getComputedStyle(el).transform
//add sanity check
return transform
.split(/\(|,|\)/)
.slice(1, -1)
.map(function(v) {
return parseFloat(v)
})
}
}
@hirasso
Copy link

hirasso commented May 2, 2019

Never mind, just found out about .offsetLeft and .offsetTop ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment