web-dev-qa-db-ja.com

JavaScriptを使用して、回転した要素のバウンディングボックスのX、Y、高さ、幅を計算します

基本的に私はJavaScriptについてこの質問をしています: 回転した長方形から境界ボックスの座標を計算します

Diagram

この場合:

  • iX =回転した(青の)HTML要素の幅
  • iY =回転した(青の)HTML要素の高さ
  • bx =バウンディングボックスの幅(赤)
  • by =バウンディングボックスの高さ(赤)
  • x =バウンディングボックスのX座標(赤)
  • y =バウンディングボックスのY座標(赤)
  • iAngle/t = HTML要素の回転角(青;表示されていませんが、以下のコードで使用されています)、参考:この例では37度です(例では重要ではありません)

JavaScriptを使用して、回転したHTML要素(幅、高さ、回転角を指定)を囲む境界ボックス(すべての赤い数字)のX、Y、高さ、幅をどのように計算しますか?これにこだわるのは、回転したHTML要素(青いボックス)の元のX/Y座標を何らかの方法でオフセットとして使用することです(これは以下のコードでは表されていません)。これは、中心点を決定するために CSS3の変換-原点 を調べる必要があるかもしれません。

部分的な解決策がありますが、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)
    }
};
_

とても近くにいるような気がしますが、それでも今のところ...

あなたが提供できるどんな助けにも感謝します!

非JAVASCRIPTERSを助けるために...

HTML要素が回転すると、ブラウザは「行列変換」または「回転行列」を返します。これは次のようになります:rotate(Xdeg) = matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0);詳細についてはこのページを参照してください

回転した要素(青)の幅、高さ、角度のみに基づいて、バウンディングボックス(赤)のX、Yを取得する方法を教えてくれると思います。

新しい情報

うーん...おもしろい...

enter image description here

X/Yの観点からは、ブラウザごとに回転の処理が異なるようです。 FFはそれを完全に無視し、IE&Opera境界ボックスを描画します(ただし、そのプロパティは公開されません。つまり、bx&by)およびChrome&Safariは長方形を回転させます!FFを除いてすべてがX/Yを適切に報告しています。したがって... X/Yの問題はFFにのみ存在するようです!なんて奇妙なことでしょう!

また、$(document).ready(function () {...});の起動が早すぎて、回転したX/Yを認識できないようです(これは私の最初の問題の一部でした!)。 $(document).ready(function () {...});でX/Y問い合わせが呼び出される直前に要素を回転していますが、しばらくすると(!?)更新されないようです。

もう少し時間があれば、例を使ってjFiddleを投げますが、「jquery-css-transform.js」の変更された形式を使用しているので、jFiddleの前に少しいじくり回します...

それで...どうしたの、FireFox?かっこいいじゃない、男!

プロットが厚くなる...

さて、FF12はFF11の問題を修正しているようで、現在はIEとOperaのように動作します。しかし、X/Yで正方形に戻りましたが、少なくとも理由はわかっていると思います。今...

回転されたオブジェクトのX/Yがブラウザによって正しく報告されているにもかかわらず、回転されていないバージョンには「ゴースト」X/Yがまだ存在しているようです。これが操作の順序であるかのように見えます:

  • X、Yが20,20の回転していない要素から開始
  • 上記の要素を回転すると、X、Yが15,35としてレポートされます。
  • JavaScript/CSSを介して上記の要素をX、Y 10,10に移動します
  • ブラウザは要素を論理的に20,20に回転解除し、10,10に移動してから再回転します。その結果、X、Yは5,25になります。

だから...私は要素を回転後10,10で終わらせたいのですが、要素が(一見)移動後に再回転されるという事実のおかげで、結果のX、YはセットX、Yとは異なります。

これが私の問題です!したがって、本当に必要なのは、目的の宛先座標(10,10)を取得し、そこから逆方向に作業して、要素が10,10に回転する開始X、Y座標を取得する関数です。少なくとも、ブラウザの内部動作のおかげで、回転した要素10 = 5のように見えるので、現在の問題はわかっています。

24
Campbeln

これが少し遅れていることは知っていますが、HTML5キャンバスに、まさにこの問題のフィドルを書きました。

http://jsfiddle.net/oscarpalacious/ZdQKg/

誰かがそれが役に立つと思うことを願っています!

私は実際にはコンテナの左上隅の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);

乾杯

16
Óscar Palacios

getBoundingClientRect()を使用してみましたか?

このメソッドは、回転を考慮して、現在の値が "bottom、height、left、right、top、width"のオブジェクトを返します。

7
Diego ZoracKy

四隅を中心からベクトルに変えて回転させ、そこから新しい最小/最大幅/高さを取得します。

編集:

あなたが今どこで問題を抱えているのかわかります。計算を行う必要がある場合は、側面全体を使用して計算を行っています回転の中心からのオフセットを使用。はい、これによりfour回転したポイントになります(奇妙なことに、これは最初に開始したポイントとまったく同じ数です)。それらの間に、1つの最小X、1つの最大X、1つの最小Y、および1つの最大Yがあります。これらはあなたの限界です。

私の要点 あなたを助けることができます

ポリゴンのバウンディングボックス(長方形、三角形など):

ライブデモ 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);
});

楕円のバウンディングボックス:

ライブデモ 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);
0
Ed Kolosovsky