SVG画布,坐标系统,视窗

编辑推荐: 掘金是一个高质量的技术社区,从 CSS 到 Vue.js,性能优化到开源类库,让你不错过前端开发的每一个技术干货。 点击链接查看最新前端内容,或到各大应用市场搜索「 掘金」下载APP,技术干货尽在掌握中。

当你在屏幕上看SVG图像时,你是通过SVG视窗来看到画布的,所以其实你只看到了画布的一部分。画布和视窗是既相互独立又相互联系的概念,它们之间的关系很容易混淆,导致有时会有预料之外的结果。你只有弄明白了它们之间的关系,才知道如何去控制它们。

SVG

今年年初,我开始写SVG系列的文章,介绍了SVG的一些基本的使用。我说过我会在这个系列结束的时候做一下总结,来总结我们这一年来学习的内容。今天先来写第一个总结。

下面这是之前的文章,看一下你有没有漏掉了哪一篇:


在W3cplus上有对应的译文: - SVG基础——如何使用可缩放矢量图形(SVG) - SVG基础——如何创建简单的图形和线条 - SVG基础——填充和描边 - SVG基础——使用Line指令创建路径 - SVG基础——使用Curve指令创建路径

如果你看过前面这一系列的文章,你可能记得我提过:如果你的SVG被剪裁,你应该在<svg>这个根元素中添加一个width以及/或者height。今天我来解释一下为什么要这样做。我想先讲讲SVG的坐标系统,用于绘制图形的SVG画布,以及你用于查看画布内容的视窗。

在我第一次研究SVG坐标系统以及视窗时,我发现我很难从概念上去理解它们,我觉得可能是因为我没有从一个正确的方向来理解它们。在我试图去理解概念的含义时,我想到了一个比喻,后面我会分享给大家。

这个题目之前有其他人讲解过,而且提供了不同的方法来帮助读者从概念上理解发生了什么事情,给你发几个我看的,而且觉得不错的。

上面的第一篇文章是Sara Soueidan写的系列的文章中的第一篇,我会在接下来的几个星期内讲讲Sara在这篇文章中讲解的内容。上面的第二篇文章是Jakob Jenkov的SVG教程中的一部分。Jakob提供了很多很棒的示例,极大地帮助了我弄明白这些东西都是怎么工作的。

中文译文,可以点击这里阅读

比喻

想象一个无穷大的画布,你可以在画布上的任何地方绘制你想要的任何内容,你也可以以任何你想要的尺寸来绘制。这就是SVG画布。

现在接着想象,有人在你的画布正前方建立了一堵同样的无穷大的墙,墙的宽度和高度也是无限延伸的,把画布全都挡住了。

因为墙都是直接放在画布前面的,所以我们无法看到画布上的内容。但是建墙的人很好,帮我们开了一扇窗户,甚至还给了我们设置这扇窗户大小尺寸的能力。这扇窗户就是SVG视窗。

墙的筑造者并没有在这里停住。他还给我们留下了工具,我们可以用它来移动画布,决定要将画布的哪部分显示在窗口区域,还可以决定要显示的区域的大小。这些工具在SVG元素中是以属性的形式(viewBoxpreserveAspectRatio)表现出来的。

我会在接下来的两周讲解这些属性。今天我想将内容集中在画布、墙、视窗上,先从它们使用的坐标系统讲起:

SVG坐标系统

虽然SVG和CSS盒模型的表现形式不一样,但是它们的坐标系统的工作方式是相同的。

所有SVG坐标系的起点(0,0)都是在父元素的左上角,它们的父元素可以是body元素、div元素、或其它的容器。

当你创建了一个新的SVG元素,你也就创建了一个新的坐标系统,即无穷大的SVG画布。起点可能是和父元素的左上角对齐,但是画布在所有方向无限延伸的。x轴的正方向是向右,y轴的正方向是向下。两个坐标轴的负方向也会向左边和上边延伸。

关于SVG有一点需要明白的就是多坐标系统的同时使用。每次你创建一个新的SVG元素,就相当于在它的坐标空间创建了一个新的画布,同时也创建了一个视窗。

每一对画布和视窗的坐标系统都是默认对齐的。它们看起来就像是在同一个系统内,但其实并不是。正如我们接下来要看的,你可以改变它们相互对齐的方式。

在实际中,你在无穷大的画布上创建的元素是放置在画布的原点附近的,但是理论上,它们是可以放在任何地方的。你可以创建一个圆,然后把它放在原点右边四十亿像素远的地方,没人阻止你这样做。

理论上,窗口也可以是接近无穷大的,你可以设置你想要的任何尺寸。但是,你只有固定了窗口的尺寸,它才可以是固定大小的,而且你一旦设置了尺寸,坐标系统将会在空间上保持这个大小。

用户代理程序(即浏览器)会默认对齐这两个坐标系统的原点和坐标轴,但是你可以根据自己的需要改变这种对齐方式

这两个系统可以设置不同的单位。可以把一个设置为像素,另一个设置为毫米、picas、英寸、点、ems,或者其他任何你想要的单位。百分比%是例外,它不能在这里使用。

