Skip to content

Instantly share code, notes, and snippets.

@envex
Forked from abernier/.gitignore
Last active February 24, 2016 13:18
Show Gist options
  • Select an option

  • Save envex/fbb6ba8978a594cb21d6 to your computer and use it in GitHub Desktop.

Select an option

Save envex/fbb6ba8978a594cb21d6 to your computer and use it in GitHub Desktop.
domvertices.js
node_modules/

domvertices

Compute the 4 vertices absolute coordinates of any deep transformed, positioned DOM element.

a                b
 +--------------+
 |              |
 |      el      |
 |              |
 +--------------+
d                c

Usage

var el = document.getElementById('foo');

console.log(domvertices(el));

outputs:

{
	a: {x: , y: , z: },
	b: {x: , y: , z: },
	c: {x: , y: , z: },
	d: {x: , y: , z: }
}
(function () {
var THREE = this.THREE || require('three');
//
// Normalize 4x4 matrix from string, ie: 'matrix()' or 'matrix3d()' or 'none'
//
function normalizeMatrix (matrixString) {
var c = matrixString.split(/\s*[(),]\s*/).slice(1,-1);
var matrix;
if (c.length === 6) {
// 'matrix()' (3x2)
matrix = new THREE.Matrix4().set(
c[0], +c[2], 0, +c[4],
+c[1], +c[3], 0, +c[5],
0, 0, 1, 0,
0, 0, 0, 1
);
} else if (c.length === 16) {
// matrix3d() (4x4)
matrix = new THREE.Matrix4().set(
+c[0], +c[4], +c[8], +c[12],
+c[1], +c[5], +c[9], +c[13],
+c[2], +c[6], +c[10], +c[14],
+c[3], +c[7], +c[11], +c[15]
);
} else {
// handle 'none' or invalid values.
matrix = new THREE.Matrix4().identity();
}
return matrix;
}
function domvertices(el) {
//
// a b
//  +--------------+
//  | |
//  | el |
//  | |
//  +--------------+
// d c
//
var w = el.offsetWidth;
var h = el.offsetHeight;
var v = {
a: new THREE.Vector3().set(0, 0, 0), // top left corner
b: new THREE.Vector3().set(w, 0, 0), // top right corner
c: new THREE.Vector3().set(w, h, 0), // bottom right corner
d: new THREE.Vector3().set(0, h, 0) // bottom left corner
};
//
// Walk the DOM up, and extract
//
var matrices = [];
while (el.nodeType === 1) {(function () {
var computedStyle = getComputedStyle(el, null);
//
// P(0->1) : relative position (to parent)
//
var P01;
(function () {
var x = 0;
var y = 0;
var parent = el.parentNode;
if (parent && parent.nodeType === 1) {
var parentComputedStyle = getComputedStyle(parent, null);
var offsetLeft = el.offsetLeft;
var offsetTop = el.offsetTop;
if (parentComputedStyle.position === 'static') {
offsetLeft -= parent.offsetLeft;
offsetTop -= parent.offsetTop;
}
x = offsetLeft - el.scrollLeft + el.clientLeft;
y = offsetTop - el.scrollTop + el.clientTop;
}
P01 = new THREE.Matrix4().makeTranslation(x, y, 0);
}).call(this);
//
// P(1->2) : transform-origin
//
var P12;
(function () {
var transformOrigin = computedStyle.transformOrigin || computedStyle.webkitTransformOrigin || computedStyle.MozTransformOrigin || computedStyle.msTransformOrigin;
transformOrigin = transformOrigin.split(' ');
var x = parseFloat(transformOrigin[0], 10);
var y = parseFloat(transformOrigin[1], 10);
P12 = new THREE.Matrix4().makeTranslation(x, y, 0);
}).call(this);
//
// P(2->3) : transform
//
var P23;
(function () {
var transform = computedStyle.transform || computedStyle.webkitTransform || computedStyle.MozTransform || computedStyle.msTransform;
P23 = normalizeMatrix(transform);
}).call(this);
//
// P(0->3) = P(0->1) . P(1->2) . P(2->3)
//
var P21 = new THREE.Matrix4().getInverse(P12);
var P03 = new THREE.Matrix4().identity();
P03.multiply(P01); // (1): translate position
P03.multiply(P12); // (2): translate transform-origin
P03.multiply(P23); // (3): transform
P03.multiply(P21); // (4): inverse of (2)
matrices.push(P03);
el = el.parentNode;
}())}
//
// apply changes of basis (in reverse order)
//
for (var i=0; i<matrices.length; i++) {
v.a = v.a.applyMatrix4(matrices[i]);
v.b = v.b.applyMatrix4(matrices[i]);
v.c = v.c.applyMatrix4(matrices[i]);
v.d = v.d.applyMatrix4(matrices[i]);
}
return v;
}
// Exports
this.domvertices = domvertices;
if (typeof module !== "undefined" && module !== null) {
module.exports = this.domvertices;
}
}).call(this);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.scene {-webkit-perspective:250;}
.scene, .camera {width:100vw; height:100vh;}
.camera, .camera * {-webkit-transform-style:preserve-3d;}
.camera {transform:rotateX(20deg) scale(1.1); background:rgba(255,255,255,.5);}
div {
display: inline-block;
background: rgba(255,0,0,.5);
width: 100px;
box-shadow: 0 0 0 1px red;
}
#a {margin-left:-50px;margin-top:-10px; transform:translate(200px, 150px) rotate(-10deg) translateZ(50px); transform-origin:center;}
#b {margin-left:100px; transform:translate(100px, 50px) rotate(-10deg) translateZ(50px) rotateX(-20deg); transform-origin:center;}
#c {position:relative; transform:translateY(100px);}
#d {position:absolute;left:100px; transform:translate(-50px, 50px) rotate(10deg); transform-origin:right top;}
#e {position:fixed;left:100px;top:50%; transform:scale(2) translate(-60px, 30px) rotate(20deg); transform-origin:right top;}
</style>
</head>
<body style="margin:0;">
<div class="scene"><div class="camera">
<div id="a">
a
<div id="b">
b
<div id="c">
c
<div id="d">
d
<div id="e">
e
</div>
</div>
</div>
</div>
</div>
</div></div>
<script src="https://code.jquery.com/jquery-2.1.3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.js"></script>
<script src="domvertices.js"></script>
<script>
function trace(v) {
for (k in v) { //
$('<b>').css({
display:'block',width:'0px',height:'0px', boxShadow:'0 0 0 1px lime',
position:'absolute',left:'0px',top:'0px', transform:'translate3d(' + v[k].x + 'px,' + v[k].y + 'px, ' + v[k].z + 'px)'
}).appendTo('.scene'); // !important so <b> is subjected to perspective
}
}
trace(domvertices(document.querySelector('#a')));
trace(domvertices(document.querySelector('#b')));
trace(domvertices(document.querySelector('#c')));
trace(domvertices(document.querySelector('#d')));
trace(domvertices(document.querySelector('#e')));
</script>
</body>
</html>
{
"name": "domvertices",
"version": "0.0.0",
"description": "Compute 4 vertices absolute coordinates from any DOM element.",
"main": "domvertices.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://gist.github.com/97a5fb8c1bebacd1958e.git"
},
"author": "Antoine BERNIER (abernier)",
"license": "ISC",
"dependencies": {
"three": "^0.69.0"
},
"devDependencies": {
"jquery": "^2.1.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment