我以为我对 SVG 有相当不错的理解,包括viewport、viewBox和用户坐标系。
在下面的第一个示例中,我们使用与viewport具有相同纵横比的viewBox。正如预期的那样,用户坐标系旋转不会扭曲任何角度。
在示例二中,与viewport相比,我们将viewbox设置为不同的纵横比。换句话说,当将viewBox映射到viewport 时,不会保持形状的纵横比。右下角不会因这种缩放而变形,这是有道理的,因为坐标系原点位于 (0,0)。
然而,当我们在示例二中旋转用户坐标系时,右下角发生了扭曲。这在示例一中不会发生。
编辑 1:需要说明的是,问题在于最后一个示例中的右下角。旋转前,但使用viewBox拉伸后,角度为 90%。然而,旋转后,它不再是 90%。
为什么不均匀缩放的三角形在旋转时会失去角度?
示例一(统一比例尺)
body {
height: 500px;
}
svg {
width: 400px;
height: 400px;
border: 1px solid red;
}Run Code Online (Sandbox Code Playgroud)
<svg id="s1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 200" preserveAspectRatio="none">
<style>
polygon {
transform: translate(100px, 0px);
animation: 2s ease-in 1s 1 normal forwards rotate-down;
fill: green;
}
@keyframes rotate-down {
0% {
transform: translate(100px, 0px) rotate(0deg);
}
100% {
transform: translate(100px, 0px) rotate(45deg);
}
}
</style>
<polygon points="100,100 100,0 0,100" />
</svg>Run Code Online (Sandbox Code Playgroud)
示例二(非均匀比例)
body {
height: 500px;
}
svg {
width: 600px;
height: 400px;
border: 1px solid red;
}Run Code Online (Sandbox Code Playgroud)
<svg id="s1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 400" preserveAspectRatio="none">
<style>
polygon {
transform: translate(100px, 0px);
animation: 2s ease-in 1s 1 normal forwards rotate-down;
fill: green;
}
@keyframes rotate-down {
0% {
transform: translate(100px, 0px) rotate(0deg);
}
100% {
transform: translate(100px, 0px) rotate(45deg);
}
}
</style>
<polygon points="100,100 100,0 0,100" />
</svg>Run Code Online (Sandbox Code Playgroud)
编辑2(图像澄清):
下面我们看到了添加 viewBox之后的三角形(因此缩放和平移),但在旋转之前。右下角为 90 度。
下面我们看到的三角形后已加入视框(因而缩放和翻译),和 后转动。右下角不再是 90 度。
编辑 3:
我终于明白了这一点。
以下是解释详细信息并链接到相关资源的答案。
我终于弄清楚了这件事的真相。
以下问题是我在得出实际问题的结论后发布的,它解释了为什么坐标变换的行为如下:
在该问题的回答中,@TemaniAfif 展示了如何计算最终变换矩阵并将其应用于图形元素的坐标,以便将其从视口坐标系映射到最终用户坐标系。
长话短说,在应用转换时,我们实际做的是复制当前用户坐标系,然后相对于我们复制的当前用户坐标系进行平移。在 SVG 中,初始用户坐标系(在 viewBox 或任何变换之前)与初始视口坐标系相同。
链式/嵌套变换应用于从左到右/从外到内的坐标系,以达到可以在其中映射图形元素的最终坐标系。请注意,嵌套变换与一个元素上的链接变换具有相同的效果。
这实际上是如何运作的?嗯,每个变换都有一个预定义的仿射变换矩阵,与 CSS/SVG 无关。有几篇维基百科文章显示了这些矩阵,例如:
为了将元素的坐标映射到最终的用户坐标系,我们从左到右(按照源代码中编写的顺序)将矩阵相互相乘,以获得最终的转换矩阵。
请注意,由于我们按照变换矩阵在源代码中写入的顺序来相乘,并且由于矩阵相乘时 AxB 与 BxA 不同,因此在源代码中写入变换的顺序很重要。
最后,我们将元素的 x 和 y 坐标与最终的变换矩阵相乘,以查看每个坐标如何从视口坐标系映射到最终的用户坐标系。
对于那些如此倾向于的人,可能更容易不考虑上述内容,而只是在心里想象链式/嵌套变换从右到左/从内到外应用于元素本身(而不是用户坐标系)(即其应用于坐标系的顺序相反)。
无论您在心里想象从左到右变换坐标系然后映射到图形元素,还是通过从右到左应用变换来变换元素本身,最终结果都是相同的。
相关规格
笔记
对于这个问题,变换是应用于 SVG 元素还是 HTML 元素并不重要。适用相同的转换机制。