1

我刚刚遇到了一个奇怪的弹跳盒计算案例,似乎我还没有掌握全部真相。

首先,边界框被定义为最紧密的框,可以包含未转换的元素。

我一直有这样的印象,对于团体来说,这意味着它基本上得到了所有孩子的边界框的联合。

然而,今天我遇到了这个:

<g id="outer">
  <g id="inner" transform="translate(100, 100)">
    <rect x="0" y="0" width="100" height="100" />
  </g>
</g>

元素的边界框如下:

  • rect: x: 0, y: 0, w: 100, h: 100
  • #inner: x: 0, y: 0, w: 100, h: 100
  • #outer: x: 100, y: 100, w: 100, h: 100

我的期望是,所有的盒子都是一样的,但正如你所看到的,外框不是内部元素的联合(在这种情况下,它将等于#inner 的 bbox)。相反,它考虑了内部元素的转换。

那么,是否可以说一个组的bbox 是其孩子的TRANSFORMED bbox 的并集?或者更编程地说,所有getBoundingClientRect调用的联合(假设滚动为0,因为getCoundingClientRect忽略滚动)?

我真的很感激一个链接指向我规范的正确部分。

4

2 回答 2

5

getBBox 返回的边界框是元素变换后坐标系中的框

返回当前用户空间中的紧密边界框(即,在应用 'transform' 属性后,如果有的话)在所有包含的图形元素的几何图形上,不包括描边、剪切、遮罩和过滤效果)...

外部 SVG 元素具有不同的坐标系。即,<g>由于内部元素的变换,它放置原点的位置与内部元素不同。

但是,getBoundingClientRect 在全局坐标系中运行。

于 2018-12-14T08:42:15.990 回答
3

在此演示中,红色多边形代表#outer矩形旋转动画期间的 BBox。

const SVG_NS = 'http://www.w3.org/2000/svg';
let o = outer.getBBox()
let i = inner.getBBox()

let BBpoly = drawBBox(o); 



function drawBBox(bb){
  let p = [{x:bb.x,y:bb.y},
           {x:bb.x+bb.width,y:bb.y},
           {x:bb.x+bb.width,y:bb.y+bb.height},
           {x:bb.x,y:bb.y+bb.height}];
  let BBpoly = drawPolygon(p, BBoxes);
  return BBpoly;
}


function drawPolygon(p, parent) {
  let poly = document.createElementNS(SVG_NS, 'polygon');
  let ry = [];
  for (var i = 0; i < p.length; i++) {
    ry.push(String(p[i].x + ", " + p[i].y));
  }
  var points = ry.join(" ");
  poly.setAttributeNS(null, 'points', points);

  parent.appendChild(poly);
  return poly;
}


function updatePolygon(p,poly){
  let ry = [];
  for (var i = 0; i < p.length; i++) {
    ry.push(String(p[i].x + ", " + p[i].y));
  }
  var points = ry.join(" ");
  poly.setAttributeNS(null, 'points', points);
}

let a = 0;
function Frame(){
  requestAnimationFrame(Frame);
  inner.setAttributeNS(null,"transform", `rotate(${a}, 120,120)`)
  let bb = outer.getBBox()
  let p = [{x:bb.x,y:bb.y},
           {x:bb.x+bb.width,y:bb.y},
           {x:bb.x+bb.width,y:bb.y+bb.height},
           {x:bb.x,y:bb.y+bb.height}];
  updatePolygon(p,BBpoly);
  
  a++
}

Frame()
svg{border:1px solid; width:300px;}
polygon{fill:none; stroke:red; }
<svg viewBox="0 0 250 250">
  <g id="BBoxes"></g>
  <g id="outer">
  <g id="inner">
    <rect x="70" y="70" width="100" height="100"  />
  </g>
</g>
</svg>

于 2018-12-14T09:00:42.013 回答