此主题将介绍与 getScreenCTM()
方法关联的 SVG 坐标转换。
SVG 坐标和转换这个题目非常广。你可以从 W3C SVG 规范中找到有关该题目的基本信息 – 尤其是坐标系、转换和单位。
本主题将介绍与 SVG 坐标关联的尤为致命问题 – 将屏幕坐标点(从技术上讲为初始视区坐标系)映射到与任何给定 SVG 元素关联的坐标系(从技术上讲为当前用户坐标系)。例如,考虑一个使用标准笛卡尔坐标系的 SVG 圆:
图 1
在此示例中,我们关注的是如何相对于圆的坐标系确定鼠标的位置。因此,我们必须将鼠标的屏幕坐标映射到圆的笛卡尔坐标,如下图所示:
图 2
在图 2 中,鼠标的屏幕坐标为 (843, 270)。将此点映射到圆的坐标系时,鼠标坐标将变为 (175, 175)。
注意
如果你不熟悉矩阵、矩阵乘法或矩阵求逆,请考虑查看以下一项或多项,然后再继续:
为了以算术方式描述图 2 中的转换,首先了解一些定义会很有帮助。从 W3C SVG 规范中,我们有:
转换矩阵定义从一个坐标系到另一个坐标系的数学映射。当前转换矩阵 (CTM) 使用 3x3 CTM 矩阵,通过以下等式定义从用户坐标系到视区坐标系的映射:
其中,
- M 是当前转换矩阵 (CTM)。
- 是表示用户坐标系中的点 (x, y) 的齐次矢量。在图 2 中,此矢量是 ,它相当于“圆点”(175, 175)。请注意, 中的“1”只是为了能够进行矩阵运算,实际上可以忽略。
- 是表示视区坐标系中的点 (x’, y’) 的齐次矢量。在图 2 中,此矢量是 ,它相当于“屏幕点”(843, 270)。
幸运的是,可以在 JavaScript 中通过调用 getScreenCTM()
方法来获取 CTM。例如,如果图 2 中的圆名为 svgCircle
,则 var M = svgCircle.getScreenCTM()
将返回相应的矩阵 M,以便使用上面的等式将圆点转换为屏幕点。也就是说,如果图 2 的当前转换矩阵 M 是:
那么我们按如下所示将圆坐标 (175, 175) 映射到屏幕坐标 (843, 270):
在四舍五入后,将产生屏幕坐标 (843, 270)。
上一个示例演示了如何将圆坐标转换为屏幕坐标,但是如何执行相反的操作?也就是说,给定了屏幕坐标,相应的圆坐标是什么?要回答此问题,我们必须求解 中的 。可按以下方式完成此操作:
其中,
- M-1 是 CTM 矩阵的逆阵,对于上面的示例,它大约是 。因为允许的所有 SVG 坐标转换都是将二维空间映射到另一个二维空间,所以 M 将始终可逆。
- I 表示 3x3 单位矩阵(谨记 M-1M = I)。
因此,我们可以使用推导出来的等式 ,将屏幕坐标 (843, 270) 映射到其相应的圆坐标,如下所示:
在四舍五入后,将产生圆坐标 (175, 175)。
理解这些数学知识后,在 JavaScript 中实现 会相对简单一些:
给定屏幕点(SVGPoint
类型)和一些 SVG 对象(例如圆)后,此函数会将屏幕点映射到与 someSvgObject
关联的坐标系。如果 someSvgObject
表示图 2 的圆,则:
-
var CTM = someSvgObject.getScreenCTM()
将获取与当前屏幕和圆大小关联的 CTM。 -
CTM.inverse()
将对 CTM 矩阵求逆,从而向我们提供上面等式中的 M-1。 -
screenPoint.matrixTransform( CTM.inverse() )
将 M-1 和给定的屏幕坐标 (即screenPoint
)相乘以产生所需的圆坐标 。
要查看与图 2 关联的完整示例,请单击 Liquid SVG。要查看与此示例关联的源代码,请使用浏览器的查看源文件功能。例如,在 Windows Internet Explorer 中,右键单击网页并选择“查看源文件”。请确保阅读本文档其余部分时有源代码可用。
请注意,随着你更改浏览器窗口的大小,圆大小将相应调整。此 liquid layout 是以下基于百分比的值的结果:
和
移动到代码的另一个方面(svgCircle
元素及其同级元素)时,将通过以下两个 <g>
元素转换提供标准笛卡尔坐标系:
也就是说,translate(400, 400)
会相对于在 svg
元素上通过 viewbox="0 0 800 800"
施加的 800x800 查看框,将视区坐标系的原点移动到点 (400, 400)。然后,scale(1, -1)
转换将用户坐标系的 x 轴乘以 1(无更改),将 y 轴乘以 -1,它的效果是围绕 x 轴翻转 y 轴。结果是提供标准笛卡尔坐标系(其原点出现在 800x800 视区的中点)。
该示例的其余(次要)详细信息将通过贯穿 Liquid SVG 的丰富注释进行介绍。要查看如何将此技术用在基于 SVG 的视频游戏中,请参阅“高级 SVG 动画”中的示例 6。