图片 19

   译文出处,画布是绘制SVG内容的一块区域

preserveAspectRatio语法

preserveAspectRatio的官方语法是:

JavaScript

preserveAspectRatio = defer? <align> <meetOrSlice>?

1
preserveAspectRatio = defer? <align> <meetOrSlice>?

它在任何建立新viewport的元素上都有效(我们会在这个系列的下一部分讨论这个问题)。

defer声明是可选的,并且只有当你在<image>上添加preserveAspectRatio才被用到。用在任何其他元素上时它都会被忽略。<images>本身不在这篇文章的讨论范围,我们暂时跳过defer这个选项。

align参数声明是否强制统一放缩,如果是,对齐方法会在viewBox的宽高比不符合viewport的宽高比的情况下生效。

如果align值设为none,例如:

JavaScript

preserveAspectRatio = “none”

1
preserveAspectRatio = "none"

图形不在保持宽高比而会缩放来适应视窗,像我们在上面两个例子中看到的那样。

其他所有preserveAspectRatio值都在保持viewBox的宽高比的情况下强制拉伸,并且指定在视窗内如何对齐viewBox。我们会简短介绍align的值。

最后一个属性,meetOrSlice也是可选的,默认值为meet。这个属性声明整个viewBox在视窗中是否可见。如果是,它和align参数通过一个或多个空格分隔。例如:

JavaScript

preserveAspectRatio = “xMinYMin slice”

1
preserveAspectRatio = "xMinYMin slice"

这些值第一眼看起来也许很陌生。为了让它们更易于理解和熟悉,你可以把meetOrSlice的值类比于background-sizecontaincover值;它们非常类似。meet类似于containslice类似于cover。下面是每个值的定义和含义:

图片 1

cos(a) -sin(a) 0
sin(a) cos(a) 0
00 1

其他建立新视窗的方法

svg不是唯一能在SVG中创建新视窗的元素。在下面部分,我们会讨论使用其他SVG元素创建新视窗的方法。

  1. <svg>使用原始坐标系。

xMinYMin

  • 强制统一缩放
  • 视窗X轴的最小值对齐元素viewBox<min-x>
  • 视窗Y轴的最小值对齐元素viewBox的<min-y>
  • 把这个类比为backrgound-position: 0% 0%;

     
svg中相关单位与CSS中是一样的:em,ex,px,pt,pc,cm,mm和in。长度还可以使用”%”。
  相对度量单位:em和ex也与CSS中一样,是相对于当前字体的font-size和x-height来说的。
 
绝对度量单位:一个px是等于一个”用户单位”的,也就是”5px”与”5″是一样的。但是一个px是不是对应一个像素,那就看有没有进行过一些变换了。
     
其他的几个单位基本都是px的倍数:1pt=1.25px,1pc=15px,1mm=3.543307px,1cm=35.43307px,1in=90px。

<g transform=”translate(-10,-20)”>
<g transform=”scale(2)”>
<g transform=”rotate(45)”>
<g transform=”translate(5,10)”>
<!– graphics elements go here –>
</g>
</g>
</g>
</g>

例子

试想我们有如下的SVG:图片 2

上述SVG是响应式的。改变屏幕的尺寸会导致整个SVG图形根据需要做出反应。下面的截图展示了拉伸页面的结果,以及SVG如何变得更小。注意SVG的内容如何根据SVG视窗和相互之间保持它们的初始位置。图片 3

使用嵌套SVG,我们将改变这个情况。我们可以对SVG中每个独立的元素根据SVG视窗声明一个位置,所以随着SVG
视窗尺寸的改变(即最外层svg的改变),每个元素独立于其他元素发生改变。

注意,在这个时候,你需要熟悉SVG viewport, viewBox,
preserveAspectRatio是如何生效的。

我们将要创建一个效果,当屏幕尺寸变化时,蛋壳的上部分移动使得其中的可爱的小鸡显示出来,如下图所示:图片 4

为了达到这个效果,蛋的上半部分必须和其他部分分离出来单独包含一个自己的svg。这个svg包含框会有一个IDupper-shell

然后,我们保证新的svg#upper-shell和外层SVG有一样的高度和宽度。可以通过在svg上声明width="100%"``height="100%"或者不声明任何高度和宽度来实现。如果内层SVG上没有声明任何宽高,它会自动扩展为外层SVG宽高的100%

最终,为了确保上壳被“抬”起或定位在svg#upper-shell顶部的中心,我们将使用适当的preserveAspectRatio值来确保viewBox被定位在视窗的顶部中心-值是xMidYMin

SVG图形的代码如下:

XHTML

<svg version=”1.1″ xmlns=””
xmlns:xlink=”; <!– … –>
<svg viewBox=”0 0 315 385″ preserveAspectRatio=”xMidYMid meet”>
<!– the chicken illustration –> <g id=”chicken”> <!–
… –> </g> <!– path forming the lower shell –>
<path id=”lower-shell” fill=”url(#gradient)” stroke=”#000000″
stroke-width=”1.5003″ d=”…”/> </svg> <svg id=”upper-shell”
viewBox=”0 0 315 385″ preserveAspectRatio=”xMidYMin meet”> <!–
path forming the upper shell –> <path id=”the-upper-shell”
fill=”url(#gradient)” stroke=”#000000″ stroke-width=”1.5003″
d=”…”/> </svg> </svg>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!– … –>
    <svg viewBox="0 0 315 385" preserveAspectRatio="xMidYMid meet">
        <!– the chicken illustration –>
        <g id="chicken">
            <!– … –>
        </g>
        <!– path forming the lower shell –>
        <path id="lower-shell" fill="url(#gradient)" stroke="#000000" stroke-width="1.5003" d="…"/>
    </svg>
 
    <svg id="upper-shell" viewBox="0 0 315 385" preserveAspectRatio="xMidYMin meet">
        <!– path forming the upper shell –>
        <path id="the-upper-shell" fill="url(#gradient)" stroke="#000000" stroke-width="1.5003" d="…"/>
    </svg>
</svg>

这个时候,注意在嵌套svg#upper-shell上声明的viewBox和最外层svg有相同的值(在它被移除之前)。我们用相同的viewBox值我原因就是这样,SVG在大屏幕上保持最初的样子。

所以,这件事是这样的:我们开始一个SVG-在我们的例子中,这是一张里面藏着一个小鸡的带裂纹的蛋。然后,我们创建了另一“层”并把上部分的壳放在里面-这一层通过使用嵌套svg创建。嵌套svg和外层svg的尺寸和viewBox一样。最终,内层SVG的viewBox被设置成不管屏幕尺寸是多少都“固定”在viewport的顶部-这确保了当屏幕尺寸很窄时SVG被拉长,上层的壳被向上举起,因此展示出“隐藏”在里面的小鸡。图片 5

一旦屏幕尺寸拉伸,SVG被拉长,使用preserveAspectratio="xMidYMin meet"把包含上部分壳的viewBox被定位到viewport的顶部。图片 6

点击下面按钮来查看在线SVG。记住改变屏幕尺寸再看SVG变化。

在线案例

嵌套或”分层”SVG使你可以根据改变的视窗定位SVG的一部分,在保持元素宽高比的情况下。所以图片可以在不扭曲内容元素的情况下自适应。

如果我们想要整个鸡蛋剥离显示出小鸡,我们可以单独用一个svg层包含下部分壳,viewBox也相同。确保下部分壳向下移动并固定在视窗的底部中心,我们使用preserveAspectRatio="xMidYMax meet"来定位。代码如下:

XHTML

<svg version=”1.1″ xmlns=””
xmlns:xlink=”; <svg id=”chick”
viewBox=”0 0 315 385″ preserveAspectRatio=”xMidYMid meet”> <!–
the chicken illustration –> <g id=”chick”> <!– … –>
</g> </svg> <svg id=”upper-shell” viewBox=”0 0 315 385″
preserveAspectRatio=”xMidYMid meet”> <!– path forming the upper
shell –> <path id=”the-upper-shell” fill=”url(#gradient)”
stroke=”#000000″ stroke-width=”1.5003″ d=”…”/> </svg>
<svg id=”lower-shell” viewBox=”0 0 315 385″
preserveAspectRatio=”xMidYMax meet”> <!– path forming the lower
shell –> <path id=”the-lower-shell” fill=”url(#gradient)”
stroke=”#000000″ stroke-width=”1.5003″ d=”…”/> </svg>
</svg>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <svg id="chick" viewBox="0 0 315 385" preserveAspectRatio="xMidYMid meet">
        <!– the chicken illustration –>
        <g id="chick">
            <!– … –>
        </g>
    </svg>
 
    <svg id="upper-shell" viewBox="0 0 315 385" preserveAspectRatio="xMidYMid meet">
        <!– path forming the upper shell –>
        <path id="the-upper-shell" fill="url(#gradient)" stroke="#000000" stroke-width="1.5003" d="…"/>
    </svg>
 
    <svg id="lower-shell" viewBox="0 0 315 385" preserveAspectRatio="xMidYMax meet">
        <!– path forming the lower shell –>
        <path id="the-lower-shell" fill="url(#gradient)" stroke="#000000" stroke-width="1.5003" d="…"/>
    </svg>
</svg>

每个svg层/viewport等于最外层svg宽高的100%。所以我们基本有了三个副本。每层包含一个元素-上部分壳,下部分壳,或小鸡。三层的viewBox是相同的,只有preserveAspectRatio不同。图片 7

当然,在这个例子里,一开始的图形中小鸡隐藏在蛋里,随着屏幕变小才显示出来。然而,你可以做一些不一样的:你可以开始在小屏幕上创建一个图形,然后在大屏幕上显示一些东西;即当svg变宽时才有更多垂直空间来展示元素。

你可以更有创造性,根据不同屏幕尺寸来显示和隐藏元素-使用媒体查询-把新元素通过特定方式定位来达到特定的效果。想象力是无穷的。

同时注意嵌套svg不需要和容器svg有相同的宽高;你可以声明宽高并且限制svg内容,超出边界裁切-这都取决于你想要达到什么效果。

示例:

初始坐标系

初始视窗坐标系是一个建立在视窗上的坐标系。原点(0,0)在视窗的左上角,X轴正向指向右,Y轴正向指向下,初始坐标系中的一个单位等于视窗中的一个”像素”。这个坐标系统类似于通过CSS盒模型在HTML元素上建立的坐标系。

初始用户坐标系是建立在SVG画布上的坐标系。这个坐标系一开始和视窗坐标系完全一样-它自己的原点位于视窗左上角,x轴正向指向右,y轴正向指向下。使用viewBox属性,初始用户坐标系统-也称当前坐标系,或使用中的用户空间-可以变成与视窗坐标系不一样的坐标系。我们在一下节中讨论如何改变坐标系。

到现在为止,我们还没有声明viewBox属性值。SVG画布的用户坐标系统和视窗坐标系统完全一样。

下图中,视窗坐标系的”标尺”是灰色的,用户坐标系(viewBox)的是蓝色的。由于它们在这个时候完全相同,所以两个坐标系统重合了。图片 8

上面SVG中的鹦鹉的外框边界是200个单位(这个例子中是200个像素)宽和300个单位高。鹦鹉基于初始坐标系在画布中绘制。

新用户空间(即,新当前坐标系)也可以通过在容器元素或图形元素上使用transform属性来声明变换。我们将在这篇文章的第二部分讨论关于变换的内容,更多细节在第三部分和最后部分中讨论。

 

变换的计算也很简单:以最外层的svg元素的视窗为例,假设svg的宽与长设置为width,height,viewBox的设置为(x0,y0,u_width,u_height)。则绘制的图形,宽和高的缩放比例分别为:width/u_width,
height/u_height。视窗的左上角的坐标设置为了(x0,y0)。

使用<use>ing <symbol>建立一个新的视窗

symbol元素会定义新视窗,无论它什么时候被use元素实例化。

symbol元素的使用可以参考use元素中的xlink:href属性:

XHTML

<svg> <symbol id=”my-symbol” viewBox=”0 0 300 200″> <!–
contents of the symbol –> <!– this content is only rendered when
`use`d –> </symbol> <use xlink:href=”#my-symbol” x=”?”
y=”?” width=”?” height=”?”> </svg>

1
2
3
4
5
6
7
<svg>
    <symbol id="my-symbol" viewBox="0 0 300 200">
        <!– contents of the symbol –>
        <!– this content is only rendered when `use`d –>
    </symbol>
    <use xlink:href="#my-symbol" x="?" y="?" width="?" height="?">
</svg>

上面值中的问号表示这些值也许没有声明-如果xy没有声明,默认值为0,也不需要声明宽高。

看到了吧,当你use一个symbol元素,然后使用开发工具检查DOM,你不会看到use标签中symbol的内容。因为use的内容在shadow
tree里被渲染,如果你在开发工具中允许shadow DOM显示你就能看到。

symbol被使用时,它被深度克隆到生成的shadow
tree中,例外是symbolsvg替换。这个生成的svg总是有明确的宽高。如果宽高的值在use元素上,这些值会被转换生成svg。如果属性宽和/或高没有声明,生成的svg元素会使用这些值的100%。

因为我们在DOM中使用了svg,并且因为这个svg实际上包含在外层svg中,我们遇到的嵌套svg的状况和我们在之前一章讨论到的并没有多少不一样-嵌套的svg形成了一个新的viewport。嵌套svgviewBox是在symbol元素上声明的viewBox。(symbol元素接受viewBox元素值。更多信息,阅读这篇文章:Structuring,
Grouping, and Referencing in SVG –
The , , and Elements)

所以我们现在有了一个新的viewport,尺寸和位置可以使用元素(x,ywidthheight)声明,viewBox值可以在symbol元素上声明。symbol的内容随后再这个视窗和viewBox中被渲染和定位。

最后,symbol元素也接收preserveAspectratio属性值,你可以在由use建立的新视窗中定位viewBox。这很清楚,不是吗?你可以像我们在之前的部分里一样控制新创建的嵌套svg

Dirk
Weber 也创建了一个使用嵌套SVG和symbol元素来模仿CSS
border
images的表现。你可以在这里查看文章。

  1. 用户坐标系(User Coordinate)

xMaxYMin

  • 强制统一缩放。
  • 视窗X轴的最大值对齐元素的viewBox的 <min-x>+<width>
  • 视窗Y轴的最小值对齐元素的viewBox<min-y>
  • 把这个类比为backrgound-position: 100% 0%;

     
上面的例子绘制的图中这个你只能看到绿色的矩形,而且绿色的矩形显示在屏幕上是200*200像素的,这个时候坐标点已经不是一一对应了,图被放大了。

平移 – translate 平移变换把相关的坐标值平移到指定的位置,该变换需要传入两个轴上平移的量。看例子:

结束语

建立新的viewports和坐标系-像上述提到的一样通过嵌套svg和其他元素-允许你控制SVG的部分内容而通过其他方式你可能没法一样控制。

在写这片文章以及思考例子和使用情况的整个过程中,我一直在思考嵌套SVG如何让我们在处理SVG时能更好控制并有更灵活的方式。自适应SVG可以通过简洁的代码创建,在SVG中可以创建独立于其他元素的流动元素,用来模拟CSS
border images来在高分屏上定义背景。

你是否已经在SVG中使用嵌套视窗来创建有趣的例子了呢?你能否相处更多有创意的例子呢?

这篇文章总结了“理解SVG坐标系和变换”这个系列。下一步,我们会讨论动画,甚至更多!敬请期待,感谢你的阅读!

1 赞 1 收藏
评论

图片 9

参考文献

理解SVG坐标系和变换:视窗,viewBox和preserveAspectRatio

2015/09/23 · HTML5 ·
SVG

原文出处:
SaraSoueidan   译文出处:Blueed(@Ivan_z3)   

SVG元素不像HTML元素一样由CSS盒模型管理。这使得我们可以更加灵活定位和变换这些元素-也许一眼看上去不太直观。然而,一旦你理解了SVG坐标系和变换,操纵SVG会非常简单并且很有意义。本篇文章中我们将讨论控制SVG坐标系的最重要的三个属性:viewport, viewBox
和 preserveAspectRatio

这是本系列三篇文章中的第一篇,这篇文章讨论SVG中的坐标系和变换。

  • 理解SVG坐标系和变换(第一部分)-viewport,viewBox,和preserveAspectRatio
  • 理解SVG坐标系和变换(第二部分)-transform属性
  • 理解SVG坐标系和变换(第三部分)-建立新视窗

为了使文中的内容和解释更形象化,我创建了一个互动演示,你可以任意改变viewBox 和 preserveAspectRatio的值。

在线案例

这个例子只是主要内容的一小部分,所以看完请回来继续阅读这篇文章

      这里一定不要混淆:视窗的大小和位置已经由创建视窗的元素和外围的元素共同确定了(例如最外层的svg元素建立的视窗由CSS,width和height确定),这里的viewBox其实是设置这个确定的区域能显示视窗坐标系的哪个部分。       viewBox的设置其实是包含了视窗空间的缩放和平移两种变换。

代码如下:

理解SVG坐标系统和变换: 建立新视窗

2015/09/23 · HTML5 ·
SVG

原文出处:
SaraSoueidan   译文出处:Blueed@Ivan_z3   

在SVG绘制的任何一个时刻,你可以通过嵌套<svg>或者使用例如<symbol>的元素来建立新的viewport和用户坐标系。在这篇文章中,我们将看一下我们如何这样做,以及这样做如何帮助我们控制SVG元素并让它们变得更加灵活(或流动)。

这是SVG坐标系和变换系列的第三篇也是最后一篇文章。在第一篇中,包括了任何要理解SVG坐标系统基础的需要知道的内容;更具体的是,
SVG
viewport, viewBox和 preserveAspectRatio属性。在第二篇文章里,你可以了解到任何你需要了解的关于SVG系统变换的内容。

  • 理解SVG坐标系和变换(第一部分)-viewport,viewBox,和preserveAspectRatio
  • 理解SVG坐标系和变换(第二部分)-transform属性
  • 理解SVG坐标系和变换(第三部分)-建立新视窗

通过这篇文章,我假定你已经读了这个系列的第一部分关于SVG
viewport, viewBox 和 preserveAspectRatio 属性的内容
。在阅读这篇文章之前你不需要读第二篇关于坐标系变换的内容。

PS:MDN关于transform属性的解释可能有一点错。

preserveAspectRatio属性

preserveAspectRatio属性强制统一缩放比来保持图形的宽高比。

如果你用不同于视窗的宽高比定义用户坐标系,如果像我们在之前的例子中看到的那样浏览器拉伸viewBox来适应视窗,宽高比的不同会导致图形在某些方向上扭曲。所以如果上一个例子中的viewBox被拉伸以在所有方向上适应视窗,图形看起来如下:图片 10

当给viewBox设置0 0 200 300的值时扭曲显而易见(显然这很不理想),这个值小于视窗尺寸。我故意选择这个尺寸从而让viewBox匹配鹦鹉边界盒子的尺寸。如果浏览器拉伸图像来适应整个视窗,看起来会像下面这样:图片 11

preserveAspectRatio属性让你可以在保持宽高比的情况下强制统一viewBox的缩放比,并且如果不想用默认居中你可以声明viewBox在视窗中的位置。

<svg width=”100″ height=”100″>
  <rect x=”0″ y=”0″ width=”100″ height=”100″ fill=”green” />
  <circle cx=”15″ cy=”15″ r=”15″ fill=”red” />
  <circle cx=”15″ cy=”15″ r=”15″ fill=”yellow” transform=”skewX(45)” />
  <rect x=”30″ y=”30″ width=”20″ height=”20″  />
  <rect x=”30″ y=”30″ width=”20″ height=”20″ transform=”skewX(45)”  />
  <rect x=”30″ y=”30″ width=”20″ height=”20″ transform=”skewY(45)”  />
</svg>

a c e
b d f
0 0 1

使用<foreignObject>建立新视窗

foreignObject元素建立一个新的viewport来渲染这个元素的内容。

foreignObject标签允许你把非SVG内容添加到SVG文件中。通常,foreignObject的内容被认为不同于命名空间。例如,你可以把一些HTML放到SVG元素的中间。

foreignObject接收属性包括xyheightwidth,用来定位对象和调整尺寸,创建用于呈现它里面所引用的内容的范围。

有需要关于foreignObject元素的要说因为它给内容创建了新的viewport。如果你感兴趣,可以查看MDN
entry或者在The
Nitty Gritty Blog上查看Christian
Schaeffer创建的实际使用例子。

该文章是SVG课程(慕课网)的学习笔记,以及查阅一些资料,加上我个人理解的一个总结。

none

不强制统一缩放。如果必要的话,在不统一(即不保持宽高比)的情况下缩放给定元素的图像内容直到元素的边界盒完全匹配是视窗矩形。

换句话说,如果有必要的话viewBox被拉伸或缩放来完全适应整个视窗,不管宽高比。图形也许会扭曲。

(注意:如果<align>的值是none,可选的<meetOrSlice>值无效。)

     
这个例子绘制一个矩形,并把它的起点(0,0)平移到(30,40)处。虽然可以直接设置(x,y)的坐标值,但是使用平移变换去实现也很方便。这个变换第二个参数可以省略,默认当0处理。

<svg width=”200″ height=”200″ viewBox=”0 0 200 200″>
<rect x=”0″ y=”0″ width=”200″ height=”200″ fill=”Red” />
<rect x=”0″ y=”0″ width=”100″ height=”100″ fill=”Green” />
</svg>

使用<iframe>建立新视窗

代表SVG文件的iframe元素建立新坐标系的情况类似于上述解释的image元素的情况。iframe元素也可以有x,y,widthheight属性,除了它自身的preserveAspectratio之外。

X’ = aX + cY + e

互动演示

要理解viewport, viewBox,
以及不同的preserveAspectRatio值是如何工作的最好方法是可视化的演示。

出于这个目的,我创建了一个简单的互动演示,你可以改变这些属性的值来查看新值导致的结果。图片 12

在线案例

我希望这篇文章在帮助你理解SVG viewport, viewBox,
和 preserveAspectRatio 内容时有作用。如果你想要了解更多关于SVG坐标系的内容,例如嵌套坐标系,建立一个新的坐标系以及SVG中的变换,继续阅读这一系列接下来的部分。感谢你的阅读!

2 赞 1 收藏
评论

图片 9

视窗变换 – viewBox属性

图片 14

嵌套<svg>元素

在第一部分我们讨论了<svg>元素如何为SVG画布内容建立一个视窗。在SVG绘制过程中的任何一个时刻,你可以创建一个新的视窗其中包含的图形是通过把一个<svg>元素包含在另一个中绘制的。通过建立新视窗,你隐性得建立了一个新视窗坐标系和新用户坐标系。

例如,试想有一个<svg>以及里面的内容:

XHTML

<svg xmlns=””
xmlns:xlink=”; <!– some SVG content
–> <svg> <!– some inner SVG content –> </svg>
<svg>

1
2
3
4
5
6
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!– some SVG content –>
    <svg>
        <!– some inner SVG content –>
    </svg>
<svg>

 

第一件需要注意的是内容<svg>元素不需要声明一个命名空间xmlns因为默认和外层<svg>的命名空间相同。当然,如果在HTML5文档中外层<svg>也不需要命名空间。

你可以使用一个嵌套的SVG来把元素组合在一起然后在父SVG中定位它们。现在,你也可以把元素组合在一起并且使用组<g>来定位-通过把元素包括在一组<g>元素中。你可以使用transform属性在画布中定位它们。然而,使用<svg>肯定好过使用<g>。使用x和y坐标来定位,在许多情况下,比使用变换更加方便。另外,<svg>元素接受宽高值,<g>不行。这意味着,<svg>也许并必要的,因为它可以创建一个新的viewport和坐标系,你可以不需要也不想要。

通过给<svg>声明宽高值,你把内容限制在通过x,y,widthheight属性定义的viewport的边界。任何超过边界的内容会被裁切。

如果你不声明xy属性,它们默认是0。如果你不声明heightwidth属性,<svg>会是父SVG宽度和高度的100%。

另外,声明用户坐标系而不是默认的也会影响内部<svg>的内容。

<svg>内的元素百分比值的声明会根据<svg>计算,而不是外层<svg>。例如,下面的代码会导致内层SVG等于400单位,里面的长方形是200个单位:

XHTML

<svg width=”800″ height=”600″> <svg width=”50%” ..> <rect
width=”50%” … /> </svg> </svg>

1
2
3
4
5
<svg width="800" height="600">
    <svg width="50%" ..>
        <rect width="50%" … />
    </svg>
</svg>

 

如果最外层<svg>的宽度为100%(例如,如果它在一个文档中内联或者你想要它可以流动),内层SVG会扩展拉伸来保持宽度为外层SVG的一半-这是强制的。

嵌套SVG在给SVG画布中的元素增加灵活性和扩展性时尤其有用。我们知道,使用viewBox值和preserveAspectRatio,我们已经可以创建响应式SVG。最外层<svg>的宽度可以设置成100%来确保它扩展拉伸到它的容器(或页面)扩展或拉伸。然后通过使用viewBox值和
preserveAspectRatio,我们可以保证SVG画布可以自适应viewport中的改变(最外层svg)。我在CSSConf演讲的幻灯片中写到了关于响应式SVG的内容。你可以在这里查看这个技术。

然而,当我们像这样创建一个响应式SVG,整个画布以及所有绘制在上面的元素都会有反应并且同时改变。但有时候,你只想让图形中的一个元素变为响应式,并且保持其他东西“固定”在一个位置和/或尺寸。这时候嵌套svg就很有用。

svg元素有独立于它父元素的坐标系,它可以有独立的viewBoxpreserveAspectRatio属性,你可以任意修改里面内容的尺寸和位置。

所以,要让一个元素更加灵活,我们可以把它包裹在<svg>元素中,并且给svg一个弹性的宽度来适应最外层SVG的宽度,然后声明preserveAspectRatio="none"这样的话里面的图形会扩展和拉伸到容器的宽度。注意svg可以多层嵌套,但是为了让事情简洁,我在这篇文章里只嵌套一层深度。

为了演示嵌套svg如何发挥作用,让我们来看一些例子。

四个坐标系

xMidYMid (默认值)

  • 强制统一缩放。
  • 视窗X轴的中间值对齐元素的viewBox的X轴中间值。
  • 视窗Y轴的中间值对齐元素的viewBox的Y轴中间值。
  • 把这个类比为backrgound-position: 50% 50%;

     
viewBox属性值的格式为(x0,y0,u_width,u_height),每个值之间用逗号或者空格隔开,它们共同确定了视窗显示的区域:视窗左上角坐标设为(x0,y0)、视窗的宽设为u_width,高为u_height;这个变换对整个视窗都起作用。

用户坐标系:本质是一个坐标系,有原点,x轴与y轴;而且在两个方向上是无限延伸的。默认情况下,原点在视窗的左上角,x轴水平向右,y轴竖直向下。可以对这个坐标系的点进行变换。

参考<image>中的SVG image建立一个新视窗

images元素表明整个文件的内容被渲染到一个当前用户坐标系中给定的长方形。image元素可以代表图片文件例如PNG或JPEG或者有”image/svg+xml”的MIME类型的文件。

代表SVG文件的image元素会导致建立一个临时新视窗因为定义相关资源有svg元素。

XHTML

<image xlink:href=”myGraphic.svg” x=”?” y=”?” width=”?” height=”?”
preserveAspectRatio=”?” />

1
<image xlink:href="myGraphic.svg" x="?" y="?" width="?" height="?" preserveAspectRatio="?" />

<image>元素接收许多属性,其中一些属性-和这篇文章有关的-是xy位置属性,widthheight属性以及preserveAspectratio

通常,SVG文件会包含一个根<svg>元素;这个元素也许声明位置和尺寸,另外也许有viewBoxpreserveAspectratio值。

当一个image元素代表SVG图片文件,根svg的xywidthheight属性被忽略。除非image元素上的preserveAspectRatio值以“defer”开头,根元素上的preserveAspectRatio值在代表SVG图片时也被忽略。然而相关image元素上的preserveAspectRatio属性定义SVG图片内容如何适应视窗。

评估被参考内容定义的preserveAspectRatio属性时使用viewBox属性值。对于明确定义的viewBox内容(例如,最外层元素上有viewBox属性的SVG文件)值应该被使用。对于大多数值(PING,JPEG),图片边界应该被使用(即image元素有隐含的尺寸为’0
0 raster-image-width
raster-image-height’的viewBox)。如果值不全的话(例如,外层的svg元素没有viewbox属性的SVG文件)preserveAspectRatio值被忽略,只有视窗x & y属性引起的移动才用来显示内容。

例如,如果一个image元素代表PNG或JPEG并且preserveAspectRatio="xMinYMin meet",那么栅格的宽高比会保持,栅格会在保证整个栅格适应视窗的情况下尽可能放大尺寸,栅格的左上角会和由image元素上x,y,widthheight定义的视窗的左上角对齐。

如果preserveAspectRatio的值是“none”那么图片的宽高比不会保持不变。图片会自适应,栅格的左上角和坐标系(x,y)完全对齐,栅格的右下角和坐标系(x+widthy+height)完全对齐。

本文地址 :

xMaxYMid

  • 强制统一缩放。
  • 视窗X轴的最大值对齐元素的viewBox的 <min-x>+<width>
  • 视窗Y轴的中间值对齐元素的viewBox的Y轴中间值。
  • 把这个类比为backrgound-position: 100% 50%;

      体会下面几种代码绘出的结果的不同:

代码如下:

使用嵌套SVG使元素流动

在保持宽高比的情况下定位元素,我们可以使用嵌套svg只允许特定元素流动-可以不保持这些特定元素的宽高比。

例如,如果你只想SVG中的一个元素流动,你可以把它包含在一个svg中,并且使用preserveAspectRatio="none"来让这个元素扩展始终撑满这个视窗的宽,并且保持宽高比和像我们在之前例子中做的一样定位其他元素。

XHTML

<svg> <!– … –> <svg viewBox=”..”
preserveAspectRatio=”none”> <!– this content will be fluid –>
</svg> <svg viewBox=”..” preserveAspectRatio=”..”> <!–
content positioned somewhere in the viewport –> </svg> <!–
… –> </svg>

1
2
3
4
5
6
7
8
9
10
<svg>
    <!– … –>
    <svg viewBox=".." preserveAspectRatio="none">
        <!– this content will be fluid –>
    </svg>
    <svg viewBox=".." preserveAspectRatio="..">
        <!– content positioned somewhere in the viewport –>
    </svg>
    <!– … –>
</svg>

Jake
Archibald创建了一个简单实用的嵌套SVG使用案例:一个简单的UI可以包含定位在最外层svg角落的元素,并且保持宽高比,UI的中间部分浮动并且根据svg宽度改变进行拉伸。你可以在这里查看。确保你在开发工具里检查代码来选取和想象不同viewbox和svg使用的效果。

即是父容器坐标系。

viewBox语法

viewBox属性接收四个参数值,包括:<min-x>, <min-y>, width 和 height

CSS

viewBox = <min-x> <min-y> <width> <height>

1
viewBox = <min-x> <min-y> <width> <height>

<min-x> 和 <min-y> 值决定viewBox的左上角,widthheight决定视窗的宽高。这里要注意视窗的宽高不一定和父<svg>元素的宽高一样。<width><height>值为负数是不合法的。值为0的话会禁止元素的渲染。

注意视窗的宽度也可以在CSS中设置为任何值。例如:设置width:100%会让SVG视窗在文档中自适应。无论viewBox的值是多少,它会映射为外层SVG元素计算出的宽度值。

设置viewBox的例子如下:

<!– The viewBox in this example is equal to the viewport, but it can
be different –> <svg width=”800″ height=”600″ viewBox=”0 0 800
600″> <!– SVG content drawn onto the SVG canvas –>
</svg>

1
2
3
4
<!– The viewBox in this example is equal to the viewport, but it can be different –>
<svg width="800" height="600" viewBox="0 0 800 600">
    <!– SVG content drawn onto the SVG canvas –>
</svg>

如果你之前在其他地方看到过viewBox,你也许会看到一些解释说你可以用viewBox属性通过缩放或者变化使SVG图形变换。这是真的。我将深入探究并且告诉你甚至可以使用viewBox来切割SVG图形。

理解viewBox和视窗之间差异最好的方法是亲身观察。所以让我们看一些例子。我们将从viewBox和viewport的宽高比相同的例子开始,所以我们还不需要深入了解preserveAspectRatio

     
从结果中,你可以直接看到同样尺寸的矩形,在不同的倾斜变换后,得到的位置和形状。这里注意矩形的起始位置都已经改变了,这是因为在新的坐标系统中,(30,30)已经在不同的位置了。

<rect x=”0″ y=”0″ width=”10″ height=”10″ transform=”translate(30,40)”
/>

你可以将X对齐和Y对齐两两结合组成一个align参数,例如:xMaxYMax或xMidYMid。

slice

在保持宽高比的情况下,缩放图形直到viewBox覆盖了整个视窗区域。viewBox被缩放到正好覆盖视窗区域(在两个维度上),但是它不会缩放任何超出这个范围的部分。换而言之,它缩放到viewBox的宽高可以正好完全覆盖视窗。

在这种情况下,如果viewBox的宽高比不适合视窗,一部分viewBox会扩展超过视窗边界(即,viewBox绘制的区域会比视窗大)。这会导致部分viewBox被切片。

你可以把这个类比为background-size: cover。在背景图片的情况中,图片在保持本身宽高比(如何)的情况下缩放到宽高可以完全覆盖背景定位区域的最小尺寸。

所以,meetOrSlice被用来声明viewBox是否会被完全包含在视窗中,或者它是否应该尽可能缩放来覆盖整个视窗,甚至意味着部分的viewBox会被“slice”。

例如,如果我们声明viewBox的尺寸为200*300,并且使用了meetslice值,保持align值为浏览器默认,每个值的结果会看起来如下:图片 15

align参数使用9个值中的一个或者为none。任何除none之外的值都用来保持宽高比缩放图片,并且还用来在视窗中对齐viewBox

当使用百分比值时,align值类似于background-position。你可以把viewBox当做背景图像。通过align定位和background-position的不同在于,不同于通过一个与视窗相关的点来声明一个特定的viewBox值,它把具体的viewBox“轴”和对应的视窗的“轴”对齐。

为了理解每个align值的含义,我们将首先介绍每一个“轴”。

还记得viewBox<min-x><min-y>值吗?我们将使用它们来定义viewBox中的”min-x”和”min-y”轴。另外,我们将定义两个轴“max-x”和”max-y“,各自通过<min-x> + <width> 和 <min-y> + <height>来定位。最后,我们定义两个轴”mid-x”和”mid-y”,根据<min-x> + (<width>/2) 和 <min-y> + (<height>/2)来定位。

这样做是不是让事情更复杂了呢?如果是这样,让我们看一下下面的图片来看一下每个轴代表了什么。在这张图片中,<min-x>和 <min-y>值都设置为0。viewBox被设置为viewBox = "0 0 300 300"图片 16

上面图片中的灰色虚线代表视窗的mid-xmid-y轴。我们将对它们赋一些值来对齐viewBoxmid-xmid-y轴。对于视窗,min-x的值等于0min-y值也等于0max-x值等于viewBox的宽度,max-y的值等于高度,mid-xmid-y代表了宽度和高度的中间值。

对齐的取值包括:

 

视窗坐标系:本质是一个坐标系,有原点,x轴与y轴;而且在两个方向上是无限延伸的。默认情况下,原点在视窗的左上角,x轴水平向右,y轴竖直向下。可以对这个坐标系的点进行变换。

“applied from right to
left.”这里说变换应用是从右到左的,但其实应该是正常的从左到右,矩阵的计算才是从右到左。

meet(默认值)

基于以下两条准侧尽可能缩放元素:

  • 保持宽高比
  • 整个viewBox在视窗中可见

在这个情况下,如果图形的宽高比不符合视窗,一些视窗会超出viewBox的边界(即viewBox绘制的区域会小于视窗)。(在viewBox一节查看最后的例子。)在这个情况下,viewBox的边界被包含在viewport中使得边界满足。

这个值类似于background-size: contain。背景图片在保持宽高比的情况下尽可能缩放并确保它适合背景绘制区域。如果背景的长宽比和应用的元素的长宽比不一样,部分背景绘制区域会没有背景图片覆盖。

平移变换[1 0 1 0 tx ty]:

坐标空间变换 让我们回顾一下canvas用户坐标的变换,它们是通过平移,缩放,旋转函数实现的;每次变换后对以后绘制的图形都起作用,除非再次进行变换,这是”当前”用户坐标系统的概念。canvas只有唯一一个用户坐标系。
在SVG中,情况完全不同。SVG本身作为一种向量图元素,它的两个坐标系统本质上都可以算作”用户坐标系统”;SVG的两个坐标空间都是可以变换的:视窗空间变换和用户空间变换。视窗空间变换由相关元素(这些元素创建了新的视窗)的属性viewBox控制;用户空间变换由图形元素的transform属性控制。视窗空间变换应用于对应的整个视窗,用户空间变换应用于当前元素及其子元素。

示例:

xMinYMax

  • 强制统一缩放。
  • 视窗X轴的最小值对齐元素viewBox<min-x>
  • 视窗X轴的最大值对齐元素的viewBox<min-y>+<height>
  • 把这个类比为backrgound-position: 0% 100%;

用户坐标系:本质是一个坐标系,有原点,x轴与y轴;而且在两个方向上是无限延伸的。默认情况下,原点在视窗的左上角,x轴水平向右,y轴竖直向下。可以对这个坐标系的点进行变换。

image:引用svg元素时会创建新视窗。
foreignObject:创建新视窗去渲染里面的对象。

meetOrSlice参数指明viewbox的缩放方式。

xMaxYMax

  • 强制统一缩放。
  • 视窗X轴的最大值对齐元素的viewBox的 <min-x>+<width>
  • 视窗Y轴的最大值对齐元素的viewBox的 <min-y>+<height>
  • 把这个类比为backrgound-position: 100% 100%;

所以,通过使用preserveAspectRatio属性的alignmeetOrSlice值,你可以声明是否统一缩放viewBox,是否和视窗对齐,在视窗中是否整个可见。

有时候,取决于viewBox的尺寸,一些值可能会导致相似的结果,例如在早先viewBox="0 0 200 300"的例子中,一些对齐完全用了不同的align值。这时候就要设置meetOrSlice的值为meet来保证viewBox包含在viewport内。图片 17

如果我们把meetOrSlice的值改成slice,不同的值我们将得到不同的结果。注意viewBox是如何拉伸来覆盖整个视窗的。x轴被拉伸到用200单位来覆盖视窗800单位。为了达到这个目的,并且保持viewBox的宽高比,y轴在底部被“裁切”,但是你可以想象它在视窗中高度上的延伸。图片 18

当然,不同的viewBox值看起来不同于我们这里用的200*300。为了保持简洁,我们不再列举更多的例子,你可以看我创建的一些互动演示来帮助你更好地形象化理解viewBoxpreserveAspectRatio在不同值下的效果。你可以在一下节中查看互动演示例子的链接。

但是在这之前,我想要提醒你注意如果<min-x> 和 <min-y>值改变,那么mid-xmid-ymax-x,
和 max-y的值也会发生改变。你可以在互动演示中改变这些值来查看轴以及相关联的viewBox的对齐方式的改变。

下面图片展示了定位轴的位置为viewBox = "100 0 200 300"时的效果。和之前用一样的例子,但是我们把<min-x>的值设为100而不是之前的0。你可以设置成任何你想要的值。注意min-xmid-x,
和 max-x轴是如何变化的。这里使用的preserveAspectRatio值为默认的xMinYMin meet,意味着mid-*轴和视窗轴的中间对齐。图片 19

image:引用svg元素时会创建新视窗。
foreignObject:创建新视窗去渲染里面的对象。

代码如下:

Y’ = bX + dY + f

viewBox

我喜欢把viewBox理解为“真实”坐标系。首先,它是用来把SVG图形绘制到画布上的坐标系。这个坐标系可以大于视窗也可以小于视窗,在视窗中可以整体可见或部分可见。

在之前的章节里,这个坐标系-用户坐标系-和视窗坐标系完全一样。因为我们没有把它声明成其他坐标系。这就是为什么所有的定位和绘制看起来是基于视窗坐标系的。因为我们一旦创建视窗坐标系(使用widthheight),浏览器默认创建一个完全相同的用户坐标系。

你可以使用viewBox属性声明自己的用户坐标系。如果你选择的用户坐标系统和视窗坐标系统宽高比(高比宽)相同,它会延伸来适应整个视窗区域(一分钟内我们就来讲个例子)。然而,如果你的用户坐标系宽高比不同,你可以用preserveAspectRatio属性来声明整个系统在视窗内是否可见,你也可以用它来声明在视窗中如何定位。我们会在下个章节里讨论这一情况的细节和例子。在这一章里,我们只讨论viewBox的宽高比符合视窗的情况-在这些例子中,preserveAspectRatio不产生影响。

在我们讨论这些例子前,我们回顾一下viewBox的语法。

     
所有的能建立一个视窗的元素(看下一节),再加上marker,pattern,view元素,都有一个viewBox属性。

这里一定不要混淆:视窗的大小和位置已经由创建视窗的元素和外围的元素共同确定了(例如最外层的svg元素建立的视窗由CSS,width和height确定),这里的viewBox其实是设置这个确定的区域能显示视窗坐标系的哪个部分。 viewBox的设置其实是包含了视窗空间的缩放和平移两种变换。

<svg viewBox="0 0 95 50"
     xmlns="http://www.w3.org/2000/svg">
   <g stroke="green" fill="white" stroke-width="5">
     <circle cx="25" cy="25" r="15"/>
     <circle cx="40" cy="25" r="15"/>
     <circle cx="55" cy="25" r="15"/>
     <circle cx="70" cy="25" r="15"/>
   </g>
</svg>

xMidYMin

  • 强制统一缩放。
  • 视窗X轴的中间值对齐元素的viewBox的X轴中间值。
  • 视窗Y轴的中间值对齐元素的viewBox的 <min-y>
  • 把这个类比为backrgound-position: 50% 0%;

视窗:指的是网页上面可视的矩形局域,长度和宽度都是有限的,这个区域一般与外围对象的尺寸有关。

上面的例子绘制的图中你可以看到绿色和红色的矩形,这种情况下视窗坐标系的点还是与视窗上的点是一一对应的,这个也是默认情况。

2. 线性变换

xMidYMax

  • 强制统一缩放。
  • 视窗X轴的中间值对齐元素的viewBox的X轴中间值。
  • 视窗Y轴的最大值对齐元素的viewBox<min-y>+<height>
  • 把这个类比为backrgound-position: 50% 100%;

<svg width=”500″ height=”500″>
 <text x=”20″ y=”20″ font-size=”20″>ABC (scale)</text>
 <text x=”50″ y=”50″ font-size=”20″ transform=”scale(1.5)”>ABC (scale)</text>
</svg>

所有的能建立一个视窗的元素(看下一节),再加上marker,pattern,view元素,都有一个viewBox属性。

慕课网SVG教程对于ViewBox的示例,我觉得不错,可以自己实践操作,看看效果。

发表评论

电子邮件地址不会被公开。 必填项已用*标注