使用javascript获取顶点角落的CSS 2d和3d矩阵之间存在差异

时间:2016-05-09 23:28:31

标签: javascript css matrix transform css-transforms

尝试动态获取任意变换元素的顶点角。将各种解决方案混合在一起产生的结果在所有变换都是3d时都能很好地工作。见.. https://jsfiddle.net/xux8h8h0/13/

但是当同一继承链中存在2d和3d变换时不起作用。

$ SPACE_TAB="   "; sed -ne '/^SUBDIRS/,/^['"$SPACE_TAB"']*$/p' test.in
SUBDIRS = \
    text1 \
    text2 \
#  commented text
   text3 \
       text4 \
$(".target").on('click', function() {

  //remove vertices from last click
  $(".vertex").remove();
  scrollpos=getScroll();
  //store nested transforms
  var transforms = [];
  
  //walk up the DOM and get all transforms effecting this element
  var p = this;
  while (p && p.nodeType==1) {
    var computedStyle = getComputedStyle(p);
    //parse a 4x4 matrix from the matrix string
    var t = parseTransformMatrix(computedStyle.transform);
    var css=computedStyle.transform;
    //if there was a transform applied,let's remember it
    if (t) {
    	// get the transform origin
      //Set the transform to NOE since we'll need to get the child elements un transformed rectangle at the end
     var origin=computedStyle.transformOrigin;
     p.style.transform = 'none';
      //add an object to the transforms array holding useful info
      transforms.unshift({
        matrix: t,
        element: p,
        origin:origin,
        css: css
      })
    }
    p=p.parentNode;
  }
  //ALL applied transforms have been undone. Let's get the untransformed rectangle of the element
  var box = this.getBoundingClientRect();

var i = 0;
  while (i < transforms.length) {
    var origin = parseTransformOrigin(transforms[i].origin);
    var bbox=transforms[i].element.getBoundingClientRect();
    transforms[i].origin=origin;
    transforms[i].origin[0]+= bbox.left;
    transforms[i].origin[1]+=bbox.top;
    i++;
  }
  

 i = 0;
  while (i < transforms.length) {
    transforms[i].element.style.transform = transforms[i].css;
    i++;
  }

  //var points=getBoxPoints(box);
  //
  var points=[
  	[box.left,box.top,0,1],
    [box.right,box.top,0,1],
    [box.right,box.bottom,0,1],
    [box.left,box.bottom,0,1]
  ];
  for(var k=0;k<points.length;k++){
  var point=points[k];
  var prev=[];
  i = 0;
  while (i < transforms.length) {
    var org=transforms[i].origin;
        
    prev.push(transforms[i]);
    var mat=computeTransformMatrix(transforms[i].matrix.matrix,org);
    var tp=transformVertex(mat,point);
    var pv=projectVertex(tp);
    point[0]=pv[0];
    point[1]=pv[1];
    var m=i;

    var scrollpos=getScroll();
  
    i++;
  }
  
  
      
  var vertex = document.createElement('div');
  vertex.setAttribute('class','vertex');
  vertex.style.left = (point[0]+scrollpos[0])+ "px";
  vertex.style.top = (point[1]+scrollpos[1])+"px";
  vertex.style.zIndex=99;
  document.body.appendChild(vertex);
  }
 
  
});

