5

我以为我对 SVG 有相当的了解,包括viewportviewBox用户坐标系

在下面的第一个示例中,我们使用与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(图片澄清):

下面我们看到添加 viewBox之后的三角形(因此缩放和平移),但旋转之前。右下角为 90 度。

在此处输入图像描述

下面我们看到viewBox 添加(因此缩放和平移)旋转的三角形。右下角不再是 90 度。

在此处输入图像描述


编辑 3:

我最终明白了这一点。

以下是解释详细信息并链接到相关资源的答案。

4

3 回答 3

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>

于 2018-12-07T12:21:40.857 回答
2

我终于明白了这一点。

以下问题是我在总结出实际问题后发布的,它解释了为什么坐标转换的行为如此:

在对该问题的回答中,@TemaniAfif 展示了如何计算最终转换矩阵并将其应用于图形元素的坐标,以便将其从视口坐标系映射到最终用户坐标系。

长话短说,当应用变换时,我们实际上做的是复制当前用户坐标系,然后相对于我们复制的当前用户坐标系进行平移。在 SVG 中,初始用户坐标系(在 viewBox 或任何变换之前)与初始视口坐标系相同。

链式/嵌套变换应用于坐标系统left-to-right / outside-in,以达到最终的坐标系统,图形元素可以在其中映射。请注意,嵌套变换与在一个元素上链接变换具有相同的效果。

这实际上是如何工作的?好吧,每个变换都有一个预定义的仿射变换矩阵,与 CSS/SVG 无关。有几篇维基百科文章显示了这些矩阵,例如:

为了将元素的坐标映射到最终的用户坐标系,我们将矩阵从左到右(在源代码中写入的顺序)相互叠加,以达到最终的变换矩阵。

请注意,由于我们按照它们在源代码中编写的顺序来乘变换矩阵,并且由于在乘矩阵时 AxB 与 BxA 不同,因此在源代码中编写变换的顺序很重要。

最后,我们将元素的 x 和 y 坐标与这个最终的变换矩阵相乘,以查看每个坐标是如何从视口坐标系映射到最终用户坐标系的。

对于那些如此倾向于的人,可能更容易考虑上述内容,而只是在脑海中想象链接/嵌套变换应用于元素本身(而不是用户坐标系)从右到左/由内向外(即与应用于坐标系的顺序相反)。

无论您是想象从左到右变换坐标系然后映射到图形元素,还是通过应用从右到左的变换来变换元素本身,最终结果都是一样的。

相关规范

笔记

对于这个问题,变换是应用于 SVG 元素还是应用于 HTML 元素并不重要。同样的转换机制也适用。

于 2018-12-09T21:27:18.253 回答
-1

似乎你认为 viewBox 是某种变换方法,就像其他人一样,在计算 SVG 图像时,这是不正确的。您在这里体验的是应用于整个 SVG 元素的转换。要应用此转换,浏览器需要计算 SVG 对象,因此所有 SVG 内转换都已应用。

这与缩放光栅图像完全相同:

polygon {
  fill: transparent;
  stroke-width: 4px;
  stroke: black;
}
Base raster image:<br>
<img src="https://i.stack.imgur.com/ZA16O.png">

<br>Stretched raster image:<br>
<img style="height: 150px; width: 300px" src="https://i.stack.imgur.com/ZA16O.png">

<br>Base SVG:<br>
<svg viewBox="0,0,160,160" style="height: 120px" preserveAspectRatio="none">
<polygon points="10,10 150,10 80,150"/>
</svg>

<br>Stretched SVG:<br>
<svg viewBox="0,0,160,160" preserveAspectRatio="none" style="height: 120px; width: 300px;">
<polygon points="10,10 150,10 80,150"/>
</svg>

只有 SVG 在转换后被绘制,因此它们不会丢失质量。


SVG 规范实际上说(这里)所有应用于 SVG 元素的转换都是这样工作的。

于 2018-12-07T15:59:26.937 回答