首页 > 解决方案 > SVG - 使用带有转换元素的 checkIntersection()

问题描述

TLDR;

我想使用svg.checkIntersection(),但难以获取/计算函数所需的正确边界框。在 SVG的初始坐标中获取转换后的SVG 元素的边界框的最简洁方法是什么?


我正在尝试检查text代码生成的 SVG 中是否存在重叠元素。使用属性将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 定义指出:

这些值位于当前“svg”元素的初始坐标系中。

所以:

所以最后...

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

标签: javascriptsvgbounding-box

解决方案


我最终在这里使用了 OSUblake 提供的解决方案,并此处结合了一个简单的矩形相交算法。

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

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

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

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);

...

有关完整实施,请参阅原始帖子。

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


推荐阅读