再次记住,这两个坐标系统,一个是作用在无穷大的画布上的,另一个是作用于固定窗口的。

SVG视窗

每次你创建了一个新的SVG元素,你也就创建了一个新的SVG视窗。视窗的大小等于你为SVG元素设置的宽度和高度。

<svg width="600" height="300" style="outline: 5px solid #630">
  <rect width="200" height="100" fill="#f00" />
</svg>

这里,我创建了一个600px宽,300px高的视窗。在视窗内我创建了一个200x100px的红色矩形。因为我没有指定单位,所以默认情况下会使用像素作为单位。因为这和我平时的设置是一样的,所以我倾向于不要指定单位,这样也比较快捷。

为了能够看到视窗的边界,我还为<svg>元素添加了一个outline。这是代码生成的结果。

你可以看到一个5px粗的棕色边框包围着一块宽为600px、高为300px的区域。边框内的内容就是视窗。

视窗内独立出来一个宽为200px、高为100px的红色矩形。默认情况下矩形的左上角是放在SVG画布的原点,和视窗的原点对齐。

我有个问题是,如果你没有为视窗设置宽和高,它的尺寸应该是怎样的呢?我没有找到明确的答案。这是由每个用户代理程序(浏览器)决定的,但是好像一般默认是300px和150px。但是,我不建议是视窗按照默认的尺寸显示,最好还是按你自己的需要来设置尺寸吧。

移动画布上的SVG元素

你可以通过给矩形设置x值和y值,改变它在SVG画布上的位置。这里我把x值和y值都设置为10px,你可以看到矩形离开了视窗左上角的位置。

<svg width="600" height="300" style="outline: 5px solid #630>
  <rect x="10" y="10" width="200" height="100" fill="#f00" />
</svg>

用这种方法改变xy坐标的值,就相当于移动了SVG画布上绘制的对象。画布本身没有移动,视窗也没有移动。我只是在画布上的另一个位置绘制了一个同样的红色矩形。

你也可以画一个部分超出了视窗边界的矩形。

<svg width="600" height="300" style="outline: 5px solid #630>
  <rect x="-100" y="-50" width="200" height="100" fill="#f00" />
</svg>

在这里你可以看到,矩形的大部分都变成不可见的了,只有小部分仍然可以在窗口中看到。其实我只是把它移动了几个像素,所以理论上你可以在这个无穷大的画布上的任何你喜欢的位置绘制矩形。

看到视窗外面的内容

有一个东西我不常见人提到的是:为什么我们看不到视窗之外的内容。因为SVG元素有一个默认值为hiddenoverflow属性,所以任何超出视窗的内容都会被隐藏。

当然,overflow属性也可以设置为其它值,比如visible

<svg width="600" height="300" style="outline: 5px solid #630; overflow: visible">
  <rect x="-100" y="-50" width="200" height="100" fill="red" />
</svg>

overflow属性的值改为visible,你可以看到SVG画布上超出视窗的那几部分内容,包括画布上那部分能出现在你屏幕上的内容(你的浏览器创建的另一个视窗)。

现在你可以看到整个红色矩形了,包括超出视窗边界的部分。在使用SVG工作的时候你一般不会这么做,现在这只是一个帮助你理解到底发生了什么东西的方式。

建立一个新的视窗

前面我说过有SVG是多个坐标系是同时作用的。最简单的情况下,也有一个用于画布,一个用于视窗的坐标系。我也提到了你可以创建新的画布,并建立新的窗口

每次你新建SVG元素,即使是嵌套在另一个SVG元素内,你会用它自己的坐标系统创建新的画布及视窗。只有较少数元素会创建新的画布和视窗:

  • <svg>元素
  • 实例化<use>元素时的<symbol>元素。
  • 引入SVG文件的<img>元素
  • <foreignObject>元素

因为我们还没有开始讨论这些元素(除了SVG元素),我现在只是把它们罗列出来。我现在主要是想强调在同一个HTML文件中创建多个SVG画布和视窗。

结束语

今天我就先讲到这里。可能我没有讲到太多SVG的新内容,但是我想要先理解好概念之后,再深入研究。

这个帮助我理解概念的比喻是:在一块无穷大的画布前有一堵无穷大的墙。我们通过墙上的一扇窗看到SVG画布上的内容,这扇窗就是SVG视窗,我们可以控制这扇窗的大小。

下周我会继续写文章,主要讲一两个属性,我们可以使用它们来四处移动画布,还可以决定画布的哪一部分或者是画布的多少内容要显示在视窗中。我会看看viewBox属性,然后接下来的星期我会聊聊preserveAspectRatio属性。

本文根据@Steven Bradley的《The SVG Canvas, Coordinate System, And Viewport》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.vanseodesign.com/web-design/svg-viewport/

彦子

在校学生,本科计算机专业。逗比一枚,热爱前端热爱生活,喜欢CSS喜欢JavaScript喜欢SVG,爱玩PS玩AI玩啊逗比的软件。努力向上,厚积薄发。

如需转载,烦请注明出处:http://www.w3cplus.com/svg/svg-viewport.html

返回顶部