javascript - 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”元素的初始坐标系中。
所以:
getBoundingClientRect()
是不合适的,因为此 SVG 旨在成为 a 中的一个组件HTML DOM
,getBoundingClientRect()
并将返回 HTML 坐标系中的值。getBBox()
没有用,因为它返回元素本地坐标系中的值,由于transform
应用,它与 SVG 的初始坐标不同。getCTM()
似乎很有用,但手动应用矩阵来获取边界框看起来像很多手写数学。如果可能的话,我想避免这种情况。
所以最后...
鉴于没有直接的内置方法,获取元素边界框的最干净和/或最简单的方法是svg.checkIntersection()
什么?
解决方案
我最终在这里使用了 OSUblake 提供的解决方案,并在此处结合了一个简单的矩形相交算法。
基本上,首先计算从对象坐标空间到 SVG 坐标空间的变换矩阵:
const matrix = svg.getScreenCTM().inverse().multiply(element.getScreenCTM());
然后将矩阵应用于元素边界框的所有四个点,并根据最小值和最大值计算x
、y
、和。width
height
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 上测试)。
推荐阅读
- javascript - JS:重复字符串(Hackerrank Challenge)
- python - xlsx 到 xml Python 脚本 TypeError
- c# - Simple example of a complex situation in Unit Testing, how should this be designed?
- c# - 阐明我对 C# 中封装的理解
- python - 二维数组到数据框中的两列
- javascript - Cannot find module 'core-js/...' even though @babel/polyfill is installed
- javascript - JQuery根据点击显示带有id的图像
- identityserver4 - IdentityServer 用于多数据库应用程序
- swift - 自定义注释标注
- c# - Task.WhenAny 这可以从同步管道中解决吗?