function parseTransformMatrix(computedStyle) {
  var style = computedStyle;

  if (style == 'none') {
    return false;
  }
  var matrix = style.split('(')[1].split(')')[0].split(',');
  var fullMatrix = new Matrix(4, 4);

  if (matrix.length<16) {
    //2d matrix
    fullMatrix.matrix[0][0] = parseFloat(matrix[0]);
    fullMatrix.matrix[1][0] = parseFloat(matrix[1]);
    
    //
    fullMatrix.matrix[0][1] = parseFloat(matrix[2]);
    fullMatrix.matrix[1][1] = parseFloat(matrix[3]);
    
    //
    fullMatrix.matrix[0][3] = parseFloat(matrix[4]);
    fullMatrix.matrix[1][3] = parseFloat(matrix[5]);
  
    
  }
  else{
  	//column 1
  	fullMatrix.matrix[0][0] = parseFloat(matrix[0]);
    fullMatrix.matrix[1][0] = parseFloat(matrix[1]);
    fullMatrix.matrix[2][0] = parseFloat(matrix[2]);
    fullMatrix.matrix[3][0] = parseFloat(matrix[3]);
    //column 2
    fullMatrix.matrix[0][1] = parseFloat(matrix[4]);
    fullMatrix.matrix[1][1] = parseFloat(matrix[5]);
    fullMatrix.matrix[2][1] = parseFloat(matrix[6]);
    fullMatrix.matrix[3][1] = parseFloat(matrix[7]);
    //column 3
    fullMatrix.matrix[0][2] = parseFloat(matrix[8]);
    fullMatrix.matrix[1][2] = parseFloat(matrix[9]);
    fullMatrix.matrix[2][2] = parseFloat(matrix[10]);
    fullMatrix.matrix[3][2] = parseFloat(matrix[11]);
    //column 4
    fullMatrix.matrix[0][3] = parseFloat(matrix[12]);
    fullMatrix.matrix[1][3] = parseFloat(matrix[13]);
    fullMatrix.matrix[2][3] = parseFloat(matrix[14]);
    fullMatrix.matrix[3][3] = parseFloat(matrix[15]);
  
  }
  return fullMatrix;
}

function parseTransformOrigin(style) {
  var origin = style.split(' ');


    var out = [ 0, 0, 0, 1 ];
    for (var i = 0; i < origin.length; ++i)
    {
        out[i] = parseFloat(origin[i].trim());
    }    
    
 return out;
}

function Matrix(cols, rows) {
  this.matrix = [];
  var i = 0;
  while (i < rows) {
    var j = 0;
   this.matrix.push([]);
   
    while (j < cols) {
      var val =0;
      if(i==j){val=1}
      this.matrix[i].push(val);
      j++;
    }
    i++;
  }
  
}

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;
}
function getScroll(){
 if(window.pageYOffset!= undefined){
  return [pageXOffset, pageYOffset];
 }
 else{
  var sx, sy, d= document, r= d.documentElement, b= d.body;
  sx= r.scrollLeft || b.scrollLeft || 0;
  sy= r.scrollTop || b.scrollTop || 0;
  return [sx, sy];
 }
}
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;
}
html,
body {
  height: 100%;
  background-color: #ddd;
  padding: 55px;
  margin:0px;
}

/* 2d transform in chain*/
#nested {
  
  transform: translate(20px) rotate(-10deg);
  //transform: translate(20px) rotate(-10deg);
}
/* 3d transform in chain*/
#transformed {
  transform: perspective(600px) translateX(40px) rotateY(40deg) rotateX(40deg);
  //transform: rotate(90deg);
  width: 400px;
  height: 400px;
  background-color: #dd0000;
  border: 2px solid black;
}

.target {
  width: 80px;
  height: 80px;
  background-color: #0000dd;
  border: 2px solid white;
}

.vertex {
  position: absolute;
  border: 3px solid black;
  border-radius: 5px;
  background-color: black;
  width:1px;
  height:1px;
}

请参阅.. https://jsfiddle.net/wsf4rv54/1/

这是为什么?第一个链接中的最后一个蓝色方块(所有三维变换)透视图似乎逐渐使顶点元素错过了标记,我也无法弄明白。

1 个答案:

答案 0 :(得分:0)

虽然这不能解决您的问题,但它可能会指向正确的方向......

在第二个示例中,您在第一个rotate(-10deg)中使用了rotateX(-10deg)。在css的3d空间中rotate等于rotateZ,而不是rotateX