SVG坐标系旋转偏斜角

时间:2018-12-07 10:00:39

标签: html css svg

我认为我对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度。

enter image description here

在下面,我们看到三角形之后被添加(因此已缩放和平移), 旋转之后。底部直角不再是90度。

enter image description here


编辑3:

我最终了解了这一点。

下面是一个答案,解释了详细信息并链接到相关资源。

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元素的转换都是这种方式。