Jquery计算旋转矩形的bouding框

时间:2017-09-26 09:10:54

标签: javascript jquery math geometry

我已经查看了其他一些有关此事的帖子,但仍然无法弄清楚为什么公式不起作用。

计算旋转矩形的边界框:

w' = sin(a)*h + cos(a)*w;
h' = sin(a)*w + cos(a)*h;

问题是我在w'h'完全不准确的情况下会出现奇怪的行为。



// calculate rotation angle of shape
function getRotationDegrees(obj) {
  var matrix = obj.css("-webkit-transform") ||
    obj.css("-moz-transform") ||
    obj.css("-ms-transform") ||
    obj.css("-o-transform") ||
    obj.css("transform");
  if (matrix !== 'none') {
    var values = matrix.split('(')[1].split(')')[0].split(',');
    var a = values[0];
    var b = values[1];
    var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
  } else {
    var angle = 0;
  }

  if (angle < 0) angle += 360;
  return angle;
}

var shape = $('.shape'),
  shapeLeft = shape.position().left,
  shapeTop = shape.position().top,
  shapeWidth = shape.width(),
  shapeHeight = shape.height(),
  angle = getRotationDegrees(shape),
  // formula below
  height = Math.abs(shapeWidth * Math.sin(angle)) + Math.abs(shapeHeight * Math.cos(angle)),
  width = Math.abs(shapeHeight * Math.sin(angle)) + Math.abs(shapeWidth * Math.cos(angle));

$('#g1').css('width', width);
$('#g2').css('height', height);
&#13;
.elements,
.element {
  position: absolute
}

#s2 {
  background: #333333;
  top: 60px;
  left: -25px;
  width: 300px;
  height: 100px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="layout" style="position:relative; margin-top:50px; margin-left:70px;">
  <div class="elements">
    <div id="g1" class="element" style="background:red;left:-35px;top:-10px;height:2px;"></div>
    <div id="g2" class="element" style="background:red;left:-35px;top:-10px;width:2px;"></div>
    
    <div id="s2" class="element shape" style="transform: rotate(8deg);"></div>
  </div>
</div>
&#13;
&#13;
&#13;

我做错了什么?

1 个答案:

答案 0 :(得分:1)

两个错误来源:

  1. (次要)角度的圆角。 (不知道你的意思是什么&#34;已经是一个数字&#34;)

  2. (主要)您直接在getRotationDegrees中使用Math.cos / sin的结果。这些函数需要弧度,即Math.atan2直接返回的结果。

  3. 下面的代码段添加了边界框的另外两条边,以及正确的位置偏移。我添加了一个滑块来更改旋转角度,以说明此代码是健壮的。

    &#13;
    &#13;
    function getMatrix(obj) {
       var matrix = obj.css("-webkit-transform") ||
                    obj.css("-moz-transform") ||
                    obj.css("-ms-transform") ||
                    obj.css("-o-transform") ||
                    obj.css("transform");
       return (matrix == 'none') ? null : matrix.split('(')[1].split(')')[0].split(',');
    }
    
    // calculate rotation angle of shape
    function getRotationRadians(matrix) {
       var angle = matrix ? Math.atan2(matrix[1], matrix[0]) : 0;
       if (angle < 0) angle += 2.0 * Math.PI;
       return angle;
    }
    
    // calculate translation
    function getTranslation(matrix) {
       return matrix ? [matrix[4], matrix[5]] : [0, 0];
    }
    
    // calculate bounding box
    function getBoundingBox(shape) {
       var shapeLeft = shape.position().left,
           shapeTop = shape.position().top,
           shapeWidth = shape.width(),
           shapeHeight = shape.height();
           
       var matrix = getMatrix(shape);
       
       var angle = getRotationRadians(matrix);
       var height = Math.abs(shapeWidth * Math.sin(angle)) + Math.abs(shapeHeight * Math.cos(angle));
       var width = Math.abs(shapeHeight * Math.sin(angle)) + Math.abs(shapeWidth * Math.cos(angle));
    
       var trans = getTranslation(matrix);
       var left = trans[0] - (width * 0.5);
       var top = trans[1] - (height * 0.5);
       
       return {'x': left, 'y': top, 'w': width, 'h': height};
    }
    
    formatBox($('.shape'));
    
    function formatBox(shape) {
       var box = getBoundingBox(shape);
         
       var offx = 124, offy = 109;
    
       var g1 = $('#g1'), g2 = $('#g2'), g3 = $('#g3'), g4 = $('#g4');
    
       g1.css('width', box.w);
       g2.css('height', box.h);
       g3.css('width', box.w);
       g4.css('height', box.h);
    
       g1.css('left', offx + box.x);
       g2.css('left', offx + box.x);
       g3.css('left', offx + box.x);
       g4.css('left', offx + box.x + box.w);
    
       g1.css('top', offy + box.y);
       g2.css('top', offy + box.y);
       g3.css('top', offy + box.y + box.h);
       g4.css('top', offy + box.y);
    }
        
    var angleInp = document.getElementById("angleInp");
    angleInp.addEventListener("change", function() {
       var shape = $('.shape');
       shape.css('transform', 'rotate(' + angleInp.value + 'deg)');
       formatBox(shape);
    }, false);
    &#13;
    .elements,
    .element {
      position: absolute
    }
    
    #s2 {
      background: #333333;
      top: 60px;
      left: -25px;
      width: 300px;
      height: 100px;
    }
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="slider">
       <input class="bar" type="range" id="angleInp" min="0" max="360" value="15" onchange="angleInp.value=value"/>
    </div>
    <div class="layout" style="position:relative; margin-top:50px; margin-left:70px;">
      <div class="elements">
        <div id="g1" class="element" style="background:red;left:0px;top:0px;height:2px;"></div>
        <div id="g2" class="element" style="background:red;left:0px;top:0px;width:2px;"></div>
        <div id="g3" class="element" style="background:red;left:0px;top:0px;height:2px;"></div>
        <div id="g4" class="element" style="background:red;left:0px;top:0px;width:2px;"></div>
        
        <div id="s2" class="element shape" style="transform: rotate(15deg);"></div>
      </div>
    </div>
    &#13;
    &#13;
    &#13;