我认为我对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;
}
<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>
示例二(比例尺不一致)
body {
height: 500px;
}
svg {
width: 600px;
height: 400px;
border: 1px solid red;
}
<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>
编辑2(需要澄清的图片):
在下面,我们看到三角形在之后被添加(因此已缩放和平移),但是在之前旋转。右下角为90度。
在下面,我们看到三角形在之后被添加(因此已缩放和平移),和 在旋转之后。底部直角不再是90度。
编辑3:
我最终了解了这一点。
下面是一个答案,解释了详细信息并链接到相关资源。
答案 0 :(得分:2)
希望本示例将向您显示正在发生的事情。
将鼠标悬停在SVG上可以查看为什么拉伸改变了角度。
body {
height: 500px;
}
svg {
width: 200px;
height: 400px;
border: 1px solid red;
transition: 1s width;
}
svg:hover {
width: 600px;
}
<svg id="s1" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 200 400" preserveAspectRatio="none">
<style>
polygon {
transform: translate(100px, 0px) rotate(45deg);
fill: green;
}
</style>
<polygon points="100,100 100,0 0,100" />
</svg>
答案 1 :(得分:2)
我终于明白了这一点。
在总结出实际问题是什么之后,我发布了以下问题,该问题解释了坐标变换为何按原样运行:
在回答该问题时,@ TemaniAfif显示了如何计算最终转换矩阵并将其应用于图形元素的坐标,以便将其从视口坐标系映射到最终用户坐标系。
长话短说,当应用转换时,我们实际上要做的是复制当前用户坐标系,然后将其相对于我们从中复制的当前用户坐标系进行转换。在SVG中,初始用户坐标系(在viewBox或任何变换之前)与初始视口坐标系相同。
将链接/嵌套的变换应用于坐标系从左到右 / 由内而外,以达到最终的坐标系,图形元素可以在其中形成被映射。请注意,嵌套转换与在一个元素上链接转换具有相同的效果。
这实际上如何工作?好吧,每个变换都有一个预定义的仿射变换矩阵,与CSS / SVG不相关。维基百科上有几篇文章介绍了这些矩阵,例如:
要将元素的坐标映射到最终的用户坐标系,我们将矩阵从左到右(在源代码中写入的顺序)彼此相乘,以得到最终的转换矩阵。 / p>
请注意,由于我们按变换矩阵在源代码中的写入顺序对其进行乘积,并且由于AxB与BxA在乘积矩阵时的顺序不同,因此在源代码中写入变换的顺序很重要。
最后,我们将元素的x和y坐标与此最终转换矩阵相乘,以查看每个坐标如何从视口坐标系映射到最终用户坐标系。
对于那些倾向的人,不考虑以上内容可能会更容易,而反而只是在头脑中想象将链接/嵌套的转换应用于元素本身(而不是用户坐标系)是对的从左到内/从里到外(即,将其应用于坐标系的顺序相反)。
您是否在脑海中想象着要从左到右变换坐标系,然后在图形元素中进行映射,还是,您可以通过从右向左应用变换来变换元素本身,最终结果将是相同的。
相关规范
注意
对于这个问题,将转换应用于SVG元素还是HTML元素并不重要。同样的转换机制也适用。
答案 2 :(得分:-1)
似乎您认为viewBox是在计算SVG图像时应用的一种转换方法,就像其他方法一样,这是不正确的。您在这里遇到的是将转换应用于整个SVG元素。要应用此转换,浏览器需要计算SVG对象,因此所有SVG内部转换都已应用。
这与缩放光栅图像完全一样:
[TestClass]
public class TrainUnitTest
{
[TestMethod]
public void Should_Get_TrainID() {
//Arrange
string expected = "1S45";
Train subject = new Train();
subject.TrainID = expected;
//Act
string actual = subject.TrainID;
//Assert
Assert.AreEqual(expected, actual);
}
}
polygon {
fill: transparent;
stroke-width: 4px;
stroke: black;
}
在转换后仅绘制SVG,因此它们不会失去质量。
SVG规范实际上说(here),所有应用于SVG元素的转换都是这种方式。