34

この SVG を考えると:

<svg xmlns="http://www.w3.org/2000/svg">
  <rect width="50" height="50"
        transform="translate(75,75) rotate(45) translate(-25,-25)" />
  <script>
    var bb = document.querySelector('rect').getBBox();
    console.log([bb.x,bb,y,bb.width,bb.height]);
  </script>
</svg>​

結果の出力は[0, 0, 50, 50]です。
望ましい結果は[39.645,39.645,70.711,70.711]です。

ビジュアル版: http://jsfiddle.net/2wpju/7/

親要素に関して要素の境界ボックスを計算する最も簡単で効率的な方法は何ですか?


以下は、これまでに思いついた最良の答えですが、2つの問題があります。

  1. より適切に処理できるようにするには、多くの作業が必要なようです。
  2. このデモで見られるように、回転した軸に沿ったバウンディング ボックスの軸に沿ったバウンディング ボックスは常にサイズが大きくなるため、必ずしも最小のバウンディング ボックスではありません (上の円に注意してください)。

 

// Calculate the bounding box of an element with respect to its parent element
function transformedBoundingBox(el){
  var bb  = el.getBBox(),
      svg = el.ownerSVGElement,
      m   = el.getTransformToElement(el.parentNode);

  // Create an array of all four points for the original bounding box
  var pts = [
    svg.createSVGPoint(), svg.createSVGPoint(),
    svg.createSVGPoint(), svg.createSVGPoint()
  ];
  pts[0].x=bb.x;          pts[0].y=bb.y;
  pts[1].x=bb.x+bb.width; pts[1].y=bb.y;
  pts[2].x=bb.x+bb.width; pts[2].y=bb.y+bb.height;
  pts[3].x=bb.x;          pts[3].y=bb.y+bb.height;

  // Transform each into the space of the parent,
  // and calculate the min/max points from that.    
  var xMin=Infinity,xMax=-Infinity,yMin=Infinity,yMax=-Infinity;
  pts.forEach(function(pt){
    pt = pt.matrixTransform(m);
    xMin = Math.min(xMin,pt.x);
    xMax = Math.max(xMax,pt.x);
    yMin = Math.min(yMin,pt.y);
    yMax = Math.max(yMax,pt.y);
  });

  // Update the bounding box with the new values
  bb.x = xMin; bb.width  = xMax-xMin;
  bb.y = yMin; bb.height = yMax-yMin;
  return bb;
}
4

6 に答える 6

4

使用する必要があるのは、次の単純な Javascript 関数だけです。

object.getBoundingClientRect();

以下でサポートされています。

Chrome  Firefox (Gecko)   Internet Explorer Opera   Safari
1.0           3.0 (1.9)   4.0               (Yes)   4.0

詳しくはこちらをご覧ください。リンク

于 2013-12-31T13:09:42.497 に答える
2

これは、回転した楕円を説明する答えです。変換メソッドは長方形に対しては問題なく機能しますが、楕円に対しては、オブジェクトを回転すると、オブジェクトよりもかなり大きなバウンディング ボックスが返されます。

組み込みの JavaScript 関数を使用するという単純な答えは、描画スペースに戻す必要があるため、あまり役に立ちません。

このコードは、楕円の傾きや縮尺を処理しません (ただし、他のオブジェクトは処理します)。しかし、http://nwlink.com/~geoffrey/svgBuildにある私のプログラムでは、まったく新しい楕円を描画することで、傾きと縮尺を処理するつもりです。スキューまたはスケールが適用された状態。

楕円の式は次のとおりです: 楕円の軸に沿った境界ボックスをどのように計算しますか? 助けてくれてありがとう。

el はノードではなく d3.js 要素です。

function toNumberIfNumeric(x) {
    var result = parseFloat(x);
    return isNaN(result) ? x : result;
}

function getAttrs(el, attributes) {
    var result = {};
    attributes.forEach(function (attr) {
        result[attr] = toNumberIfNumeric(el.attr(attr));
    });
    return result;
}    

function getTransformedBbox(el, referenceNode) {

    var node = el.node();

    switch (node.nodeName) {
        case "ellipse":

            var rotate = getTransform(el, "rotate");
            if (rotate.angle === 0) {
                return node.getBBox();
            }
            var attr = getAttrs(el, ["cx", "cy", "rx", "ry"]);
            var radians = rotate.angle / 180 * Math.PI;
            var radians90 = radians + Math.PI / 2;

            var ux = attr.rx * Math.cos(radians);
            var uy = attr.rx * Math.sin(radians);
            var vx = attr.ry * Math.cos(radians90);
            var vy = attr.ry * Math.sin(radians90);

            var halfWidth = Math.sqrt(ux * ux + vx * vx);
            var halfHeight = Math.sqrt(uy * uy + vy * vy);

            return {
                x: attr.cx - halfWidth,
                y: attr.cy - halfHeight,
                width: 2 * halfWidth,
                height: 2 * halfHeight
            };

        default:
            var bb = node.getBBox(),
                svg = node.ownerSVGElement,
                m = node.getTransformToElement(referenceNode);

            // Create an array of all four points for the original bounding box
            var pts = [
                svg.createSVGPoint(), svg.createSVGPoint(),
                svg.createSVGPoint(), svg.createSVGPoint()
            ];
            pts[0].x = bb.x;
            pts[0].y = bb.y;
            pts[1].x = bb.x + bb.width;
            pts[1].y = bb.y;
            pts[2].x = bb.x + bb.width;
            pts[2].y = bb.y + bb.height;
            pts[3].x = bb.x;
            pts[3].y = bb.y + bb.height;

            // Transform each into the space of the parent,
            // and calculate the min/max points from that.    
            var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity;
            pts.forEach(function (pt) {
                pt = pt.matrixTransform(m);
                xMin = Math.min(xMin, pt.x);
                xMax = Math.max(xMax, pt.x);
                yMin = Math.min(yMin, pt.y);
                yMax = Math.max(yMax, pt.y);
            });

            // Update the bounding box with the new values
            bb.x = xMin;
            bb.width = xMax - xMin;
            bb.y = yMin;
            bb.height = yMax - yMin;
            return bb;
    }
}
于 2016-12-03T17:18:09.583 に答える
2

SVG 1.1 SE では次のように定義されていますが、 getBBox() がオブジェクトの変換をバウンディング ボックスを直接定義するものと見なさない限り、またはそれまでは、これが現在の方法のようです。

SVGRect getBBox() ストローク、クリッピング、マスキング、およびフィルター効果を除く、含まれているすべてのグラフィック要素のジオメトリで、現在のユーザー空間 (つまり、「transform」属性があれば適用後) のタイト バウンディング ボックスを返します。getBBox は、要素がまだレンダリングされていない場合でも、メソッドが呼び出された時点で実際の境界ボックスを返さなければならないことに注意してください。

「現在のユーザー空間」をどのように定義するかがすべてだと思います

于 2014-10-02T19:51:48.817 に答える