svg getBoundingClientRect()+变换:rotate()"以非常特定的方式在铬中被漏洞

发布于 2025-01-20 04:09:46 字数 4551 浏览 4 评论 0原文

getBoundingClientRect()在所有SVG元素上都可以正常工作,除非在Chrome中旋转元素时。

在下面我绘制了2条线,左侧的一条是对角线,右线逐渐启动,如黑线所示。绿色框是getBoundingClientRect()的视觉表示。然后,我将相同的转换旋转同时旋转,然后更新边界框的视觉框架。

从以下内容中可以看到,左边界框并不能表示实际的界限,但是,右边界框确实是。

问题是我需要该行的真实客户端界限,无论其方向是什么。这在Firefox中正常工作。有人知道当行具有变换旋转时,是否知道其他方法来获取或计算界限?

我在此处发布了此副本: getBoundingClientRect() )“在Chrome中被漏洞吗?。为了帮助有类似问题的人,但随后决定我实际上问社区。

Chrome:V100.0.4896.75

此错误现已在此处报告给Cromium Bugs委员会: https://bugs.chromium.org/p/chromium/issues/detail?id=1314959

更新:我添加了相同的2个静态线transform旋转的属性为40兆,而2 div表示“ getBoundingClientRect”。左框显然没有显示包含整个元素的最小矩形。

更新2 包括bbox blue的Visual>。 getBbox()在任何旋转转换之前,只需计算儿童相对于SVG元素本身的界限。 getBoundingClientRect确实正确计算了转换,但是正在使用bbox,它在此处具有自己的问题:

let l = [1,2,3,4,5,6].map(d => document.getElementById(`line${d}`)),
  vis = [1,2,3,4,5,6].map(d => document.createElement(`div${d}`)),
  bboxvis = [1,2,3,4,5,6].map(d => document.createElement(`div${d}`)),
  r = 0;

vis.map((element) => {
  document.body.appendChild(element)
  element.style.position = "absolute"
  element.style.border = "1px solid green"
  element.style.background = `#0FF0002e`
})
bboxvis.map((element) => {
  document.body.appendChild(element)
  element.style.position = "absolute"
  element.style.border = "1px solid blue"
  element.style.background = `#0000FF2e`
})

let updateBounds = (element, displayElement, bboxvisEl) => { 
  let rect = element.getBoundingClientRect(),
    svgBounds = element.parentElement.getBoundingClientRect(),
    bbox = element.getBBox(),
    d = document.documentElement;
  displayElement.style.top = rect.y+d.scrollTop+"px"
  displayElement.style.left = rect.x+d.scrollLeft+"px"
  displayElement.style.width = rect.width+"px"
  displayElement.style.height = rect.height+"px"
  bboxvisEl.style.top = bbox.y+svgBounds.y+d.scrollTop + "px"
  bboxvisEl.style.left = bbox.x+svgBounds.x+d.scrollLeft +"px"
  bboxvisEl.style.width = bbox.width+"px"
  bboxvisEl.style.height = bbox.height+"px"
}

[3,4,5].forEach(i => {
    updateBounds(l[i], vis[i], bboxvis[i]);
  bboxvis[i].style.transform = `rotate(40deg)`;
})

setInterval(() => { 
  [0,1,2].forEach(i => {
    l[i].setAttribute("transform", `rotate(${r} 80 80)`);
    bboxvis[i].style.transform = `rotate(${r}deg)`;
    updateBounds(l[i], vis[i], bboxvis[i]);
  })
  r++; 
  if(r===360) r=0;
}, 20)
.container {
  width:140px;
  height:140px;
  display:inline-block;
}
<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="40" y1="40" x2="120" y2="120" stroke="black" stroke-width="2"></line>
  <line x1="40" y1="40" x2="120" y2="120" id="line1" stroke="red" stroke-width="2"></line>
</svg>

<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="80" y1="30" x2="80" y2="130" stroke="black" stroke-width="2"></line>
  <line x1="80" y1="30" x2="80" y2="130" id="line2" stroke="red" stroke-width="2"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="60" y1="30" x2="100" y2="130" stroke="black" stroke-width="2"></line>
  <line x1="60" y1="30" x2="100" y2="130" id="line3" stroke="red" stroke-width="2"></line>
</svg>
<br/>

<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="40" y1="40" x2="120" y2="120" id="line4" stroke="red" stroke-width="2" transform="rotate(40 80 80)"></line>
</svg>

<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="80" y1="30" x2="80" y2="130" id="line5" stroke="red" stroke-width="2" transform="rotate(40 80 80)"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="60" y1="30" x2="100" y2="130" id="line6" stroke="red" stroke-width="2" transform="rotate(40 80 80)"></line>
</svg>

getBoundingClientRect() works fine on all SVG elements except in the circumstance when an element is rotated in Chrome.

Below I have drawn 2 lines, the one on the left is diagonal and the right line starts vertical, as represented by the black lines. The green box is a visual representation of the getBoundingClientRect(). I then apply the same transform rotate to both lines at the same time and then update the bounding box visual.

As you can see from the following, the left bounding box does not represent the actual bounds, however, the right one does.

The problem is I need the true client bounds of the line in whatever orientation it is. This works fine in Firefox. Does anyone know of another way to get or calculate the bounds when a line, specifically, has a transform rotate?

I have posted a copy of this here: getBoundingClientRect() + "transform: rotate()" is bugged in Chrome?. To help people with a similar problem, but then decided I'd actually ask the community.

Chrome: v100.0.4896.75

This bug has now been reported to the cromium bugs board here: https://bugs.chromium.org/p/chromium/issues/detail?id=1314959

UPDATE: I've added the same 2 static lines with a direct transform attribute with a rotation of 40deg, and 2 div's representing the 'getBoundingClientRect'. The left box is clearly not showing the smallest rectangle which contains the entire element.

UPDATE 2 Included a BBox Visual in blue. getBBox() simply calculates the bounds of a child relative to the SVG element itself, prior to any rotation transforms. getBoundingClientRect does calculate the transform correctly, but is using the BBox, which has it's own issues here: https://bugs.chromium.org/p/chromium/issues/detail?id=377665

let l = [1,2,3,4,5,6].map(d => document.getElementById(`line${d}`)),
  vis = [1,2,3,4,5,6].map(d => document.createElement(`div${d}`)),
  bboxvis = [1,2,3,4,5,6].map(d => document.createElement(`div${d}`)),
  r = 0;

vis.map((element) => {
  document.body.appendChild(element)
  element.style.position = "absolute"
  element.style.border = "1px solid green"
  element.style.background = `#0FF0002e`
})
bboxvis.map((element) => {
  document.body.appendChild(element)
  element.style.position = "absolute"
  element.style.border = "1px solid blue"
  element.style.background = `#0000FF2e`
})

let updateBounds = (element, displayElement, bboxvisEl) => { 
  let rect = element.getBoundingClientRect(),
    svgBounds = element.parentElement.getBoundingClientRect(),
    bbox = element.getBBox(),
    d = document.documentElement;
  displayElement.style.top = rect.y+d.scrollTop+"px"
  displayElement.style.left = rect.x+d.scrollLeft+"px"
  displayElement.style.width = rect.width+"px"
  displayElement.style.height = rect.height+"px"
  bboxvisEl.style.top = bbox.y+svgBounds.y+d.scrollTop + "px"
  bboxvisEl.style.left = bbox.x+svgBounds.x+d.scrollLeft +"px"
  bboxvisEl.style.width = bbox.width+"px"
  bboxvisEl.style.height = bbox.height+"px"
}

[3,4,5].forEach(i => {
    updateBounds(l[i], vis[i], bboxvis[i]);
  bboxvis[i].style.transform = `rotate(40deg)`;
})

setInterval(() => { 
  [0,1,2].forEach(i => {
    l[i].setAttribute("transform", `rotate(${r} 80 80)`);
    bboxvis[i].style.transform = `rotate(${r}deg)`;
    updateBounds(l[i], vis[i], bboxvis[i]);
  })
  r++; 
  if(r===360) r=0;
}, 20)
.container {
  width:140px;
  height:140px;
  display:inline-block;
}
<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="40" y1="40" x2="120" y2="120" stroke="black" stroke-width="2"></line>
  <line x1="40" y1="40" x2="120" y2="120" id="line1" stroke="red" stroke-width="2"></line>
</svg>

<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="80" y1="30" x2="80" y2="130" stroke="black" stroke-width="2"></line>
  <line x1="80" y1="30" x2="80" y2="130" id="line2" stroke="red" stroke-width="2"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="60" y1="30" x2="100" y2="130" stroke="black" stroke-width="2"></line>
  <line x1="60" y1="30" x2="100" y2="130" id="line3" stroke="red" stroke-width="2"></line>
</svg>
<br/>

<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="40" y1="40" x2="120" y2="120" id="line4" stroke="red" stroke-width="2" transform="rotate(40 80 80)"></line>
</svg>

<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="80" y1="30" x2="80" y2="130" id="line5" stroke="red" stroke-width="2" transform="rotate(40 80 80)"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="container">
  <line x1="60" y1="30" x2="100" y2="130" id="line6" stroke="red" stroke-width="2" transform="rotate(40 80 80)"></line>
</svg>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文