svg<g>个元素的BBox计算

BBox calculation of svg <g> elements

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

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

我一直觉得,对于组来说,这意味着它基本上是所有 children 的边界框的并集​​。

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

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

元素的边界框如下:

我的期望是,所有框都是相同的,但如您所见,外框不是内部元素的并集(在那种情况下它等于#inner 的 bbox)。相反,它考虑了内部元素的转换。

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

非常感谢 link 指出规格的正确部分。

getBBox返回的边界框是element's transformed coordinate system

中的框

Returns the tight bounding box in current user space (i.e., after application of the ‘transform’ attribute, if any) on the geometry of all contained graphics elements, exclusive of stroking, clipping, masking and filter effects)...

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

getBoundingClientRect 然而在全局坐标系中运行。

在此演示中,红色多边形代表 #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>