SVG - 对转换后的元素使用 checkIntersection()

SVG - Using checkIntersection() with transformed elements

TLDR;

我想使用 svg.checkIntersection(),但很难 getting/calculating 函数所需的正确边界框。在初始坐标中获取 transformed SVG 元素 的边界框的最干净方法是什么SVG?


我正在尝试检查代码生成的 SVG 中是否有重叠的 text 元素。 text 元素位于 (0, 0) 并使用 transform 属性移动到正确的位置,如下所示:

<svg xmlns="http://www.w3.org/2000/svg" id="svg0" viewBox="-100 -100 200 200">
  <text id="t0" transform="rotate(-30) translate(15 -5)">Text 0</text>
  <text id="t1" transform="rotate(-10) translate(15 -10)">Text 1</text>
  <!-- do they overlap? -->
</svg>

请注意,所使用的具体变换是不可预先确定的。

所以自然有人会尝试这个:

const mySvg = document.querySelector("#svg0");
const text0 = mySvg.querySelector("#t0");
const text1 = mySvg.querySelector("#t1");
const isOverlap = mySvg.checkIntersection(text0, /* bounding box of text1 */);

问题是没有简单的方法来获得这个边界框。 W3 definition 状态:

The values are in the initial coordinate system for the current ‘svg’ element.

因此:

所以最后...

鉴于没有直接的内置方法,什么是最干净and/or最简单的方法来获取用于 svg.checkIntersection() 的元素边界框?

我最终使用了 OSUblake here, combined with a simple rectangle intersection algorithm here 提供的解决方案。

基本上,首先计算从对象坐标space到SVG坐标space的变换矩阵:

const matrix = svg.getScreenCTM().inverse().multiply(element.getScreenCTM());

然后将矩阵应用于元素边界框的所有四个点,并根据最小值和最大值计算 xywidthheight

const p = svg.createSVGPoint();

p.x = r.x;
p.y = r.y;
const pA = p.matrixTransform(matrix);

p.x = r.x + r.width;
p.y = r.y;
const pB = p.matrixTransform(matrix);

...

完整实施请参阅原文 post。

这最终确实成为了一个很大的数学函数,这是我真正想要避免的。但最终它无需 DOM 更改即可完成工作。结合简单的交集函数,它确实允许我也放弃 svg.checkIntersection(),这首先给出了奇怪的结果(在 Chrome 83 上测试)。