山东seo网站/青岛seo推广专员
定义SVG
定义一个SVG画布,可以在其中创建各种形状,诸如矩形<rect>
、圆形<circle>
、直线<line>
、路径<path>
、多边形<polygon>
等。
<svg width="800" height="600">
<circle r="200" cx="200" cy="200" fill="#20B2AA"></circle>
</svg>
上面的代码在宽为800、高为600的SVG画布上,绘制了一个原点在(200,200)、半径为200的圆形,如下图。
SVG的单位默认为px,也可以设置为em、ex、pt、pc、cm、mm、in和百分比。
理解视窗和坐标系
我们利用上图来理解SVG的视窗,创建一个SVG就创造了一个无穷大的世界。
在这个无穷大的世界中规定一个区域,用来绘制不同的图形,我们把这个区域叫做SVG的视窗(viewport)。width和height属性用来定义视窗的范围。
事实上,我们可以在SVG世界中的任何地方绘制图形,但是只有在视窗范围内的图形可以被观察到。上图中蓝色和红色的形状可以完全看到,而绿色的圆只能看到一部分。
在同一页面中你也可以定义多个SVG世界,这个时候你必须掌握SVG坐标系的知识,不然你的世界将一团糟,你明明画了一个图形,但是在页面中看不到它!
SVG世界中存在几个坐标系:
-
世界坐标系:定义了一个SVG元素就定义了一个世界坐标系;
-
用户坐标系:就是画布的坐标系,以视窗左上角为原点,用于定位图形;
-
前驱坐标系:父容器的坐标系,图形进行坐标变换都是基于前驱坐标系;
-
自身坐标系:每个图形或者分组都拥有自己的坐标系,用于定义自己的一些图形属性,例如宽高。
对本文第一段代码做一些变化,理解坐标系的作用:
<svg width="800" height="600">
<g transform="translate(100,0)">
<circle id="mycircle" r="200" cx="200" cy="200" fill="#20B2AA"></circle>
</g>
</svg>
以上代码中,g分组相对于用户坐标系向右平移了100px,circle相对于前驱坐标系向右平移了100px,总体表现为circle相对于原来的位置向右平移了200px,如下图所示。
如果把以上g元素改成svg,也就是在大的svg中嵌套了另一个svg,这个时候需要注意的是在新的svg元素中添加的所有元素的坐标,都是相对于新的svg的用户坐标系!这个时候千万不要再依照原来的SVG坐标系了!
比如,页面上的圆位于(300,200)的位置,当你想在圆外面包裹一层宽高为400px的svg,若是你没有重新设置圆的位置,你会得到令人崩溃的结果!此时设置圆的位置为(200,200),你才会破涕为笑!
理解SVG的viewBox属性
上面讲到的用户坐标系,还没有发挥真正厉害的作用,没有定义svg元素的viewBox属性,用户坐标系充其量就是一个普通的视窗坐标系。
先来看一个小例子,还是在本文第一段代码的基础上,往svg元素中添加viewBox属性:
<svg width="800" height="600" viewBox="0 0 400 300">
<circle r="200" cx="200" cy="200" fill="#20B2AA"></circle>
</svg>
设置viewBox="0 0 400 300"
,我们得到这样的图形:
可以看到,圆形放大了一倍,超出SVG视窗的部分也被剪裁了。这是为什么?viewBox到底是什么鬼东西?
别急,先看下viewBox的四个值是什么。
viewBox:" <min-x> <min-y> width height "
前面说了,SVG提供一个可观察的窗口,我们可以把viewBox想象成用户自定义的一个画布,左上角的坐标是(<min-x>
, <min-y>
),宽高为viewBox后两个参数width和height。
重点来了!一旦定义了viewBox属性,就会进行下面两个步骤:
-
SVG中的图形根据定义的宽高在画布上画出来
-
viewBox会进行拉伸铺满SVG的整个视窗
就像下图展示的这样:
这种情况下,一个用户单位等于两个视窗单位,图形会被放大一倍。同样的,如果viewBox="0 0 1600 1200"
,那么两个用户单位等于一个视窗单位,图形会被缩小一倍。
如果viewBox和svg的宽高比不一致会发生什么情况呢?实践出真知,来看一下。
总结一下,当宽高比不一致的时候,viewBox画布以原有的宽高比拉伸直到一个方向上铺满SVG视窗,然后居中排列。
那么viewBox画布的左上角坐标改变了又如何呢?再实践一下!
可以看到,viewBox画布先根据width和height两个值进行了我们之前说的两个步骤:创建图形、拉伸画布,再根据拉伸的比例向坐标轴正方向移动100*600/500px
。
要指出的是,当<min-x>, <min-y>
为正值时,图形向坐标轴负方向(左上角)移动,当<min-x>, <min-y>
为负值时,图形向坐标轴正方向(右下角)移动。
以上变化一直保持原图形的宽高比以适应视窗大小,那么如果不想保持宽高比,只想使画布宽高都铺满视窗怎么办?
我们需要用到preserveAspectRatio属性,这个属性在设置了viewBox属性,并且viewBox和SVG的宽高比不一致的情况下才起作用。
preserveAspectRatio = defer? <align> <meetOrSlice>
defer
声明是对<image>
元素起作用,这里不作讨论。
<aline>
值有很多可选值,当preserveAspectRatio = “none”
时,图形会铺满整个SVG视窗,失去原有的宽高比。
<aline>
的其他值:xMinYMin、xMinYMax、xMaxYMin、xMidYMid(默认)、xMidYMin、xMidYMax、xMinYMid、xMaxYMid(<meetOrSlice>
仅在这些值下生效,meet为默认值)
一张图理解这些值
图上标注的x-
、y-
是viewBox的六个坐标值,Min
和Max
分别代表最小坐标值和最大坐标值,Mid
代表画布的中点值。
同样的,SVG视窗也拥有这六个值。比如上图中,preserveAspectRatio = “xMaxYMid”
,代表viewBox画布和SVG视窗在x方向上以最大坐标值对齐,也就是右对齐,y方向上以中点值对齐,也就是居中对齐。其他值类似。
<meetOrSlice>
声明画布是否完全铺满整个视窗,默认值meet让视窗包含画布,slice是要让画布完全铺满视窗。下图可以看到slice值的作用。
总结
SVG世界纷繁复杂,理解了视窗和坐标系的概念,才能以不变应万变。