通过 JavaScript 计算旋转元素的边界框的 X、Y、高度和宽度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10392658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calculate the bounding box's X, Y, Height and Width of a rotated element via JavaScript
提问by Campbeln
Basically I'm asking this question for JavaScript: Calculate Bounding box coordinates from a rotated rectangle
基本上我是为 JavaScript 提出这个问题:从旋转的矩形计算边界框坐标
In this case:
在这种情况下:
- iX = Width of rotated (blue) HTML element
- iY = Height of rotated (blue) HTML element
- bx = Width of Bounding Box (red)
- by = Height of Bounding Box (red)
- x = X coord of Bounding Box (red)
- y = Y coord of Bounding Box (red)
- iAngle/t = Angle of rotation of HTML element (blue; not shown but used in code below), FYI: It's 37 degrees in this example (not that it matters for the example)
- iX = 旋转(蓝色)HTML 元素的宽度
- iY = 旋转(蓝色)HTML 元素的高度
- bx = 边界框的宽度(红色)
- by = 边界框的高度(红色)
- x = 边界框的 X 坐标(红色)
- y = 边界框的 Y 坐标(红色)
- iAngle/t = HTML 元素的旋转角度(蓝色;未显示但在下面的代码中使用),仅供参考:在此示例中为 37 度(对于示例而言并不重要)
How does one calculate the X, Y, Height and Width of a bounding box (all the red numbers) surrounding a rotated HTML element (given its width, height, and Angle of rotation) via JavaScript? A sticky bit to this will be getting the rotated HTML element (blue box)'s original X/Y coords to use as an offset somehow (this is not represented in the code below). This may well have to look at CSS3's transform-originto determine the center point.
如何通过 JavaScript 计算围绕旋转 HTML 元素(给定其宽度、高度和旋转角度)的边界框(所有红色数字)的 X、Y、高度和宽度?对此的一个棘手问题是将旋转的 HTML 元素(蓝色框)的原始 X/Y 坐标用作以某种方式的偏移量(这在下面的代码中没有表示)。这很可能得看CSS3的transform-origin来确定中心点。
I've got a partial solution, but the calculation of the X/Y coords is not functioning properly...
我有一个部分解决方案,但 X/Y 坐标的计算无法正常运行......
var boundingBox = function (iX, iY, iAngle) {
var x, y, bx, by, t;
//# Allow for negetive iAngle's that rotate counter clockwise while always ensuring iAngle's < 360
t = ((iAngle < 0 ? 360 - iAngle : iAngle) % 360);
//# Calculate the width (bx) and height (by) of the .boundingBox
//# NOTE: See https://stackoverflow.com/questions/3231176/how-to-get-size-of-a-rotated-rectangle
bx = (iX * Math.sin(iAngle) + iY * Math.cos(iAngle));
by = (iX * Math.cos(iAngle) + iY * Math.sin(iAngle));
//# This part is wrong, as it's re-calculating the iX/iY of the rotated element (blue)
//# we want the x/y of the bounding box (red)
//# NOTE: See https://stackoverflow.com/questions/9971230/calculate-rotated-rectangle-size-from-known-bounding-box-coordinates
x = (1 / (Math.pow(Math.cos(t), 2) - Math.pow(Math.sin(t), 2))) * (bx * Math.cos(t) - by * Math.sin(t));
y = (1 / (Math.pow(Math.cos(t), 2) - Math.pow(Math.sin(t), 2))) * (-bx * Math.sin(t) + by * Math.cos(t));
//# Return an object to the caller representing the x/y and width/height of the calculated .boundingBox
return {
x: parseInt(x), width: parseInt(bx),
y: parseInt(y), height: parseInt(by)
}
};
I feel like I am so close, and yet so far...
我觉得我很近,但又很远……
Many thanks for any help you can provide!
非常感谢您提供的任何帮助!
TO HELP THE NON-JAVASCRIPTERS...
帮助非 JAVASCRIPTER...
Once the HTML element is rotated, the browser returns a "matrix transform" or "rotation matrix" which seems to be this: rotate(Xdeg) = matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0);
See this page for more info.
一旦 HTML 元素被旋转,浏览器就会返回一个“矩阵变换”或“旋转矩阵”,这似乎是这样的:rotate(Xdeg) = matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0);
有关更多信息,请参阅此页面。
I have a feeling this will enlighten us on how to get the X,Y of the bounding box (red) based solely on the Width, Height and Angle of the rotated element (blue).
我有一种感觉,这将启发我们如何仅根据旋转元素(蓝色)的宽度、高度和角度来获得边界框(红色)的 X、Y。
New Info
新信息
Humm... interesting...
嗯……有意思……
Each browser seems to handle the rotation differently from an X/Y perspective! FF ignores it completely, IE & Opera draw the bounding box (but its properties are not exposed, ie: bx & by) and Chrome & Safari rotate the rectangle! All are properly reporting the X/Y except FF. So... the X/Y issue seems to exist for FF only! How very odd!
从 X/Y 角度来看,每个浏览器似乎都以不同的方式处理旋转!FF 完全忽略它,IE & Opera 绘制边界框(但它的属性没有暴露,即:bx & by),Chrome & Safari 旋转矩形!除 FF 外,所有人都正确报告了 X/Y。所以...... X/Y 问题似乎只存在于 FF 中!多么奇怪!
Also of note, it seems that $(document).ready(function () {...});
fires too early for the rotated X/Y to be recognized (which was part of my original problem!). I am rotating the elements directly before the X/Y interrogation calls in $(document).ready(function () {...});
but they don't seem to update until some time after(!?).
另外值得注意的是,$(document).ready(function () {...});
对于旋转的 X/Y 来说,它似乎触发得太早了(这是我最初的问题的一部分!)。我在 X/Y 询问调用之前直接旋转元素,$(document).ready(function () {...});
但它们似乎直到一段时间后才更新(!?)。
When I get a little more time, I will toss up a jFiddle with the example, but I'm using a modified form of "jquery-css-transform.js" so I have a tiny bit of tinkering before the jFiddle...
当我有更多时间时,我会在示例中折腾一个 jFiddle,但我使用的是“jquery-css-transform.js”的修改形式,所以在 jFiddle 之前我有一点点修补......
So... what's up, FireFox? That ain't cool, man!
所以……怎么了,火狐?这不酷,伙计!
The Plot Thickens...
情节变厚了...
Well, FF12 seems to fix the issue with FF11, and now acts like IE and Opera. But now I am back to square one with the X/Y, but at least I think I know why now...
好吧,FF12 似乎解决了 FF11 的问题,现在就像 IE 和 Opera 一样。但现在我又回到了 X/Y 的原点,但至少我想我现在知道为什么了......
It seems that even though the X/Y is being reported correctly by the browsers for the rotated object, a "ghost" X/Y still exists on the un-rotated version. It seems as though this is the order of operations:
似乎即使浏览器正确报告了旋转对象的 X/Y,但未旋转版本上仍然存在“幽灵”X/Y。似乎这是操作顺序:
- Starting with an un-rotated element at an X,Y of 20,20
- Rotate said element, resulting in the reporting of X,Y as 15,35
- Move said element via JavaScript/CSS to X,Y 10,10
- Browser logically un-rotates element back to 20,20, moves to 10,10 then re-rotates, resulting in an X,Y of 5,25
- 从 X,Y 为 20,20 的未旋转元素开始
- 旋转所述元素,导致 X,Y 报告为 15,35
- 通过 JavaScript/CSS 将所述元素移动到 X,Y 10,10
- 浏览器逻辑上将元素取消旋转回 20,20,移动到 10,10 然后重新旋转,导致 X,Y 为 5,25
So... I want the element to end up at 10,10 post rotation, but thanks to the fact that the element is (seemingly) re-rotated post move, the resulting X,Y differs from the set X,Y.
所以......我希望元素在旋转后的 10,10 处结束,但由于元素(似乎)在移动后重新旋转,结果 X,Y 与集合 X,Y 不同。
This is my problem! So what I really need is a function to take the desired destination coords (10,10), and work backwards from there to get the starting X,Y coords that will result in the element being rotated into 10,10. At least I know what my problem is now, as thanks to the inner workings of the browsers, it seems with a rotated element 10=5!
这是我的问题!所以我真正需要的是一个函数来获取所需的目标坐标 (10,10),然后从那里向后工作以获得起始 X,Y 坐标,这将导致元素旋转到 10,10。至少我现在知道我的问题是什么,由于浏览器的内部工作原理,它似乎带有旋转元素 10=5!
回答by óscar Palacios
I know this is a bit late, but I've written a fiddle for exactly this problem, on an HTML5 canvas:
我知道这有点晚了,但我已经在 HTML5 画布上为这个问题写了一个小提琴:
http://jsfiddle.net/oscarpalacious/ZdQKg/
http://jsfiddle.net/oscarpalacious/ZdQKg/
I hope somebody finds it useful!
我希望有人觉得它有用!
I'm actually not calculating your x,y for the upper left corner of the container. It's calculated as a result of the offset (code from the fiddle example):
我实际上不是在计算容器左上角的 x,y。它是根据偏移量计算的(来自小提琴示例的代码):
this.w = Math.sin(this.angulo) * rotador.h + Math.cos(this.angulo) * rotador.w;
this.h = Math.sin(this.angulo) * rotador.w + Math.cos(this.angulo) * rotador.h;
// The offset on a canvas for the upper left corner (x, y) is
// given by the first two parameters for the rect() method:
contexto.rect(-(this.w/2), -(this.h/2), this.w, this.h);
Cheers
干杯
回答by Diego ZoracKy
Have you tried using getBoundingClientRect()?
您是否尝试过使用getBoundingClientRect()?
This method returns an object with current values of "bottom, height, left, right, top, width"considering rotations
考虑旋转,此方法返回具有“底部、高度、左侧、右侧、顶部、宽度”当前值的对象
回答by Ignacio Vazquez-Abrams
Turn the four corners into vectors from the center, rotate them, and get the new min/max width/height from them.
将四个角从中心变成矢量,旋转它们,并从中获得新的最小/最大宽度/高度。
EDIT:
编辑:
I see where you're having problems now. You're doing the calculations using the entire side when you need to be doing them with the offsets from the center of rotation. Yes, this results in fourrotated points (which, strangely enough, is exactly as many points as you started with). Between them there will be one minimum X, one maximum X, one minimum Y, and one maximum Y. Those are your bounds.
我知道你现在哪里有问题。当您需要使用距旋转中心的偏移量进行计算时,您正在使用整个边进行计算。是的,这会导致四个旋转点(奇怪的是,这与您开始时的点数一样多)。在它们之间将有一个最小的 X、一个最大的 X、一个最小的 Y 和一个最大的 Y。这些就是你的界限。
回答by Ed Kolosovsky
My gistcan help you
我的要点可以帮助你
Bounding box of a polygon (rectangle, triangle, etc.):
多边形的边界框(矩形、三角形等):
Live demo https://jsfiddle.net/Kolosovsky/tdqv6pk2/
现场演示https://jsfiddle.net/Kolosovsky/tdqv6pk2/
let points = [
{ x: 125, y: 50 },
{ x: 250, y: 65 },
{ x: 300, y: 125 },
{ x: 175, y: 175 },
{ x: 100, y: 125 },
];
let minX = Math.min(...points.map(point => point.x));
let minY = Math.min(...points.map(point => point.y));
let maxX = Math.max(...points.map(point => point.x));
let maxY = Math.max(...points.map(point => point.y));
let pivot = {
x: maxX - ((maxX - minX) / 2),
y: maxY - ((maxY - minY) / 2)
};
let degrees = 90;
let radians = degrees * (Math.PI / 180);
let cos = Math.cos(radians);
let sin = Math.sin(radians);
function rotatePoint(pivot, point, cos, sin) {
return {
x: (cos * (point.x - pivot.x)) - (sin * (point.y - pivot.y)) + pivot.x,
y: (sin * (point.x - pivot.x)) + (cos * (point.y - pivot.y)) + pivot.y
};
}
let boundingBox = {
x1: Number.POSITIVE_INFINITY,
y1: Number.POSITIVE_INFINITY,
x2: Number.NEGATIVE_INFINITY,
y2: Number.NEGATIVE_INFINITY,
};
points.forEach((point) => {
let rotatedPoint = rotatePoint(pivot, point, cos, sin);
boundingBox.x1 = Math.min(boundingBox.x1, rotatedPoint.x);
boundingBox.y1 = Math.min(boundingBox.y1, rotatedPoint.y);
boundingBox.x2 = Math.max(boundingBox.x2, rotatedPoint.x);
boundingBox.y2 = Math.max(boundingBox.y2, rotatedPoint.y);
});
Bounding box of an ellipse:
椭圆的边界框:
Live demo https://jsfiddle.net/Kolosovsky/sLc7ynd1/
现场演示https://jsfiddle.net/Kolosovsky/sLc7ynd1/
let centerX = 350;
let centerY = 100;
let radiusX = 100;
let radiusY = 50;
let degrees = 200;
let radians = degrees * (Math.PI / 180);
let radians90 = radians + Math.PI / 2;
let ux = radiusX * Math.cos(radians);
let uy = radiusX * Math.sin(radians);
let vx = radiusY * Math.cos(radians90);
let vy = radiusY * Math.sin(radians90);
let width = Math.sqrt(ux * ux + vx * vx) * 2;
let height = Math.sqrt(uy * uy + vy * vy) * 2;
let x = centerX - (width / 2);
let y = centerY - (height / 2);