![](/img/trans.png)
[英]Trouble with difference bewteen CSS 2d and 3d matrix using javascript to get vertex corners
[英]get real 2D vertex coordinates of a div after CSS 3D transformations with Javascript
我已經嘗試了幾天,但似乎無法正確解決。
基本上,我有一些div,其父級具有CSS透視圖並應用了rotateX 3D轉換,我需要獲取這些div的實際屏幕坐標。
這是一個jsfiddle,上面有我的意思的示例(盡管無法正常工作)。
https://jsfiddle.net/6ev6d06z/3/
如您所見,頂點已關閉(由於其父級的轉換)
我試過使用
getBoundingClientRect()
但這似乎並沒有考慮3D轉換。 我不知道是否有一種已經建立的方法來獲取我所需要的東西,否則我想必須有一種使用matrix3D計算坐標的方法。
任何幫助表示贊賞。
因為它沒有內置的方法來獲取轉換后的元素的每個頂點的實際2d坐標。 對於所有API(例如getBoundingClientRect),它們返回已轉換元素的邊界矩形,表示為2點矩形[(top,left),(bottom,right)]。
話雖如此,您只需花費一點點精力和矩陣數學就可以絕對獲得實際坐標。 最簡單的方法是使用預制的矩陣庫進行數學運算(我對math.js有所了解,但並未使用過),盡管它當然可以自己實現。
用偽代碼執行以下操作:
然后在真實代碼中獲得樂趣: https : //jsfiddle.net/cLnmgvb3/1/
$(".target").on('click', function(){
$(".vertex").remove();
// Note: The 'parentOrigin' and 'rect' are computed relative to their offsetParent rather than in doc
// coordinates. You would need to change how these offsets are computed to make this work in a
// more complicated page. In particular, if txParent becomes the offsetParent of 'this', then the
// origin will be wrong.
// (1) Get the untransformed bounds of the parent element. Here we only care about the relative offset
// of the parent element to its offsetParent rather than it's full bounding box. This is the origin
// that the target elements are relative to.
var txParent = document.getElementById('transformed');
var parentOrigin = [ txParent.offsetLeft, txParent.offsetTop, 0, 0 ];
console.log('Parent Origin: ', parentOrigin);
// (2) Get the untransformed bounding box of the target elements. This will be the box that is transformed.
var rect = { left: this.offsetLeft, top: this.offsetTop, right: this.offsetLeft + this.offsetWidth, bottom: this.offsetTop + this.offsetHeight };
// Create the vertices in the coordinate system of their offsetParent - in this case <body>.
var vertices =
[
[ rect.left, rect.top, 0, 1 ],
[ rect.right, rect.bottom, 0, 1 ],
[ rect.right, rect.top, 0, 1 ],
[ rect.left, rect.bottom, 0, 1 ]
];
console.log('Original: ', vertices);
// (3) Transform the vertices to be relative to transformed parent (the element with
// the CSS transform on it).
var relVertices = [ [], [], [], [] ];
for (var i = 0; i < 4; ++i)
{
relVertices[i][0] = vertices[i][0] - parentOrigin[0];
relVertices[i][1] = vertices[i][1] - parentOrigin[1];
relVertices[i][2] = vertices[i][2];
relVertices[i][3] = vertices[i][3];
}
// (4) Get the CSS transform from the transformed parent
var tx = getTransform(txParent);
console.log('Transform: ', tx);
// (5) Get the CSS transform origin from the transformed parent - default is '50% 50%'
var txOrigin = getTransformOrigin(txParent);
console.log('Transform Origin: ', txOrigin);
// (6) Compute the full transform that is applied to the transformed parent (-origin * tx * origin)
var fullTx = computeTransformMatrix(tx, txOrigin);
console.log('Full Transform: ', fullTx);
// (7) Transform the vertices from the target element's bounding box by the full transform
var txVertices = [ ];
for (var i = 0; i < 4; ++i)
{
txVertices[i] = transformVertex(fullTx, relVertices[i]);
}
console.log('Transformed: ', txVertices);
// (8) Perform the homogeneous divide to apply perspective to the points (divide x,y,z by the w component).
var projectedVertices = [ ];
for (var i = 0; i < 4; ++i)
{
projectedVertices[i] = projectVertex(txVertices[i]);
}
console.log('Projected: ', projectedVertices);
// (9) After the transformed vertices have been computed, transform them back into the coordinate
// system of the offsetParent.
var finalVertices = [ [], [], [], [] ];
for (var i = 0; i < 4; ++i)
{
finalVertices[i][0] = projectedVertices[i][0] + parentOrigin[0];
finalVertices[i][1] = projectedVertices[i][1] + parentOrigin[1];
finalVertices[i][2] = projectedVertices[i][2];
finalVertices[i][3] = projectedVertices[i][3];
}
// (10) And then add the vertex elements in the 'offsetParent' coordinate system (in this case again
// it is <body>).
for (var i = 0; i < 4; ++i)
{
$("<div></div>").addClass("vertex")
.css('position', 'absolute')
.css('left', finalVertices[i][0])
.css('top', finalVertices[i][1])
.appendTo('body');
}
});
function printMatrix(mat)
{
var str = '';
for (var i = 0; i < 4; ++i)
{
for (var j = 0; j < 4; ++j)
{
str += (' ' + mat[i][j]);
}
str += '\r\n';
}
console.log(str);
}
function getTransform(ele)
{
var st = window.getComputedStyle(ele, null);
var tr = st.getPropertyValue("-webkit-transform") ||
st.getPropertyValue("-moz-transform") ||
st.getPropertyValue("-ms-transform") ||
st.getPropertyValue("-o-transform") ||
st.getPropertyValue("transform");
var values = tr.split('(')[1],
values = values.split(')')[0],
values = values.split(',');
var mat = [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ];
if (values.length === 16)
{
for (var i = 0; i < 4; ++i)
{
for (var j = 0; j < 4; ++j)
{
mat[j][i] = +values[i * 4 + j];
}
}
}
else
{
for (var i = 0; i < 3; ++i)
{
for (var j = 0; j < 2; ++j)
{
mat[j][i] = +values[i * 2 + j];
}
}
}
return mat;
}
function getTransformOrigin(ele)
{
var st = window.getComputedStyle(ele, null);
var tr = st.getPropertyValue("-webkit-transform-origin") ||
st.getPropertyValue("-moz-transform-origin") ||
st.getPropertyValue("-ms-transform-origin") ||
st.getPropertyValue("-o-transform-origin") ||
st.getPropertyValue("transform-origin");
var values = tr.split(' ');
var out = [ 0, 0, 0, 1 ];
for (var i = 0; i < values.length; ++i)
{
out[i] = parseInt(values[i]);
}
return out;
}
function createTranslateMatrix(x, y, z)
{
var out =
[
[1, 0, 0, x],
[0, 1, 0, y],
[0, 0, 1, z],
[0, 0, 0, 1]
];
return out;
}
function multiply(pre, post)
{
var out = [ [], [], [], [] ];
for (var i = 0; i < 4; ++i)
{
for (var j = 0; j < 4; ++j)
{
var sum = 0;
for (var k = 0; k < 4; ++k)
{
sum += (pre[k][i] * post[j][k]);
}
out[j][i] = sum;
}
}
return out;
}
function computeTransformMatrix(tx, origin)
{
var out;
var preMul = createTranslateMatrix(-origin[0], -origin[1], -origin[2]);
var postMul = createTranslateMatrix(origin[0], origin[1], origin[2]);
var temp1 = multiply(preMul, tx);
out = multiply(temp1, postMul);
return out;
}
function transformVertex(mat, vert)
{
var out = [ ];
for (var i = 0; i < 4; ++i)
{
var sum = 0;
for (var j = 0; j < 4; ++j)
{
sum += +mat[i][j] * vert[j];
}
out[i] = sum;
}
return out;
}
function projectVertex(vert)
{
var out = [ ];
for (var i = 0; i < 4; ++i)
{
out[i] = vert[i] / vert[3];
}
return out;
}
注意:接受的答案與跨瀏覽器不兼容。 這與瀏覽器計算偏移量屬性的愚蠢方式有關。 我更改了上面的答案以使用
var rect=this.getBoundingClientRect()
並且結果更加兼容跨瀏覽器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.