GibboK
GibboK

Reputation: 73918

How to calculate bounding rectangles size for a DOM element on which CSS transform matrix is applied? Without using Element.getBoundingClientRect()

I have a DIV who has been transformed using a matrix.

I need to calculate some information for its bounding rectangles size.

Specifically I need found out: Width, Height, Rotation (deg from the matrix)

I cannot use Element.getBoundingClientRect()

I am manly interesting in a math solution, assuming that I have all the data needed to perform the rendering of div in advance (like: top, left position) any feedbacks is welcome.

In the example, the green box is a visual rappresentation of the dimension I need to found out.

#box {
  position: absolute;
  top: 100px;
  left: 100px;
  width: 200px;
  height: 200px;
  background-color: red;
  transform: matrix(0.707107, 0.707107, -0.707107, 0.707107, -0.707107, 34.6482);
}

#result {
  position: absolute;
  height: 282.8427734375px;
  left: 57.871490478515625px;
  top: 93.22679901123047px;
  width: 282.8428039550781px;
  border: 1px solid green;
}
<div id="box"></div>
<div id="result"></div>

Upvotes: 1

Views: 585

Answers (1)

gipouf
gipouf

Reputation: 1241

When you say "without DOM operations" I assume that you have all the data needed to perform the calculation by hand in advance. Specifically, you have the (left, top) coordinates and width/height dimensions of the pre-transformed rectangle, and you also have the details of each transformation that was applied to the rectangle, and in the correct order. In this case, I would first build four points as follows, which represents the pre-transformed rectangle:

  • p1 = (left, top)
  • p2 = (left + width, top)
  • p3 = (left, top + height)
  • p4 = (left + width, top + height)

Then I would apply the transformation chain to each of these four points, to get p1', p2', p3', p4'.

Then I would run over each p', and max/min the top/left coordinates of all of them:

  • max_top
  • min_top
  • max_left
  • min_left

Now, from that information I can derive that:

  • (min_left, min_top) will give us the top-left point of the bounding rect.
  • (max_left - min_left, max_top - min_top) will give us the dimensions of the bounding rect.

However, It would be easier if you could just query for the element's transformation matrix, and break its components into floats. Then use a JS math library (such as numericJS) to build a transformation matrix out of these components, and use it to transform your points.

Here is a snippet that can be used to extract a numericJS matrix out of an element's CSS transform property:

getTransformationMatrix: function (element) {
    var transform = element.css('transform');

    // Verify that the returned result is valid
    if (transform && transform !== "none" && transform !== "") {
        // The returned string from 'element.css('transform')' has the following template - 'matrix(a, c, b, d, tx, ty)'. We would like to extract the values of a, b, c and d,
        // in order to use them to construct a Matrix object which will represent the following matrix:
        //   a b tx
        // ( c d ty )
        //   0 0 1
        // For more information, please see https://developer.mozilla.org/en-US/docs/Web/CSS/transform
        var transformValues = transform.split('(')[1].split(')')[0].split(',');

        var a = parseFloat(transformValues[0]);
        var c = parseFloat(transformValues[1]);
        var b = parseFloat(transformValues[2]);
        var d = parseFloat(transformValues[3]);
        var tx = parseFloat(transformValues[4]);
        var ty = parseFloat(transformValues[5]);

        return [[a, b, tx], [c, d, ty], [0, 0, 1]];
    }

    // return the identity matrix if no transformation is set on the element.
    return new [[1, 0 ,0], [0, 1, 0], [0, 0, 1]];
}

You can now use it to transform a given point:

function getTransformedPoint(matrix, point) {
   return numeric.dot(matrix, [p.left, p.top, 1]);
}

var matrix = getTransformationMatrix(element);
transformedP1 = getTransformedPoint(matrix, p1);
transformedP2 = getTransformedPoint(matrix, p2);
transformedP3 = getTransformedPoint(matrix, p3);
transformedP4 = getTransformedPoint(matrix, p4);

Upvotes: 1

Related Questions