Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transform: calculating the new top and left of the transformed element #43

Closed
hlubovac opened this issue Dec 26, 2012 · 3 comments
Closed

Comments

@hlubovac
Copy link

Maybe I'm missing something, but I think your calculation involving matrices seems to be too complex - and it visibly doesn't [always] provide good results.

It is pretty obvious that the resulting element is wrapped in imaginary (invisible) shape that is always a square, which size can be easily calculated using Pythagorean theorem, and which offset can also be easily calculated (using the fact that its top-left corner is at the same coordinates as the top-left corner of original element and the fact that they need to be centered relative to each other). I came up with this, which gives me visibly correct results:

// calculate offset for IE7 and IE8
var squareSideLength = Math.sqrt(Math.pow(elementWidth, 2) / 2) + Math.sqrt(Math.pow(elementHeight, 2) / 2);
var offsetLeft = -1 * parseInt((squareSideLength - elementWidth) / 2, 10);
var offsetTop = -1 * parseInt((squareSideLength - elementHeight) / 2, 10);

I ended up using your example for calculating args for Matrix, and that code above to calculate offset.

Thank you for sharing. You saved me a lot of time.

@hlubovac
Copy link
Author

What I said is wrong: I made that conclusion incorrectly based on one special test case (angle 45). However, I would think dimensions of the transformed rectangle can be calculated using trigonometry (sin A = b / c; cos A = a / c). Finally, since location (x, y) of the transformed rectangle is known (same as x and y of the original element), and the rule of how other browsers position it (centered relative to the original element), then it should be relatively easy to figure out the unknown offset.

@hlubovac
Copy link
Author

I came up with this below. It seems accurate to me. I tested with images of different sizes and variety of angles. This is only a part of the routine I'm working on that relates to my comment above.

I ended up using the Matrix function for IE9 also, because I want to flip images that are rotated, and IE's "filter: FlipH/FlipV" in conjunction with Matrix filter produced black background in corners of transformed image, which I didn't like. So, I'm using Matrix for all IE's for both rotating and flipping. That part isn't showing here, but I wanted to mention how this works for IE9, as well as for IE8 and IE7.

I hope I'm not off-topic, as - based on the example (https://github.com/heygrady/transform/wiki/correcting-transform-origin-and-translate-in-ie) - I understood that to calculate the offset that I was looking for it was suggested to use another library (Sylvester), then some really complex code involving matrices, and then the usage of word "approximate" (related to resulting offset) scared me a little, and finally when I tried I also saw visible errors in certain scenarios. I'm a little bit rusty in trigonometry, but I think what I have below is accurate. Perhaps some of the cases that I treated separately can be combined, but ultimately the result would be the same.

var rotationAngle; // degrees; 0 <= rotationAngle <= 360

var elementWidth, elementHeight; // pixel values; size of element before rotating

var transformedWidth, transformedHeight; // transient values [pixel]

if (rotationAngle === 0 || rotationAngle === 180)
{
    transformedWidth = elementWidth;
    transformedHeight = elementHeight;
}
else if (rotationAngle === 90 || rotationAngle === 270)
{
    transformedWidth = elementHeight;
    transformedHeight = elementWidth;
}
else if (rotationAngle < 90)
{
    var rad = rotationAngle * Math.PI / 180;
    transformedWidth = elementHeight * Math.sin(rad) + elementWidth * Math.cos(rad);
    transformedHeight = elementWidth * Math.sin(rad) + elementHeight * Math.cos(rad);
}
else if (rotationAngle < 180)
{
    var rad = (rotationAngle - 90) * Math.PI / 180;
    transformedWidth = elementWidth * Math.sin(rad) + elementHeight * Math.cos(rad);
    transformedHeight = elementHeight * Math.sin(rad) + elementWidth * Math.cos(rad);
}
else if (rotationAngle < 270)
{
    var rad = (rotationAngle - 180) * Math.PI / 180;
    transformedWidth = elementHeight * Math.sin(rad) + elementWidth * Math.cos(rad);
    transformedHeight = elementWidth * Math.sin(rad) + elementHeight * Math.cos(rad);
}
else if (rotationAngle < 360)
{
    var rad = (rotationAngle - 270) * Math.PI / 180;
    transformedWidth = elementWidth * Math.sin(rad) + elementHeight * Math.cos(rad);
    transformedHeight = elementHeight * Math.sin(rad) + elementWidth * Math.cos(rad);
}

// Element's rectangle before rotation and its transformed element's rectangle 
// after rotation need to be centered relative to each other. These offset values 
// are how much transformed element needs to be shifted left and up (IE only). 
var offsetLeft = -1 * parseInt((transformedWidth - elementWidth) / 2, 10);
var offsetTop = -1 * parseInt((transformedHeight - elementHeight) / 2, 10);

@hlubovac
Copy link
Author

I'm sure you know that IE7 and IE8 are reporting the transformed image size to be the same as the "invisible" transformed-element's size, which is the contrary of what IE9 (even with Matrix filter used) and other browsers are reporting (which is the original image size).

I'm using jQuery. I discovered that - after rotation using Matrix filter - jQuery reports the same as IE7/8. However, native JS reports original-image's size. I stepped through jQuery's width/height functions, but I got lost so I gave up. Anyway, DOMElement.width and DOMElement.height can be used to get the original size after rotation.

@hlubovac hlubovac closed this as completed Jan 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant