您的位置:新葡亰496net > 新葡亰官网 > 新葡亰496net:视窗坐标系与用户坐标系及调换概

新葡亰496net:视窗坐标系与用户坐标系及调换概

发布时间:2019-06-19 08:35编辑:新葡亰官网浏览(78)

    理解SVG坐标系统和变换: transform属性

    2015/09/23 · HTML5 · SVG

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

    SVG元素可以通过缩放,移动,倾斜和旋转来变换-类似HTML元素使用CSS transform来变换。然而,当涉及到坐标系时这些变换所产生的影响必然有一定差别。在这篇文章中我们讨论SVG的transform属性和CSS属性,包括如何使用,以及你必须知道的关于SVG坐标系变换的知识。

    这是我写的SVG坐标系统和变换部分的第二篇。在第一篇中,包括了任何要理解SVG坐标系统基础的需要知道的内容;更具体的是, SVG viewport, viewBox 和 preserveAspectRatio 属性。

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

    这一部分我建议你先阅读第一篇,如果没有,确保你在阅读这篇之前已经读了第一篇。

    坐标系统   SVG存在两套坐标系统:视窗坐标系与用户坐标系。默认情况下,用户坐标系与视窗坐标系的点是一一对应的,都为原点在视窗的左上角,x轴水平向右,y轴竖直向下;如下图所示: 

    点评:SVG存在两套坐标系统:视窗坐标系与用户坐标系。默认情况下,用户坐标系与视窗坐标系的点是一一对应的,记下来介绍下坐标与变换,感兴趣的朋友可以了解下啊,或许对你有所帮助

    理解SVG transform坐标变换

    2015/10/11 · HTML5 · SVG

    原文出处: 张鑫旭   

    理解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的值。

    在线案例

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

    transform属性值

    tranform属性用来对一个元素声明一个或多个变换。它输入一个带有顺序的变换定义列表的<transform-list>值。每个变换定义由空格或逗号隔开。给元素添加变换看起来如下:

    有效地SVG变换有:旋转缩放移动, 和倾斜transform属性中使用的变换函数类似于CSS中transform属性使用的CSS变换函数,除了参数不同。

    注意下列的函数语法定义只在transform属性中有效。查看section about transforming SVGs with CSS properties获取关于CSS变换属性中使用的语法信息。

    新葡亰496net 1

    坐标系统 SVG存在两套坐标系统:视窗坐标系与用户坐标系。默认情况下,用户坐标系与视窗坐标系的点是一一对应的,都为原点在视窗的左上角,x轴水平向右,y轴竖直向下;如下图所示: 

    一、HTML transform和SVG transform

    SVG中自带transform属性,没错,是属性,例如:

    JavaScript

    <svg width="200" height="150"> <rect x="30" y="30" width="120" height="90" transform="rotate(45)"></rect> </svg>

    1
    2
    3
    <svg width="200" height="150">
        <rect x="30" y="30" width="120" height="90" transform="rotate(45)"></rect>
    </svg>

    普通的HTML元素没有transform属性,但是支持CSS3的transform, 好奇的小伙伴可能会疑问了,CSS3中的transform变换,跟SVG中的transform是什么关系呢?

    恩,有点类似于谢霆锋和陈冠希之间的关系,有些小复杂。

    新葡亰496net 2

    OK, 先说说相似之处吧。
    一些基本的变换类型是一样的,包括:位移translate, 旋转rotate, 缩放scale, 斜切skew以及直接矩阵matrix. 但只局限于2D层面的变换。SVG似乎只支持二维变换(若有不对,欢迎指正),且类似translateXrotateX也都是不支持的。

    下面就是不一样的地方了:
    1. CSS3 transform一般用在普通元素上,虽然也可以应用在SVG元素上,但是IE浏览器(IE edge未测试)却不支持SVG元素;

    JavaScript

    rect { /* IE说:你这是弄啥来? */ transform:rotate(45deg); }

    1
    2
    3
    4
    rect {
        /* IE说:你这是弄啥来? */
        transform:rotate(45deg);
    }

    2. HTML元素的CSS3 transform和SVG的transform坐标系统大相径庭;

    平常我们使用transform其坐标是相对于当前元素而言的,默认是元素的中心点变换,我们可以通过transform-origin属性改变变换的中心点。而SVG中的transform的坐标变换的是相对于画布的左上角计算的,跟HTML的transform差别较大,理解上也更加麻烦。而本文就是彻底理清SVG中的transform到底是怎么工作的。

    3. 具体的语法细节有差异。SVG transform属性语法有些自带偏移。而CSS transform则更加纯粹些。

    //zxx: 据说CSS的transform和SVG的transform属性即将合并。

    SVG画布

    canvas是绘制SVG内容的一块空间或区域。理论上,画布在所有维度上都是无限的。所以SVG可以是任意尺寸。然而,SVG通过有限区域展现在屏幕上,这个区域叫做viewport。SVG中超出视窗边界的区域会被裁切并且隐藏。

    Matrix

    你可以使用matrix()函数在SVG元素上添加一个或多个变换。matrix变换语法如下:

    matrix(<a> <b> <c> <d> <e> <f>)

    1
    matrix(<a> <b> <c> <d> <e> <f>)

    上述声明通过一个有6个值的变换矩阵声明一个变换。matrix(a,b,c,d,e,f)等同于添加变换matrix[a b c d e f]

    如果你不精通数学,最好不要用这个函数。对于那些精通的人,你可以在这里阅读更多关于数学的内容。因此这个函数很少使用-我将忽略来讨论其他变换函数。

     

    新葡亰496net 3

    二、SVG transform translate位移

    我们先来看下最简单最基本的translate位移变换,例如,我们偏移(295,115)大小的位置,HTML元素的偏移(下图左)和SVG元素的偏移(下图右)就会不一样。一个是相对自己的中心点(下图左),一个是SVG的左上角(下图右)。

    新葡亰496net 4

    虽然两者的相对位置不一样,但是,对于单纯地位移来讲,无论你相对于那个点位置,实际偏移的位置都是一样的,因此,从表现上讲,两者最终的位置看上去还是一样的。

    您可以狠狠地点击这里:HTML translate和SVG translate比对demo

    新葡亰496net 5

    前面我们提到过,SVG元素也能使用CSS3的transform进行变换(非IE浏览器),但是只能支持2D层面的几个属性,例如translateX(tx),translateY(ty)以及translate(tx[, ty])translateZ(tz)则并不支持。

    如果我们使用SVG元素自带的transform属性进行变换,则仅支持translate(tx[ ty])这种用法(缺省使用0代替),当多个参数值的时候,可以使用逗号,或者直接空格分隔,但是不能包含单位,例如下面这种写法直接翘辫子:

    CSS

    transform="translate(30px 12px)"

    1
    transform="translate(30px 12px)"

    下面这种无单位写法才可以:

    CSS

    transform="translate(30 12)" transform="translate(30, 12)"

    1
    2
    transform="translate(30 12)"        
    transform="translate(30, 12)"

    另外,和CSS3的transform一样,SVG中的translate位移也是支持多声明累加的。例如:

    CSS

    transform="translate(30 12) translate(30 12)"

    1
    transform="translate(30 12) translate(30 12)"

    等同于:

    CSS

    transform="translate(60 24)"

    1
    transform="translate(60 24)"

    需要注意的是,俩个translate中间不要混有其他的transform变换。否则,最终的位移就不是简单的相加了。

    视窗

    视窗是一块SVG可见的区域。你可以把视窗当做一个窗户,透过这个窗户可以看到特定的景象,景象也许完整,也许只有一部分。

    SVG的视窗类似访问当前页面的浏览器视窗。网页可以是任何尺寸;它可以大于视窗宽度,并且在大多数情况下都比视窗高度要高。然而,每个时刻只有一部分网页内容是透过视窗可见的。

    整个SVG画布可见还是部分可见取决于这个canvas的尺寸以及preserveAspectRatio属性值。你现在不需要担心这些;我们之后会讨论更多的细节。

    你可以在最外层<svg>元素上使用widthheight属性声明视窗尺寸。

    <!-- the viewport will be 800px by 600px --> <svg width="800" height="600"> <!-- SVG content drawn onto the SVG canvas --> </svg>

    1
    2
    3
    4
    <!-- the viewport will be 800px by 600px -->
    <svg width="800" height="600">
        <!-- SVG content drawn onto the SVG canvas -->
    </svg>

    在SVG中,值可以带单位也不可以不带。一个不带单位的值可以在用户空间中通过用户单位声明。如果值通过用户单位声明,那么这个值的数值被认为和px单位的数值一样。这意味着上述例子将被渲染为800px*600px的视窗。

    你也可以使用单位来声明值。SVG支持的长度单位有:emexpxptpccmmmin和百分比。

    一旦你设定最外层SVG元素的宽高,浏览器会建立初始视窗坐标系和初始用户坐标系。

    Translation

    要移动SVG元素,你可以用translate()函数。translate函数的语法如下:

    CSS

    translate(<tx> [<ty>])

    1
    translate(<tx> [<ty>])

    translate()函数输入一个或两个值得来声明水平和竖直移动值。tx代表x轴上的translation值;ty代表y轴上的translation值。

    ty值是可选的,如果省略,默认值为0txty值可以通过空格或者逗号分隔,它们在函数中不代表任何单位-它们默认等于当前用户坐标系单位。

    下面的例子把一个元素向右移动100个用户单位,向下移动300个用户单位。

    <circle cx="0" cy="0" r="100" transform="translate(100 300)" />

    1
    <circle cx="0" cy="0" r="100" transform="translate(100 300)" />

    上述代码如果以translate(100, 300)用逗号来分隔值的形式声明一样有效。

     

    SVG的视窗位置一般是由CSS指定,尺寸由SVG元素的属性width和height设置,但是如果SVG是存储在embedded对象中(例如object元素,或者其他SVG元素),而且包含SVG的文档是用CSS或者XSL格式化的,并且这些外围对象的CSS或者其他指定尺寸的值已经可以计算出视窗的尺寸了,则此时会使用外围对象的尺寸。

    三、SVG transform rotate旋转

    上面的位移变换,我们似乎没看到明显的不一样。但是,从这里的旋转变换开始,就可以看出明显的差异了。

    下面图示的是基本的45度旋转(来自css-tricks)(左HTML元素,右SVG元素):

    新葡亰496net 6

    由于SVG元素的默认是SVG左上角为中心变换的,因此,矩形旋转的幅度就有了过山车的感觉。

    您可以狠狠地点击这里:HTML rotate和SVG rotate比对demo

    新葡亰496net 7

    结果会发现,两者位置大相径庭了:

    CSS transform中的rotate语法比较直白:rotate(angle),就一个angle参数,表示角度大小,不过必须要有单位,比如deg(度), turn(圈), grad(百分度 – 一种角的测量单位,定义为一个圆周角的1/400。常用于建筑或土木工程的角度测量),甚至可以使用calc()计算,例如:calc(.25turn - 30deg).

    但是,SVG中的属性transform旋转就没有这么多花头,单位?哦,别逗了,毛线都没有,直接光秃秃的数值,表示角度deg,例如:

    CSS

    transform="rotate(45)"

    1
    transform="rotate(45)"

    具体语法为:rotate(angle[ x y]). 大家注意到没有,这里有个[ x y][]表示这个可选参数。也就是说,SVG中的rotate旋转比CSS的rotate多了一个可选参数,那这个可选参数[ x y]表示什么意思呢?

    告诉你,是非常有用的东西。用来偏移transform变换中心点的。

    为什么说非常有用呢?SVG元素默认是基于左上角的,但是我们的旋转元素往往都在SVG的中间区域,此时旋转跨度太大,智商余额不足的我们就脑补不过来,此时难免希望可以像CSS的transform变换一样,围绕元素的中心点变换。怎么办?

    我们可以借助CSS3 transform-origin修改SVG元素默认的变换中心点,然后配合CSS变换。但是,我们前面多次提到,IE浏览器的SVG元素不识别CSS中的transform. 所以,从兼容性上讲,CSS策略是不可行的。难道就没有其他办法了,有,就是这里的可选参数[ x y],通过对变换中心点的偏移修正,我们也能让SVG元素围绕自身的中心点旋转了。

    所以,上面的demo,我们稍微修改下,就能让矩形围绕自己旋转了,见下:

    JavaScript

    <rect x="30" y="30" width="120" height="90" rx="10" ry="10" fill="#a0b3d6" transform="rotate(45, 90 75)"></rect> <!-- 90 = 30 120/2 --> <!-- 75 = 30 90/2 -->

    1
    2
    3
    <rect x="30" y="30" width="120" height="90" rx="10" ry="10" fill="#a0b3d6" transform="rotate(45, 90 75)"></rect>
    <!-- 90 = 30 120/2 -->
    <!-- 75 = 30   90/2 -->

    您可以狠狠地点击这里:SVG元素也围绕自身中心点旋转demo

    新葡亰496net 8

    使用原理图表示就是下面这样(左HTML旋转,右SVG元素偏移旋转):

    新葡亰496net 9

    同样的,rotate旋转可以多个值并存,例如下面的CSS和attribute用法:

    CSS

    transform: rotate(45deg) rotate(-45deg); transform="rotate(45) rotate(-45)

    1
    2
    transform: rotate(45deg) rotate(-45deg);
    transform="rotate(45) rotate(-45)

    然而,需要注意的是,SVG属性的transform声明的中心变换坐标是不能共享的。

    因此,虽然transform="rotate(45, 90 75)"是中心点旋转,但是,后面再添加其他东西,例如:rotate(-45)则偏移值忽略,终中心点还是SVG的左上角(0,0)位置,好惨!

    例如原来的45度旋转,再加个-45度反向旋转:

    XHTML

    <rect x="30" y="30" width="120" height="90" rx="10" ry="10" fill="#a0b3d6" transform="rotate(45, 90 75) rotate(-45)"></rect>

    1
    <rect x="30" y="30" width="120" height="90" rx="10" ry="10" fill="#a0b3d6" transform="rotate(45, 90 75) rotate(-45)"></rect>

    结果位置回去了?才怪呢!新葡亰496net 10

    CSS的是又回去了,但是SVG的确是挂在月球上了。究其原因是rotate(-45)又是相对SVG左上角变换的啦!

    新葡亰496net 11

    您可以狠狠地点击这里:SVG连续旋转demo

    虽然乍看上去,好像SVG的坐标系统有些怪怪的,但是,实际上,在有些需求场景下,SVG这种看似独立的偏移系统更容易实现一些功能。

    比方说,我们希望某个SVG元素先以右下角为中心旋转90度,然后再以右上角为中心旋转90度,该怎么处理?

    对于SVG transform,我们直接面向需求写数值就可以了。假设我们的SVG元素的高宽是120*90, 左上角坐标是(30,30), 则,显然,右下角坐标是(150,120), 右上角坐标是(150,30),于是,我们的transform值就很简单:

    XHTML

    transform="rotate(90, 150 120) rotate(90 150 30)"

    1
    transform="rotate(90, 150 120) rotate(90 150 30)"

    参见下面的示意图(示意图的坐标与上面略有出入,但不影响原理示意):新葡亰496net 12

    但是,如果我们使用之前容易理解的CSS3来实现,反而就复杂了,因为CSS3中的transform的变换点只能一次性指定,如果要实现不同变换点的旋转效果,只能通过translate再次偏移,例如,实现上面的右下角再右上角90度旋转,则要这样:

    CSS

    transform-origin: right bottom; /* 或者 100% 100% */ transform: rotate(90deg) translate(0, -100%) /* 从右下到右上 */ rotate(90deg) translate(0, 100%);

    1
    2
    3
    4
    5
    6
    transform-origin: right bottom; /* 或者 100% 100% */
    transform:
      rotate(90deg)
      translate(0, -100%) /* 从右下到右上 */
      rotate(90deg)
      translate(0, 100%);

    Gif示意下就是:新葡亰496net 13

    显然要麻烦很多。可见,两种坐标系统没有绝对的优劣。

    您可以狠狠地点击这里:右下再右上旋转90度demo

    新葡亰496net 14

    上图为两种变换的最终效果,虽然最终的效果是一样的,但是,从理解上而言,这回,是SVG的transform反而更容易理解。还是那句话,辩证看问题,凡事无绝对。

    初始坐标系

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

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

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

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

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

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

    Scaling

    你可以通过使用scale()函数变换来向上或者向下缩放来改变SVG元素的尺寸。scale变换的语法是:

    CSS

    scale(<sx> [<sy>])

    1
    scale(<sx> [<sy>])

    scale()函数输入一个或两个值来声明水平和竖直缩放值。sx代表沿x轴的缩放值,用来水平延长或者拉伸元素;sy代表沿y轴缩放值,用来垂直延长或者缩放元素。

    sy值是可选的,如果省略默认值等于sxsxsy可以用空格或者逗号分隔,它们是无单位值。

    下面例子把一个元素的尺寸根据最初的尺寸放大两倍:

    XHTML

    <rect width="150" height="100" transform="scale(2)" x="0" y="0" />

    1
    <rect width="150" height="100" transform="scale(2)" x="0" y="0" />

    下列例子把一个元素缩放到最初宽度的两倍,并且把高度压缩到最初的一半:

    XHTML

    <rect width="150" height="100" transform="scale(2 0.5)" x="0" y="0" />

    1
    <rect width="150" height="100" transform="scale(2 0.5)" x="0" y="0" />

    上述例子使用逗号分隔的值例如scale(2, .5)仍然有效。

    这里需要注意当SVG元素缩放时,整个坐标系被缩放,导致元素在视窗中重新定位,现在不用担心这些,我们会在下一节中讨论细节。

     

    这里需要区分视窗,视窗坐标系,用户坐标系的概念:

    四、SVG transform scale缩放

    SVG中的缩放的语法就比较单纯了,就scale(sx[, sy])sx表示横坐标缩放比例,sy表示纵坐标缩放比例。其中sy是可缺省的,如果缺失,表示使用和sx一样的值,也就是等比例缩放。其中,sxsy两个参数可以逗号分隔,也可以使用空格分隔。这和CSS3中的使用有所不同,两外,SVG transform属性值缩放是不支持scaleXscaleY这些鬼的。

    同样的,CSS控制的transform和SVG元素属性控制的transform的坐标系统是不一样的。一个默认元素中心(下图左),一个是SVG画布左上角(下图右),于是(from css-tricks):新葡亰496net 16

    因此,当我们对SVG元素scale缩放时候,发现位置也有出乎我们意料,就应该知道是怎么回事了。

    rotate旋转虽然也是迥异坐标,但是其参数自带偏移参数,我们我们移个花接个木,还是可以得到我们想要的结果。但是,scale缩放这里,就要悲惨很多了,没有自带偏移参数,于是,当我们要实现SVG元素居中缩放的效果,还需要使用translate手动偏移。

    怎么个手动偏移法呢?即使先translate其中心点位置到元素的中心坐标位置,然后缩放,然后坐标再反方向还原回去。例如,某元素中心点坐标是(95, 75), 垂直缩放1.5倍的效果则是:

    CSS

    transform="translate(95 75) scale(1, 1.5) translate(-95 -75)"

    1
    transform="translate(95 75) scale(1, 1.5) translate(-95 -75)"

    您可以狠狠地点击这里:CSS transform和SVG transform scale缩放demo

    对应的CSS代码就简单多了,直接:

    CSS

    .scale { transform: scale(1, 1.5); }

    1
    2
    3
    .scale {
        transform: scale(1, 1.5);
    }

    然后最终效果都是一样的:新葡亰496net 17

    使用Gif原理示意如下:

    新葡亰496net 18

    viewBox

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

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

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

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

    Skew

    SVG元素也可以被倾斜,要倾斜一个元素,你可以使用一个或多个倾斜函数skewX 和 skewY

    skewX(<skew-angle>) skewY(<skew-angle>)

    1
    2
    skewX(<skew-angle>)
    skewY(<skew-angle>)

    函数skewX声明一个沿x轴的倾斜;函数skewY声明一个沿y轴的倾斜。

    倾斜角度声明是无单位角度的默认是度。

    注意倾斜一个元素可能会导致元素在视窗中重新定位。在下一节中有更多细节。

     

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

    五、SVG transform skew斜切

    先来了解下CSS中的斜切,斜切,如果单纯切一个方向,我们可以看成把矩形变成了平行四边形,其总面积不变化。

    以纯X轴变换举例,skewX(-45deg)则下面这样子(灰色方块为原始位置):

    新葡亰496net 19

    skewX(45deg)则下面这样子:新葡亰496net 20

    对于SVG的skew斜切变换,表现效果原理是一样的。但是,使用的语法却相当有意思。

    在前面的一些变换中,例如位移、缩放之类是不支持translateXscaleX这种CSS常见用法的,但是这里的skew却有点让人哭笑不得:不支持skew(x[, y])这种语法,而只能是skewX或者skewY.

    别问我为什么?我只是大自然的搬运工,我不生产语法。

    因此,没有:

    JavaScript

    <del datetime="2015-10-10T12:49:32 00:00">transform="skew(45, 0)"</del>

    1
    <del datetime="2015-10-10T12:49:32 00:00">transform="skew(45, 0)"</del>

    只有:

    CSS

    transform="skewX(45)"

    1
    transform="skewX(45)"

    同样的,由于变换中心点的差异,CSS实现的变换和SVG属性变换往往最后的位置是不一样的:

    新葡亰496net 21

    不仅如此,如果元素的中心点不是就是SVG的左上角,则skewX(α1) skewX(α2)的最终位置和skewX(α1 α2)是不一样的(位移和旋转不会这样子)。

    您可以狠狠地点击这里:CSS SVG transform skew斜切差异及连续斜切差异demo

    正如demo所示,CSS的和SVG的位置差异很大:新葡亰496net 22

    SVG的连续变换和一次性变换的位置也是不一样的:新葡亰496net 23

    可能有人要疑问,为何连续斜切变换和一次性变换位置会不一样?其实原因很简单,因为斜切的角度和元素偏移大小并不是线性的,比方说,从70到80度和80度到90度之间的位移大小(虽然都是10度的变化区间)是显然不是一个档次的。因此,分开多次连续斜切最终的坐标偏移要比一次性偏移来得小。

    最后,和缩放一样,你想要让SVG元素中心点斜切,可以先translate偏移,在skew变换。就不重复举例演示了。

    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

    Rotation

    你可以使用rotate()函数来旋转SVG元素。这个函数的语法如下:

    CSS

    rotate(<rotate-angle> [<cx> <cy>])

    1
    rotate(<rotate-angle> [<cx> <cy>])

    rotate()函数对于给定的点和 旋转角度值执行旋转。不像CSS3中的旋转变换,不能声明除degress之外的单位。角度值默认无单位,默认单位是度。

    可选的cxcy值代表无单位的旋转中心点。如果没有设置cxcy,旋转点是当前用户坐标系的原点(查看第一部分如果你不知道用户坐标系是什么。)

    在函数rotate()中声明旋转中心点一个快捷方式类似于CSS中设置transform: rotate()transform-origin。SVG中默认的旋转中心是当前使用的用户坐标系的左上角,这样也许你无法创建想要的旋转效果,你可以在rotate()中声明一个新的中心点。如果你知道元素在SVG画布中的尺寸和定位,你可以把它的中心设置为旋转中心。

    下面的例子是以当前用户坐标系中的(50,50)点为中心进行旋转一组元素:

    XHTML

    <g id="parrot" transform="rotate(45 50 50)" x="0" y="0"> <!-- elements making up a parrot shape --> </g>

    1
    2
    3
    <g id="parrot" transform="rotate(45 50 50)" x="0" y="0">
        <!-- elements making up a parrot shape -->
    </g>

    然而,如果你想要一个元素围绕它的中心旋转,你也许想要像CSS中一样声明中心为50% 50%;不幸的是,在rotate()函数中这样做是不允许的-你必须用绝对坐标。然而,你可以在CSS的transform属性中使用transform-origin属性。这篇文章后面会讨论更多细节。

     

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

    六、其他居中变换处理

    像缩放、斜切这些SVG变换,想要如CSS transform-origin:50% 50%一样的中心点变换效果,需要事先位移,我们有没有其他办法呢?

    这里有两个思路可供大家参考下。

    1. 原始中心位置乃SVG左上角
    拿45度旋转举例,我们可以把元素默认就放在中心点和SVG左上角重合的位置上,参见下面的gif演示:新葡亰496net 24

    于是,我们原来的3步曲就变成了2步曲:

    CSS

    translate(140 105) rotate(45) translate(-140 -105) → translate(140 105) rotate(45)

    1
    translate(140 105) rotate(45) translate(-140 -105) → translate(140 105) rotate(45)

    2. 通过viewBox调整
    viewBox可以用来改变SVG画布的视区,这个我之前专门撰文介绍过,是SVG学习必备被深入理解的基础知识,参见:“理解SVG的viewport,viewBox,preserveAspectRatio”一文。

    我们可以把元素默认挂在左上角,然后,通过viewBox做手脚,让元素呈现的位置并不是真正的左上角,例如应用viewBox='-140 -105 280 210',则变化如下示意图:

    新葡亰496net 25

    此时,我们只需要让元素旋转就可以了,无需额外的做translate位移,见下gif:新葡亰496net 26

    与viewport宽高比相同的viewBox

    我们从一个简单的例子开始。这个例子中的viewBox的尺寸是视窗尺寸的一半。在这个例子中我们不改变viewBox的原点,所以<min-x><min-y>都设置成0。viewBox的宽高是viewport宽高的一半。这意味着我们保持宽高比。

    <svg width="800" height="600" viewBox="0 0 400 300"> <!-- SVG content drawn onto the SVG canvas --> </svg>

    1
    2
    3
    <svg width="800" height="600" viewBox="0 0 400 300">
        <!-- SVG content drawn onto the SVG canvas -->
    </svg>

    所以,viewBox="0 0 400 300"到底有什么用呢?

    • 它声明了一个特定的区域,canvas横跨左上角的点(0,0)到点(400,300)
    • SVG图像被这个区域裁切
    • 区域被拉伸(类似缩放效果)来充满整个视窗。
    • 用户坐标系被映射到视窗坐标系-在这种情况下-一个用户单位等于两个视窗单位。

    下面的图片展示了在我们例子中把上面的viewBox应用到<svg> 画布中的效果。灰色单位代表视窗坐标系,蓝色坐标系代表viewBox建立的用户坐标系。

    新葡亰496net 27

    任何在SVG画布中画的内容都会被对应到新的用户坐标系中。

    我喜欢像Google地图一样通过viewBox把SVG画布形象化。在Google地图中你可以在特定区域缩放;这个区域是唯一可见的,并且在浏览器视窗中按比例增加。然而,你知道地图的剩余部分还在那里,但是不可见因为它超出视窗的边界-被裁切了。

    现在让我们试着改变<min-x><min-y>的值。都设置为100。你可以设置成任何你想要的值。宽高比还是和视窗的宽高比一样。

    <svg width="800" height="600" viewBox="100 100 200 150"> <!-- SVG content drawn onto the SVG canvas --> </svg>

    1
    2
    3
    <svg width="800" height="600" viewBox="100 100 200 150">
        <!-- SVG content drawn onto the SVG canvas -->
    </svg>

    添加viewBox="100 100 200 150"的效果和之前例子中一样都是裁切的效果。图形被裁切然后拉伸来充满整个视窗区域。

    新葡亰496net 28

    再一次,用户坐标系被映射到视窗坐标系-200用户单位映射为800视窗单位因此每个用户单位等于四个视窗单位。结果像你看到的那样是放大的效果。

    另外注意,在这个时候,为<min-x><min-y>声明非0的值对图形有变换的效果;更加特别的是,SVG 画布看起来向上拉伸100个单位,向左拉伸100个单位(transform="translate(-100 -100)")。

    的确,作为规范说明,viewBox属性的影响在于用户代理自动添加适当的变换矩阵来把用户空间中具体的矩形映射到指定区域的边界(通常是视窗)”

    这是一个很棒的说明我们之前已经提到的内容的方法:图形被裁切然后被缩放以适应视窗。这个说明随后增加了一个注释:“在一些情况下用户代理在缩放变换之外需要增加一个移动变换。例如,在最外层的svg元素上,如果viewBox属性对<min-x><min-y>声明非0值得那么就需要移动变换。”

    为了更好演示移动变换,让我们试着给<min-x><min-y>添加-100。移动效果类似transform="translate(100 100)";这意味着图形会在切割和缩放后移动到右下方。回顾倒数第二个裁切尺寸为400*300的例子,添加新的无效<min-x><min-y>值,新的代码如下:

    <svg width="800" height="600" viewBox="-100 -100 300 200"> <!-- SVG content drawn onto the SVG canvas --> </svg>

    1
    2
    3
    <svg width="800" height="600" viewBox="-100 -100 300 200">
        <!-- SVG content drawn onto the SVG canvas -->
    </svg>

    给图形添加上述viewBox transformation的结果如下图所示:新葡亰496net 29

    注意,与transform属性不同,因为viewBox自动添加的tranfomation不会影响有vewBox属性的元素的x,y,宽和高等属性。因此,在上述例子中展示的带有width,heightviewBox属性的svg元素,widthheight属性代表添加viewBox 变换之前的坐标系中的值。在上述例子中你可以看到初始(灰色)viewport坐标系甚至在<svg>上使用了viewBox属性后仍然没有影响。

    另一方面,像tranform属性一样,它给所有其他属性和后代元素建立了一个新的坐标系。你还可以看到在上述例子中,用户坐标系是新建立的-它不是保持像初始用户坐标系和使用viewBox前的视窗坐标系一样。任何<svg>后代会在这个的用户坐标系中定位和确定尺寸,而不是初始坐标系。

    最后一个viewBox的例子和前一个类似,但是它不是切割画布,我们将在viewport里扩展它并看它如何影响图形。我们将声明一个宽高比视窗大的viewBox,并依然保持viewport的宽高比。我们在下一章里讨论不同的宽高比。

    在这个例子中,我们将viewBox的尺寸设为viewport的1.5倍。

    <svg width="800" height="600" viewBox="0 0 1200 900"> <!-- SVG content drawn onto the SVG canvas --> </svg>

    1
    2
    3
    <svg width="800" height="600" viewBox="0 0 1200 900">
        <!-- SVG content drawn onto the SVG canvas -->
    </svg>

    现在用户坐标系会被放大到1200*900。它会被映射到视窗坐标系,用户坐标系中的每一个单位水平方向上等于视窗坐标系中的viewport-width / viewBox-width,竖直方向上等于viewport-height / viewBox-height。这意味着,在这种情况下,每一个用户坐标系中的x-units等于viewport坐标系中的0.66x-units,每个用户y-unit映射成0.66的viewport y-units。

    当然,理解这些最好的方法是把结果视觉化。viewBox被缩放到适应下图所示的viewport。因为图形在画布里基于新的用户坐标系绘制的,而不是视窗坐标系,它看起来比视窗小。新葡亰496net 30

    到目前为止,我们所有的例子的宽高比都和视窗一致。但是如果viewBox中声明的宽高比和视窗中的不一样会发生什么呢?例如,试想我们把视窗的尺寸设为1000*500。宽高比不再和视窗的一样。在例子中使用viewBox="0 0 1000 500"的结果如下图:新葡亰496net 31

    用户坐标系。因此图形在视窗中定位:

    • 整个viewBox适应视窗。
    • 保持viewBox的宽高比。viewBox没有被拉伸来覆盖视窗区域。
    • viewBox在视窗中水平垂直居中。

    这是默认表现。那用什么控制表现呢?如果我们想改变视窗中viewBox的位置呢?这就需要用到preserveAspectRatio属性了。

    坐标系变化

    现在我们已经讨论了所有可能的SVG变换函数,我们深入挖掘视觉部分和对SVG元素添加每个变换的效果。这是SVG变换最重要的部分。因此它们被称为“坐标系统变换”而不仅仅是“元素变换”。

    在这个说明中,transform属性被定义成两个在被添加的元素上建立新用户空间(当前坐标系)之一-viewBox属性是创建新用户空间的两个属性中的另一个。所以到底是什么意思呢?

    这个行为类似于在HTML元素上添加CSS变换-HTML元素坐标系发生了变换,当你把变换组合使用时最明显。虽然在很多方面很相似,HTML和SVG的变换还是有一些不同。

    主要的不同是坐标系。HTML元素的坐标系建立在元素自身智商。然而,在SVG中,元素的坐标系最初是当前坐标系或使用中的用户空间。

    当你在一个SVG元素上添加transform属性,元素获取当前使用的用户坐标系的一个“副本”。你可以当做给发生变换的元素创建一个新“层”,新层上是当前用户坐标系的副本(the viewBox)。

    然后,元素新的当前坐标系被在transform属性中声明的变换函数改变,因此导致元素自身的变换。这看起来好像是元素在变换后的坐标系中重新绘制。

    要理解如何添加SVG变换,让我们从可视化的部分开始。下面图片是我们要研究的SVG画布。

    新葡亰496net 32

    鹦鹉和小狗使我们要变换的元素(组<g>)。

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <g id="parrot"> <!-- shapes and paths forming the parrot --> </g> <g id="dog"> <!-- shapes and paths forming the dog --> </g> </svg>

    1
    2
    3
    4
    5
    6
    7
    8
    <svg width="800" height="800" viewBox="0 0 800 600">
        <g id="parrot">
            <!-- shapes and paths forming the parrot -->
        </g>
        <g id="dog">
            <!-- shapes and paths forming the dog -->
        </g>
    </svg>

    灰色坐标是通过viewBox建立的画布的初始坐标系。为了方便起见,我将不改变初始坐标系-我用一个和视窗相同尺寸的viewBox,如你在上述代码中看到的一样。

    现在我们建立了画布和初始用户空间,让我们开始变换元素。首先让我们把鹦鹉向左移动150单位,向下移动200个单位。

    当然,鹦鹉是由若干路径和形状组成的。只要把transform属性添加到包含它们的组<g>上就行了;这会对整个形状和路径添加变换,鹦鹉会作为一个整体进行变换。查看 article on structuring and grouping SVGs获取更多信息。

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <g id="parrot" transform="translate(150 200)"> <!-- shapes and paths forming the parrot --> </g> <!-- ... --> </svg>

    1
    2
    3
    4
    5
    6
    <svg width="800" height="800" viewBox="0 0 800 600">
        <g id="parrot" transform="translate(150 200)">
            <!-- shapes and paths forming the parrot -->
        </g>
        <!-- ... -->
    </svg>

    下面图片展示了上述变换后的结果。鹦鹉的半透明版本是变换前的初始位置。新葡亰496net 33

    SVG中的变换和HTML元素上CSS中的一样简单直观。我们之前提到在元素上添加transform属性时会在元素上创建一个新的当前用户坐标系。下面图片显示了初始坐标系的“副本”,它在鹦鹉元素发生变换时被建立。注意观察鹦鹉当前坐标系是如何变换的。新葡亰496net 34

    这里需要注意的非常重要的一点是建立在元素上的新的当前坐标系是初始用户坐标系的复制,在里面元素的位置得以保持。这意味着它不是建立在元素边界盒上,或者新的当前坐标系的尺寸受制于元素的尺寸。这就是HTML和SVG坐标系之间的区别。

    建立在变换元素上的新当前坐标系不是建立在元素边界盒上,或者新的当前坐标系的尺寸受制于元素的尺寸。

    我们把小狗变换到画布的右下方时会更加明显。试想我们想要把小狗向右移动50单位,向下移动50单位。这就是狗的最初的坐标以及新的当前坐标系(也因为狗改变)会如何显示。注意小狗的新的坐标系统的原点不在狗边界盒子的左上角。另外注意狗和它新的坐标系看起来它们好像移动到画布新的一层上。新葡亰496net 35

    现在我们试一试其他事情。不再移动,试着缩放。我们将鹦鹉放大到两倍尺寸:

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <g id="parrot" transform="scale(2)"> <!-- shapes and paths forming the parrot --> </g> <!-- ... --> </svg>

    1
    2
    3
    4
    5
    6
    <svg width="800" height="800" viewBox="0 0 800 600">
        <g id="parrot" transform="scale(2)">
            <!-- shapes and paths forming the parrot -->
        </g>
        <!-- ... -->
    </svg>

    放缩SVG元素和放缩HTML元素的结果不一样。缩放后SVG元素的在视窗中的位置随着缩放改变。下面图片展示了把鹦鹉放大到两倍时的结果。注意初始位置和尺寸,以及最终位置和尺寸。新葡亰496net 36

    从上面图片中我们可以注意到不只鹦鹉的尺寸(宽和高)变成了两倍,鹦鹉的坐标(xy)也乘以了缩放因子(这里是两倍)。

    这个结果的原因我们之前已经提到了:元素当前坐标系发生变化,鹦鹉在新系统中绘制。所以,在这个例子中,当前坐标系被缩放。这个效果类似于使用viewBox = "0 0 400 300",等于“放大”了坐标系,因此把里面的内容放大到双倍尺寸(如果你还没有读过请查看这个系列的第一部分)。

    所以,如果我们把坐标系变换形象化来展现当前变换系统中的鹦鹉,我们会得到以下结果:新葡亰496net 37

    鹦鹉的新的当前坐标系统被缩放,同时“放大”鹦鹉。注意,在它当前的坐标系中,鹦鹉没有重新定位-只有缩放坐标系统才会导致它在视窗中重定位。鹦鹉在新的缩放后的系统中按初始的xy坐标被重绘。

    让我们尝使用不同因子在两个方向上缩放鹦鹉。如果我们添加transform="scale(2 0.5)缩放鹦鹉,我们把宽度变为两倍高度为原来的一半。效果和添加viewBox="0 0 400 1200"类似。新葡亰496net 38

    注意一下鹦鹉在倾斜后的坐标系中的位置,并且把它和初始系统(半透明的鹦鹉)中的位置做比较:xy位置坐标保持不变。

    在SVG中倾斜元素也导致元素被“移动”,因为它当前的坐标系统被倾斜了。

    试想我们使用skewX函数沿x轴给一只狗增加一个倾斜变化。我们在垂直方向上把狗倾斜了25度。

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <!-- ... --> <g id="dog" transform="skewX(25)"> <!-- shapes and paths forming the dog --> </g> </svg>

    1
    2
    3
    4
    5
    6
    <svg width="800" height="800" viewBox="0 0 800 600">
        <!-- ... -->
        <g id="dog" transform="skewX(25)">
            <!-- shapes and paths forming the dog -->
        </g>
    </svg>

    下列图片展示了对小狗添加倾斜变换的结果。新葡亰496net 39

    注意到狗的位置对比初始位置也改变了,因为它的坐标系也被倾斜了。

    下面的图片展示了同样角度的情况下使用skewY()而不是skewX倾斜狗的情况:新葡亰496net 40

    最后,让我们尝试旋转鹦鹉。旋转默认的中心是当前用户坐标系的左上角。新的建立在旋转元素上的当前系统也被旋转了。在下面的例子中,我们将把鹦鹉旋转45度。旋转方向为顺时针。

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <g id="parrot" transform="rotate(45)"> <!-- shapes and paths forming the parrot --> </g> <!-- ... --> </svg>

    1
    2
    3
    4
    5
    6
    <svg width="800" height="800" viewBox="0 0 800 600">
        <g id="parrot" transform="rotate(45)">
            <!-- shapes and paths forming the parrot -->
        </g>
        <!-- ... -->
    </svg>

    添加上述变换的结果如下:新葡亰496net 41

    你很可能想要围绕默认坐标系原点之外的点来旋转一个元素。在transform属性中使用rotate()函数,你可以声明这个点。试想在这个例子中我们想按照它自己的中心旋转这个鹦鹉。根据鹦鹉的宽、高以及位置,我精确计算出它的中心在(150,170)。这个鹦鹉可以围着它的中心旋转。

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <g id="parrot" transform="rotate(45 150 170)"> <!-- shapes and paths forming the parrot --> </g> <!-- ... --> </svg>

    1
    2
    3
    4
    5
    6
    <svg width="800" height="800" viewBox="0 0 800 600">
        <g id="parrot" transform="rotate(45 150 170)">
            <!-- shapes and paths forming the parrot -->
        </g>
        <!-- ... -->
    </svg>

    在这个时候,这只鹦鹉会被旋转并且看起来如下:新葡亰496net 42

    我们说变换添加在坐标系上,因此,元素最终被影响并且发生变换。那么究竟如何改变旋转中心工作在坐标系的原点(0,0)的点呢?

    当你改变中心或者旋转时,坐标系被变换或者旋转特定角度,然后再次根据声明的旋转中心产生特定变换。在这个例子中:

    XHTML

    <g id="parrot" transform="rotate(45 150 170)">

    1
    <g id="parrot" transform="rotate(45 150 170)">

    被浏览器当成一系列的移动和旋转等同于:

    XHTML

    <g id="parrot" transform="translate(150 170) rotate(45) translate(-150 -170)">

    1
    <g id="parrot" transform="translate(150 170) rotate(45) translate(-150 -170)">

    当前坐标系变换到你想要的中心店。然后旋转声明的角度。最终系统被负值变换。上述添加到系统的变换如下:新葡亰496net 43

    在我们进行下一部分讨论嵌套和组合变换前,我想请大家注意建立在变换元素上的当前用户坐标系是独立于建立在其他变换元素之上的其他坐标系的。下列图片展示了建立在狗和鹦鹉上的两个坐标系,以及它们之间是如何保持独立的。新葡亰496net 44

    另外注意每个当前坐标系仍然处于在外层<svg>容器中使用viewBox属性建立的画布的主要坐标系中。任何添加到viewBox上的变换会影响整个画布以及所有里面的元素,不管它们是否建立了自己的坐标系。

    例如,以下是把整个画布的用户空间从viewBox="0 0 800 600"改成 viewBox="0 0 600 450"的结果。整个画布被缩放,保持任何添加到独立元素上的变换。新葡亰496net 45

     

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

    七、结束语

    本文介绍的内容实际上都还是非常基本的。实际SVG应用的时候,可能是多个变换参杂在一起,所以,如果本文介绍的几个基本变换都没搞清楚,到时候,想必是想破脑袋都不明白怎么元素跑这里了,怎么变成这样了!

    本文的这些知识点虽然基本,但是相当重要的。再加上,不同的变换方法的语法细节还不一样。有的自带偏移,有的需要手动偏移等等;不同变换的前后位置不同,甚至同一变换分开连续变换和一次性变换的结果都不一样等等;都要求大家要细心耐心阅读。

    本文内容和结构参考自:Transforms on SVG Elements. 但要比原文要精炼很多,同时,每一个变换都有亲自实践认证,因此,从品质上讲,可能还要略高一筹。

    对了,矩阵matrix没有细说过,这个可以参考我之前的文章:“理解CSS3 transform中的Matrix(矩阵)”,一脉相承的。

    我也是初学者,出错在所难免,欢迎指正!

    感谢阅读,欢迎交流!新葡亰496net 46

    1 赞 收藏 评论

    新葡亰496net 47

    preserveAspectRatio属性

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

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

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

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

    嵌套和组合变换

    很多时候你可能想要在一个元素上添加多个变换。添加多个变换意味着“组合”变换。

    当变换组合时,最重要的是意识到,和HTML元素变换一样,当这个系统发生了之前的变换后在添加下一个变换到坐标系中。

    例如,如果你要在一个元素上添加旋转,接下来移动,移动变换会根据新的坐标系统,而不是初始的没有旋转时的系统。

    下面了例子就是做了这件事。我们先添加旋转,然后沿x轴使用transform="rotate(45 150 170) translate(200)"把鹦鹉移动200个单位。新葡亰496net 50

    取决于最终的位置和变换,你可以根据需要组合变换。总是记住坐标系。

    注意当你倾斜一个元素-以及它的坐标系统-坐标系统不再是最初的那个,坐标系不再会按照最初的来计算-它将会是倾斜后的坐标系。简单来说,这意味着坐标系原点不再是90度的角,新的坐标会根据新的角度来计算。

    当变换元素的子元素也需要变换时会发生变换嵌套。添加到子元素上的变换会累积父元素上添加的变换和它本身的变换。

    所以,效果上来说,嵌套变化类似于组合:唯一区别是不像在一个元素上添加一系列的变化,它自动从父元素上获得变换,最后执行添加在它自身的变换,就像我们在上面添加的变换一样-一个接一个。

    这对于你想要根据另外一个元素变换一个元素时尤其有用。例如,试想你想要给小狗的尾巴设定一个动画。这个尾巴是#dog组的后代。

    XHTML

    <svg width="800" height="800" viewBox="0 0 800 600"> <!-- ... --> <g id="dog" transform="translate(..)"> <!-- shapes and paths forming the dog --> <g id="head"> <!-- .. --> </g> <g id="body" transform="rotate(.. .. ..)"> <path id="tail" d="..." transform="rotate(..)"> <!-- animateTransform here --> </path> <g id="legs"> <!-- ... --> </g> </g> </g> </svg>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <svg width="800" height="800" viewBox="0 0 800 600">
        <!-- ... -->
        <g id="dog" transform="translate(..)">
            <!-- shapes and paths forming the dog -->
            <g id="head">
                <!-- .. -->
            </g>
            <g id="body" transform="rotate(.. .. ..)">
                <path id="tail" d="..." transform="rotate(..)">
                    <!-- animateTransform here -->
                </path>
                <g id="legs">
                    <!-- ... -->
                </g>
            </g>
        </g>
    </svg>

    试想我们变换dog组;围绕某一点把它的身体旋转一定角度,然后我们想要再把尾巴旋转一定角度。

    当尾巴被旋转后,它从祖先(#body)身上“继承”了变换坐标系,也从祖先(#dog)身上继承了变换坐标系,然后旋转(和#body组一样的旋转)然后在发生自身的旋转。这里添加的一系列变换的效果类似于我们之前在上述组合变换例子中解释的。

    所以,你看,在#tail上嵌套变换实际上和组合变换有一样的效果。

     

    默认情况下,视窗坐标系与用户坐标系是重合的,但是这里需要注意,视窗坐标系属于的是创建视窗的元素,视窗坐标系确定好以后,整个视窗的坐标基调就确定了。但是用户坐标系是属于每个图形元素的,只要图形进行了坐标变换,就会创建新的用户坐标系,这个元素中所有的坐标和尺寸都使用这个新的用户坐标系。

    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。下面是每个值的定义和含义:

    使用CSS属性变换SVGs

    在SVG2中,transform属性简称transform属性;因为SVG变换已经被引入CSS3变换规范中。后者结合了SVG变化,CSS2 2D变换和CSS 3D变换规范,并且把类似transform-origin 和 3D transformations引入了SVG。

    声明在CSS变换规范中的CSS变换属性可以被添加到SVG元素上。然而,transform属性函数值需要遵循CSS规范中的语法声明:函数参数必须逗号隔开-空格隔开是不允许的,但是你可以在逗号前后引用一两个空格;rotate()函数不接受<cx><cy>值-旋转中心使用transform-origin属性声明。另外,CSS变换函数接受角度和坐标单位,例如角度的rad(radians)和坐标的px,em等。

    使用CSS来旋转一个SVG元素看起来如下:

    CSS

    #parrot { transform-origin: 50% 50%; /* center of rotation is set to the center of the element */ transform: rotate(45deg); }

    1
    2
    3
    4
    #parrot {
        transform-origin: 50% 50%; /* center of rotation is set to the center of the element */
        transform: rotate(45deg);
    }

    SVG元素也可以使用CSS 3D变换在三维空间中变换。依然要注意坐标系,然而,不同于建立在HTML元素上的坐标系。这意味着3D旋转看起来也不同除非改变旋转中心。

    CSS

    #SVGel { transform: perspective(800px) rotate3d(1, 1, 0, 45deg); }

    1
    2
    3
    #SVGel {
        transform: perspective(800px) rotate3d(1, 1, 0, 45deg);
    }

    因为通过CSS来变换SVG元素非常类似于通过CSS来变换HTML元素-语法层面-在这篇文章中我将跳过这个部分。

    另外,在写这篇文章的时候,在一些浏览器中实现一些特性是不可能的。因为浏览器支持改变很快,我建议你实验一下这些属性来决定哪些可以工作哪些不可以,决定什么现在可以用什么不可以。

    注意一旦CSS变换可以完全实现在SVG上,我依然建议你使用CSS变换函数语法即使你用transform属性的形式添加变换。也就是说,上面提到的transform属性函数的语法还是有效的。

     

    简单点说:视窗坐标系描述了视窗中所有元素的初始坐标概况,用户坐标系描述了每个元素的坐标概况,默认情况下,所有元素都使用默认的与视窗坐标系重合的那个用户坐标系。

    meet(默认值)

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

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

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

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

    动画transform

    SVG变换可以变成动画,就像CSS变换一样。如果你使用CSS transform属性来产生SVG变换,你可以像在HTML元素上创建CSS变换动画一样使用CSS动画把这些变换变成动画。

    SVGtransform属性可以用SVG<animateTransform>元素来做成动画。<animateTransform>元素是SVG中三个用来给不同的SVG属性设置动画的元素之一。

    关于<animateTransform>元素的详细内容不在本片文章的讨论范围内。阅读我写的关于不同SVG动画元素的文章,包括<animateTransform>

     

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

    slice

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

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

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

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

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

    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"新葡亰496net 52

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

    对齐的取值包括:

    最后的话

    学习SVGs一开始可能非常困惑,如果对于坐标系变换里的内容不是很清楚,尤其是如果你带着CSS HTML变换的背景知识,自然而然希望SVG元素和HTML元素的变换一样。

    然而,一旦你意识到它们的工作方式,你能更好得控制SVG画布,并且轻易操纵元素。

    这一系列的最后部分,我将讨论嵌套SVGs和建立新的viewports和viewboxes。敬请关注!

    1 赞 1 收藏 评论

    新葡亰496net 53

      SVG的视窗位置一般是由CSS指定,尺寸由SVG元素的属性width和height设置,但是如果SVG是存储在embedded对象中(例如object元素,或者其他SVG元素),而且包含SVG的文档是用CSS或者XSL格式化的,并且这些外围对象的CSS或者其他指定尺寸的值已经可以计算出视窗的尺寸了,则此时会使用外围对象的尺寸。

    视窗变换 - viewBox属性

    none

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

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

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

          这里需要区分视窗,视窗坐标系,用户坐标系的概念:

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

    xMinYMin

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

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

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

    xMinYMid

    • 强制统一缩放。
    • 视窗X轴的最小值对齐元素viewBox<min-x>
    • 视窗Y轴的中间值来对齐元素的viewBox的中间值。
    • 新葡亰496net,把这个类比为backrgound-position: 0% 50%;

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

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

    xMinYMax

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

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

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

    xMidYMin

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

          默认情况下,视窗坐标系与用户坐标系是重合的,但是这里需要注意,视窗坐标系属于的是创建视窗的元素,视窗坐标系确定好以后,整个视窗的坐标基调就确定了。但是用户坐标系是属于每个图形元素的,只要图形进行了坐标变换,就会创建新的用户坐标系,这个元素中所有的坐标和尺寸都使用这个新的用户坐标系。

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

    xMidYMid (默认值)

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

          简单点说:视窗坐标系描述了视窗中所有元素的初始坐标概况,用户坐标系描述了每个元素的坐标概况,默认情况下,所有元素都使用默认的与视窗坐标系重合的那个用户坐标系。

    代码如下:

    xMidYMax

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

     

    <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>

    xMaxYMin

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

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

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

    xMaxYMid

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

     

    代码如下:

    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内。新葡亰496net 54

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

    当然,不同的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-*轴和视窗轴的中间对齐。新葡亰496net 56

    视窗变换 - viewBox属性

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

    互动演示

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

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

    在线案例

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

    2 赞 1 收藏 评论

    新葡亰496net 58

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

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

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

    代码如下:

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

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

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

    上面的例子绘制的图中,视窗坐标系的单位被缩小,所以两个矩形都缩小了。

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

    在日常工作中,我们经常需要完成的一个任务就是缩放一组图形,让它适应它的父容器。我们可以通过设置viewBox属性达到这个目的。

    <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>

    能建立新视窗的元素 任何时候,我们都可以嵌套视窗。创建新的视窗的时候,也会创建新的视窗坐标系和用户坐标系,当然也包括裁减路径也会创建新的。下列是能建立新视窗的元素列表:
    svg:svg支持嵌套。
    symbol:当被use元素实例化的时候创建新的视窗。

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

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

     

    保持缩放的比例 - preserveAspectRatio属性 有些时候,特别是当使用viewBox的时候,我们期望图形占据整个视窗,而不是两个方向上按相同的比例缩放。而有些时候,我们却是希望图形两个方向是按照固定的比例缩放的。使用属性preserveAspectRatio就可以达到控制这个的目的。
    这个属性是所有能建立一个新视窗的元素,再加上image,marker,pattern,view元素都有的。而且preserveAspectRatio属性只有在该元素设置了viewBox以后才会起作用。如果没有设置viewBox,则preserveAspectRatio属性会被忽略。
    属性的语法如下:preserveAspectRatio="[defer] <align> [<meetOrSlice>]" 注意3个参数之间需要使用空格隔开。
    defer:可选参数,只对image元素有效,如果image元素中preserveAspectRatio属性的值以"defer"开头,则意味着image元素使用引用图片的缩放比例,如果被引用的图片没有缩放比例,则忽略"defer"。所有其他的元素都忽略这个字符串。
    align:该参数决定了统一缩放的对齐方式,可以取下列值:
      none - 不强制统一缩放,这样图形能完整填充整个viewport。
      xMinYMin - 强制统一缩放,并且把viewBox中设置的<min-x>和<min-y>对齐到viewport的最小X值和Y值处。
      xMidYMin - 强制统一缩放,并且把vivewBox中X方向上的中点对齐到viewport的X方向中点处,简言之就是X方向中点对齐,Y方向与上面相同。
      xMaxYMin - 强制统一缩放,并且把viewBox中设置的<min-x> <width>对齐到viewport的X值最大处。
      类似的还有其他类型的值:xMinYMid,xMidYMid,xMaxYMid,xMinYMax,xMidYMax,xMaxYMax。这些组合的含义与上面的几种情况类似。
    meetOrSlice:可选参数,可以去下列值:
      meet - 默认值,统一缩放图形,让图形全部显示在viewport中。
      slice - 统一缩放图形,让图形充满viewport,超出的部分被剪裁掉。

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

    下图诠释了各种填充的效果:

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

    新葡亰496net 59

     

    用户坐标系的变换 - transform属性 该类型变换是通过设置元素的transform属性来指定的。这里需要注意,transform属性设置的元素的变换,只影响该元素及其子元素,与别的元素无关,不影响别的元素。

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

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

          上面的例子绘制的图中,视窗坐标系的单位被缩小,所以两个矩形都缩小了。

    代码如下:

         在日常工作中,我们经常需要完成的一个任务就是缩放一组图形,让它适应它的父容器。我们可以通过设置viewBox属性达到这个目的。

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

     

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

    能建立新视窗的元素       任何时候,我们都可以嵌套视窗。创建新的视窗的时候,也会创建新的视窗坐标系和用户坐标系,当然也包括裁减路径也会创建新的。下列是能建立新视窗的元素列表:
    svg:svg支持嵌套。
    symbol:当被use元素实例化的时候创建新的视窗。

    旋转 - rotate 旋转一个元素也是一个很常见的任务,我们可以使用rotate变换实现,该变换需要传入旋转的角度参数。看例子:

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

    代码如下:

     

    <rect x="20" y="20" width="20" height="20" transform="rotate(45)" />

    保持缩放的比例 - preserveAspectRatio属性       有些时候,特别是当使用viewBox的时候,我们期望图形占据整个视窗,而不是两个方向上按相同的比例缩放。而有些时候,我们却是希望图形两个方向是按照固定的比例缩放的。使用属性preserveAspectRatio就可以达到控制这个的目的。
          这个属性是所有能建立一个新视窗的元素,再加上image,marker,pattern,view元素都有的。而且preserveAspectRatio属性只有在该元素设置了viewBox以后才会起作用。如果没有设置viewBox,则preserveAspectRatio属性会被忽略。
          属性的语法如下:preserveAspectRatio="[defer] <align> [<meetOrSlice>]" 注意3个参数之间需要使用空格隔开。
    defer:可选参数,只对image元素有效,如果image元素中preserveAspectRatio属性的值以"defer"开头,则意味着image元素使用引用图片的缩放比例,如果被引用的图片没有缩放比例,则忽略"defer"。所有其他的元素都忽略这个字符串。
    align:该参数决定了统一缩放的对齐方式,可以取下列值:
      none - 不强制统一缩放,这样图形能完整填充整个viewport。
      xMinYMin - 强制统一缩放,并且把viewBox中设置的<min-x>和<min-y>对齐到viewport的最小X值和Y值处。
      xMidYMin - 强制统一缩放,并且把vivewBox中X方向上的中点对齐到viewport的X方向中点处,简言之就是X方向中点对齐,Y方向与上面相同。
      xMaxYMin - 强制统一缩放,并且把viewBox中设置的<min-x> <width>对齐到viewport的X值最大处。
      类似的还有其他类型的值:xMinYMid,xMidYMid,xMaxYMid,xMinYMax,xMidYMax,xMaxYMax。这些组合的含义与上面的几种情况类似。
    meetOrSlice:可选参数,可以去下列值:
    新葡亰496net:视窗坐标系与用户坐标系及调换概述,transform坐标转变。  meet - 默认值,统一缩放图形,让图形全部显示在viewport中。
      slice - 统一缩放图形,让图形充满viewport,超出的部分被剪裁掉。

    这个例子会显示一个旋转45度的矩形。有几点注意:
    1.这里的变换是以角度值为参数的。
    2.旋转指的是相对于x轴的旋转。
    3.旋转是围绕用户坐标系的原点(0,0)展开的。

          下图诠释了各种填充的效果:

    倾斜 - skew transform还支持倾斜变换,可以是沿着x轴的(左右倾斜,正角度为向右倾斜,其实是倾斜了y轴),或者是沿着y轴的(上下倾斜,正角度为向下倾斜,其实是倾斜了x轴)倾斜;该变换需要传入一个角度参数,这个角度参数会决定倾斜的角度。看下面的例子:

    新葡亰496net 60

    代码如下:

    用户坐标系的变换 - transform属性       该类型变换是通过设置元素的transform属性来指定的。这里需要注意,transform属性设置的元素的变换,只影响该元素及其子元素,与别的元素无关,不影响别的元素。

    <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>

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

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

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

    缩放 - scale 缩放对象由缩放变换完成,该变换接受2个参数,分别指定在水平和竖直上的缩放比例,如果第二个参数省略则与第一个参数取相同的值。看下面的例子:

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

    代码如下:

      旋转 - rotate       旋转一个元素也是一个很常见的任务,我们可以使用rotate变换实现,该变换需要传入旋转的角度参数。看例子:

    <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>

    <rect x="20" y="20" width="20" height="20" transform="rotate(45)" />

    变换矩阵 - matrix 学过图形学的都知道,所有的变换其实都是由矩阵表征的,所以上面的变换其实都可以用一个3*3矩阵去表示:

          这个例子会显示一个旋转45度的矩形。有几点注意:
    1.这里的变换是以角度值为参数的。
    2.旋转指的是相对于x轴的旋转。
    3.旋转是围绕用户坐标系的原点(0,0)展开的。

    代码如下:

      倾斜 - skew       transform还支持倾斜变换,可以是沿着x轴的(左右倾斜,正角度为向右倾斜,其实是倾斜了y轴),或者是沿着y轴的(上下倾斜,正角度为向下倾斜,其实是倾斜了x轴)倾斜;该变换需要传入一个角度参数,这个角度参数会决定倾斜的角度。看下面的例子:

    a c e
    b d f
    0 0 1

    新葡亰496net 61

    由于只有6个值用到了,所以也简写成[a b c d e f]。把matrix(a,b,c,d,e,f)赋给transfrom就可以实施相应的变换。变换会把坐标和长度都转换成新的尺寸。上面各种变换对应的矩阵如下:

    <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>

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

    新葡亰496net 62

    代码如下:

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

    1 0 tx
    0 1 ty
    0 0 1

      缩放 - scale       缩放对象由缩放变换完成,该变换接受2个参数,分别指定在水平和竖直上的缩放比例,如果第二个参数省略则与第一个参数取相同的值。看下面的例子:

    缩放变换[sx 0 0 sy 0 0]:

    <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>

    代码如下:

      变换矩阵 - matrix       学过图形学的都知道,所有的变换其实都是由矩阵表征的,所以上面的变换其实都可以用一个3*3矩阵去表示:

    sx 0 0
    0 sy 0
    0 0 1

    a c e
    b d f
    0 0 1

    旋转变换[cos(a) sin(a) -sin(a) cos(a) 0 0]:

          由于只有6个值用到了,所以也简写成[a b c d e f]。把matrix(a,b,c,d,e,f)赋给transfrom就可以实施相应的变换。变换会把坐标和长度都转换成新的尺寸。上面各种变换对应的矩阵如下:

    代码如下:

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

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

    1 0 tx       
    0 1 ty
    0 0 1

    沿X轴的倾斜[1 0 tan(a) 1 0 0]:

    缩放变换[sx 0 0 sy 0 0]:

    代码如下:

    sx 0 0
    0 sy 0
    0  0 1

    1 tan(a) 0
    0 1 0
    0 0 1

    旋转变换[cos(a) sin(a) -sin(a) cos(a) 0 0]:

    沿Y轴的倾斜[1 tan(a) 0 1 0 0]:

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

    代码如下:

    沿X轴的倾斜[1 0 tan(a) 1 0 0]:

    11 0
    tan(a) 1 0
    00 1

    1 tan(a) 0
    0   1    0
    0   0    1

    变换本质 前面我们总结canvas的时候,我们知道各种变换都是作用在用户坐标系上的。在SVG中,所有的变换也都是针对两个坐标系(本质上都是"用户坐标系")的。当给容器对象或图形对象指定"transform"属性,或者给"svg,symbol,marker,pattern,view"指定"viewBox"属性以后,SVG会根据当前的用户坐标系统进行变换,去创建新的用户坐标系,并作用于当前的对象以及它的子对象。该对象中指定的坐标和长度的单位不再是1:1的对应到外围的坐标系,而是随着变形,转换到新的用户坐标系中;这个新的用户坐标系是只作用于当前的元素及其子元素。

    沿Y轴的倾斜[1 tan(a) 0 1 0 0]:

    变换链 transform属性支持设置多个变换,这些变换只要中间用空格分开,然后一起放到属性中就可以了。执行效果跟按顺序独立执行这些变换是一样的。

    1      1 0
    tan(a) 1 0
    0      0 1

    代码如下:

     

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

    变换本质       前面我们总结canvas的时候,我们知道各种变换都是作用在用户坐标系上的。在SVG中,所有的变换也都是针对两个坐标系(本质上都是"用户坐标系")的。当给容器对象或图形对象指定"transform"属性,或者给"svg,symbol,marker,pattern,view"指定"viewBox"属性以后,SVG会根据当前的用户坐标系统进行变换,去创建新的用户坐标系,并作用于当前的对象以及它的子对象。该对象中指定的坐标和长度的单位不再是1:1的对应到外围的坐标系,而是随着变形,转换到新的用户坐标系中;这个新的用户坐标系是只作用于当前的元素及其子元素。

    上面的效果与下面的一样:

     

    代码如下:

    变换链       transform属性支持设置多个变换,这些变换只要中间用空格分开,然后一起放到属性中就可以了。执行效果跟按顺序独立执行这些变换是一样的。

    <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>

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

    单位 最后说一下单位,任何坐标和长度都可以带和不带单位。
    不带单位的情况

    上面的效果与下面的一样:

    不带单位的值被认为带的是"用户单位",就是当前用户坐标系的单位值。
    带单位的情况

    新葡亰496net 63

    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元素的width和height没有指定单位(也就是"用户单位"),则这些值会被认为单位是px。

    新葡亰496net 64

    这一篇比较拗口,其实只要记住“图形元素的坐标和长度指的是,经过视窗坐标系变换和用户坐标系变换双重变换后,新用户坐标系的坐标和长度”就可以了

     

    实用参考: 脚本索引:
    开发中心:
    热门参考:
    官方文档:

    单位       最后说一下单位,任何坐标和长度都可以带和不带单位。
      不带单位的情况

          不带单位的值被认为带的是"用户单位",就是当前用户坐标系的单位值。
      带单位的情况

          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。

          如果最外层的SVG元素的width和height没有指定单位(也就是"用户单位"),则这些值会被认为单位是px。

     

          这一篇比较拗口,其实只要记住“图形元素的坐标和长度指的是,经过视窗坐标系变换和用户坐标系变换双重变换后,新用户坐标系的坐标和长度”就可以了

     

    本文由新葡亰496net发布于新葡亰官网,转载请注明出处:新葡亰496net:视窗坐标系与用户坐标系及调换概

    关键词: