https://github.com/oreillymedia/svg-essentials-examples
栅格及矢量
栅格 | 矢量 | |
---|---|---|
本质 | 描述哪个方格应该填充什么颜色。 | 描述要绘制从某个点到另一个点的直线或曲线。 |
特点 | 不关心内容是什么。 | 是XML程序,信息被存储为纯文本,所以具有开放性、可移植性及可交互性。所有的文本都是可搜索的,可缩放而不损失图像质量。 |
适用场景 | 适合存储照片。 | 适合CAD等需要精确测量和放大绘图以便查看细节的程序。 |
我是一只猫
<?xml version='1.0'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width='140' height='170'
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink'
>
<title>Cat</title>
<desc>Stick Figure of a Cat</desc>
<circle cx='70' cy='95' r='50' style='stroke: black; fill: none' />
<circle cx='55' cy='80' r='5' stroke='black' fill='#339933' />
<circle cx='85' cy='80' r='5' stroke='black' fill='#339933' />
<g id='whiskers'>
<line x1='75' y1='95' x2='135' y2='85' style='stroke: black;' />
<line x1='75' y1='95' x2='135' y2='105' style='stroke: black;' />
</g>
<use xlink:href='#whiskers' transform='scale(-1 1) translate(-140 0)' />
<polyline points='108 62, 90 10, 70 45, 50 10, 32 62' style="stroke: black; fill: none;" />
<polyline points='35 110, 45 120, 95 120, 105 110' style="stroke: black; fill: none;" />
<path d='M 75 90 L 65 90 A 5 10 0 0 0 75 90' style="stroke: black; fill: ffcccc;" />
<text x='60' y='165' style='font-family:sans-serif; font-size: 14pt; stroke: none; fill: black;'>Cat</text>
</svg>
- 根元素
<svg>
以像素为单位定义了整个图像的 width 和 height, 还通过 xmlns 属性定义了 SVG 的命名空间。- <title>
的内容可被阅读器显示在标题栏上或者是作为鼠标指针指向图像时的提示,<desc>
允许为图像定义完整的描述信息。- 坐标原点(0,0)为图像的左上角。
<circle>
的属性指定中心点坐标(cx cy)及半径 r。<line>
被包装在分组元素里面,通过指定起点(x1,y1)及终点(x2, y2)的方式绘制一条``直线。 <use>
复用分组并变换坐标系统,首先在 scale 变换中对 x 坐标乘以-1,翻转了坐标系统。这意味着原始坐标系统中的点 (75,95) 现在位于 (-75,95) 。在新的坐标系统中,向左移动会使坐标增大。意味着必须将坐标系统向右translate(平移)140个像素(负值,才能将它们移到目标位置。<polyline>
接受 (x,y) 代表一个点作为 points 属性的值,用来绘制耳朵和嘴这样的折线。<path>
绘制鼻子,移动到坐标 (75,90),绘制一条到(65,90)的直线,然后以x半径为5,y半径为10绘制一个椭圆,最后回到坐标(75,90)处。<text>
是一个容器元素,内容是你想要显示的文本,(x,y)用于指定文本的位置。
集成 HTML
将SVG作为图像 | - SVG与主页面是分离的,无法在两者之间通信:主页面上的样式及脚本对 SVG 无效 - 如果 |
|
---|---|---|
将SVG作为CSS背景 | - 默认按固有尺寸,且在垂直及水平方向上repeat,以填满元素 - 如果没有固有尺寸,SVG缩放为元素高度和宽度的100% |
div.background-cat { background-image: url(‘cat.svg’); background-size: 100% 100%; } |
将SVG作为对象 | - 可以让那些不能直接显示SVG但是有SVG插件的老版本浏览器用户也能查看图像。 - 渲染同 - 与 |
|
内联SVG | - 通过在SVG命名空间内(在 |
|
在SVG中插入(X)HTML | - IE11+ 支持 |
y=’25%’ width=’10em’ height=’50%’ requiredFeatures=”http://www.w3.org/TR/SVG11/feature#Extensibility“ >
y=’25%’ dy=’1em’ > 这个 text 元素没有被包含,因此会被裁掉 |
视口
单位 | 描述 |
---|---|
em | 默认字体的大小,相当于文本行高 |
ex | 字母 x 的高度 |
px | 像素 |
pt | 点(1/72inch) |
pc | 12点(1/6inch) |
cm | 厘米 |
mm | 毫米 |
in | 英寸 |
默认情况下没有单位的数值都被视为像素。
在 4cm * 5cm
的图纸上设置一个16px/cm的坐标系,感觉是在更改分辨率
<svg width='4cm' height='5cm' viewBox='0 0 64 80'>
<rect x='10' y='35' width='50' height='40' style="stroke: black; fill: none" />
<polyline points='10 35, 35 7.68, 60 35' style="stroke: black; fill: none" />
<polyline points='30 75, 30 55, 40 55, 40 75' style="stroke: black; fill: none" />
</svg>
当 viewBox 的宽高比为 1:1,但视口宽高比为 1:3 时,SVG 可以做三件事:
- 按较小的尺寸等比例缩放图形,以使图形完全填充视口。图片将变为原始宽高的一半
- 按较大的尺寸等比例缩放图形并裁掉超出视口的部分。图片会变成原始宽高的1.5倍
- 拉伸和挤压视图以使其恰好填充新的视口(也就是说,完全不保留宽高比)
preserveAspectRatio 允许指定被缩放的图像相对视口的对齐方式,以及是希望它适配边缘还是要裁剪
preserveAspectRatio=”alignment[meet |slice]”
- alignment : 指定轴和位置
X对齐 | Y对齐 |
---|---|
xMin: 按视口左侧边缘,viewBox 最小 x 值对齐 | yMin: 按视口顶部边缘,viewBox 最小 y 值对齐 |
xMid: 按视口水平中心,viewBox 中点 x 值对齐 | yMid: 按视口垂直中心,viewBox 中点 y 值对齐 |
xMax: 按视口右侧边缘,viewBox 最大 x 值对齐 | yMax: 按视口底部边缘,viewBox 最大 y 值对齐 |
线段
可以通过指定CSS属性 shape-rendering 的值来控制反锯齿特性。
- crispEdges: 会关闭反锯齿特性,得到清晰的图像
- geometricPrecision:会使边缘圆滑,得到模糊的图像
<!-- 5个像素的虚线,3个像素的空隙,9个像素的虚线,2个像素的空隙 -->
<line
x1='0' y1='125' x2='135' y2='125'
style='stroke: currentColor;'
stroke-dasharray='5 3 9 2'
stroke-width=2
stroke-opacity=0.5
/>
- stroke:定义画笔颜色,支持颜色关键字、十六进制数字、rgb、currentColor 关键字。
- stoke-width: 定义画笔粗细。
- stroke-opacity: 取值0.0~1.0,控制线条的不透明度。
stroke-dasharray: 取值是一系列数字,代表线的长度和空隙的长度。用来绘制点线或虚线
矩形
fill-opacity: 取值0.0~1.0,控制填充的不透明度。
通过指定 rx、ry 可以绘制一个圆角矩形。如果只指定了一个值,则认为它们相等。
rx 的最大值是矩形宽度的一半。
<rect
x='100'
y='5'
rx='4'
width='30'
height='80'
style="stroke: black; fill: none; stroke-width: 1;"
/>
圆和椭圆
<svg
width='200'
height='200'
viewBox='0 0 200 200'
>
<circle
cx='30'
cy='30'
r='20'
style="stroke: black; stroke-width: 5; fill: none" />
<ellipse
cx='80'
cy='30'
rx='20'
ry='10'
style="stroke: black; stroke-width: 5; fill: none"
/>
</svg>
多边形
<svg
width='200'
height='200'
viewBox='0 0 200 200'
>
<polygon
points='15 10, 55 10, 45 20, 5 20'
style="stroke: black; stroke-width: 2; fill: none"
/>
<polygon
points='35 37.5, 37.9 46.1, 46.9 46.1, 39.7 51.5, 42.3 60.1, 35 55, 27.7 60.1, 30.3 51.5, 23.1 46.1, 32.1 46.1'
style="stroke: black; stroke-width: 2; fill: yellow; fill-opacity: 0.5"
/>
<polygon
points='60 60, 65 72, 80 60, 90 90, 72 80, 72 85, 50 95'
style="stroke: black; stroke-width: 2; fill: yellow; fill-opacity: 0.5"
/>
</svg>
填充边线交叉的多边形
SVG 有两种判断某个点是否在多边形的规则。
分别对应 fill-rule 属性的 nonzero(默认)和 evenodd,选择不同的规则会有不同的效果。
- nonzero: 从这个点画一条线到无穷远,然后数这条线与图形边线有多少次交叉。如果交叉的边线是从右往左画,则总数加1;如果交叉的边线是从左往右画,则总数减1;如果最后总数为0,则认为该点在图形外部,否则认为在图形内部。
- evenodd:也画同样一条线,但它只算与边线相交的次数,如果总数是奇数,则认为点在图形内部,否则认为点在图形外部。
<svg
width='200'
height='200'
viewBox='0 0 200 200'
>
<polygon
points='48 16, 16 96, 96 48, 0 48, 80 96'
style="stroke: black; stroke-width: 2; fill: none;"
/>
<polygon
points='148 16, 116 96, 196 48, 100 48, 180 96'
style="
fill-rule: nonzero;
fill: yellow;
stroke: black;
stroke-width: 2;"
/>
<polygon
points='248 16, 216 96, 296 48, 200 48, 280 96'
style="
fill-rule: evenodd;
fill: #00ff00;
stroke: black;
stroke-width: 2;"
/>
</svg>
折线
实现绘制不闭合的形状
<svg
width='200'
height='200'
>
<polyline
points='5 20, 20 20, 25 10, 35 30, 45 10, 55 30, 65 10, 75 30, 80 20, 95 20'
style="stroke: black; stroke-width: 2; fill: none;"
/>
</svg>
线帽和连接线
stroke-linecap: butt | round | square
<svg
width='200'
height='200'
>
<line x1='0' y1='15' x2='135' y2='15'
style='stroke: currentColor; stroke-linecap: butt' stroke-width=8
stroke-opacity=0.5 />
<line x1='0' y1='25' x2='135' y2='25'
style='stroke: currentColor; stroke-linecap: round' stroke-width=8
stroke-opacity=0.5 />
<line x1='0' y1='35' x2='135' y2='35'
style='stroke: currentColor; stroke-linecap: square' stroke-width=8
stroke-opacity=0.5 />
</svg>
stroke-linejoin: miter | round | bevel
如果值为miter,则相交处有可能比线本身宽,可以指定 stroke-miterlimit
来设置相交处的显示宽度与线宽的比率,默认值是 4.
<svg
width='200'
height='200'
>
<polyline points="30 30, 45 15, 60 30"
style='stroke-linejoin: miter; stroke: currentColor; stroke-linecap: butt' stroke-width=8
stroke-opacity=0.5 />
<polyline points="90 30, 105 15, 120 30"
style='stroke-linejoin: round; stroke: currentColor; stroke-linecap: round' stroke-width=8
stroke-opacity=0.5 />
<polyline points="150 30, 165 15, 180 30"
style='stroke-linejoin: bevel; stroke: currentColor; stroke-linecap: square' stroke-width=8
stroke-opacity=0.5 />
</svg>
基本形状总结
形状元素
形状 | 语法 | 描述 |
---|---|---|
线段 | /> |
从起始点(start-x, start-y)画一条线到(end-x, end-y) |
矩形 | y=’top-y’ width=’width’ height=’height’ /> |
画一个矩形,左上角位于(left-x, top-y),宽高分别为width和height |
圆 | cy=’center-y’ r=’radius’ /> |
以指定半径 radius 画一个圆,圆心位于(center-x, center-y) |
椭圆 | cy=’center-y’ rx=’x-radius’ ry=’y-radius’ /> |
画一个椭圆,x方向半径为 x-radius, y方向半径为y-radius,圆心位于(center-x, center-y) |
多边形 | /> |
画一个封闭图形,轮廓由 points-list 指定,它由一系列 x/y 坐标对组成,这些数值只能用用户坐标,不可以添加长度单位。 |
折线段 | /> |
画一系列相连的折线段,折线点由 points-list 指定,它由一系列 x/y 坐标对组成。这些数值只能使用用户坐标,不可以添加长度单位。 |
当为属性指定数值时,默认会以用户坐标为准。除最后两个元素外,其他元素的属性都可以在数字后加上单位,比如mm、pt等
笔画特性
属性 | 值 | |
---|---|---|
笔画颜色 | stroke | 默认值为none |
笔画宽度 | stroke-width | 默认值为1 |
透明度 | stroke-opacity | 0.0~1.0,默认值1.0(完全不透明) |
虚线及间隙 | stroke-dasharray | 默认值none,用一系列的数字来指定虚线和间隙的长度,这些数字只能使用用户坐标 |
线帽 | stroke-linecap | 线头尾的形状。值为 butt(默认) | round | square |
连接线 | stroke-linejoin | 圆形的棱角或者一系列连线的形状。值为 miter(默认) | round | bevel |
相交处比例 | stroke-miterlimit | 默认值为4。相交处显示宽度与线宽的最大比例 |
填充特性
属性 | 值 | |
---|---|---|
填充颜色 | fill | 默认值为 black |
填充透明度 | fill-opacity | 0.0~1.0,默认值1.0(完全不透明) |
填充区域 | fill-rule | 值为nonzero(默认) | evenodd。该属性决定判断某个点是否在图形内部的方法。只有当边线交叉时或者内部有“洞”时才有效。 |
文档结构
文档表现
内联样式
直接设置style属性的值为一系列视觉属性
<polyline
points='5 20, 20 20, 25 10, 35 30, 45 10, 55 30, 65 10, 75 30, 80 20, 95 20'
style="stroke: black; stroke-width: 2; fill: none;"
/>
内部样式表
通过一个内部样式表来罗列常用的样式,而无需在每个SVG元素内植入样式。这样可以为所有某一类元素应用样式,也可以使用命名类为特定元素应用样式。内部样式表被定义你在
“内联样式”几乎总是比内部或外部样式表渲染更快,因为样式表和类增加了渲染时的查询和解析时间。然而样式表更容易管理,更小的文件体积和可缓存的特性可以加快文档加载速度。
<svg
width='200'
height='200'
>
<defs>
<style type="text/css">
<![CDATA[
circle {
fill: #ffc;
stroke: blue;
stroke-width: 2;
stroke-dasharray: 5 3;
}
]]>
</style>
</defs>
<circle cx='20' cy='20' r='10' />
<circle cx='60' cy='20' r='15' />
<circle cx='20' cy='60' r='10' style='fill: #cfc' />
<circle cx='60' cy='60' r='15' style='stroke-width: 1; stroke-dasharray: none;' />
</svg>
外部样式表
ext_style.css
* {
fill: none;
stroke: black;
}
rect {
stroke-dasharray: 7 3;
}
circle.red {
fill: red;
}
.thick {
stroke-width: 5;
}
.semiblue {
fill: blue;
fill-opacity: 0.5;
}
<?xml version='1.0'?>
<?xml-stylesheet href='ext_style.css' type='text/css'?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<svg
width='200'
height='200'
>
<rect x='10' y ='20' width='40' height='30'>
<circle cx='70' cy='20' r='10' class='red'/>
<polygon class='thick semiblue' points='248 16, 216 96, 296 48, 200 48, 280 96' style="
fill-rule: evenodd;
fill: #00ff00;
stroke: black;
stroke-width: 2;" />
</svg>
表现属性
表现属性位于优先级列表的最底部。任何来自内联样式、内部样式表或者外部样式表的样式声明都会覆盖表现属性,但表现属性会覆盖继承的样式。
<svg
width='200'
height='200'
>
<defs>
<style type="text/css">
<![CDATA[
circle {
fill: red;
stroke: blue;
stroke-width: 2;
stroke-dasharray: 5 3;
}
]]>
</style>
</defs>
<circle cx='20' cy='60' r='10' fill='green' />
</svg>
分组
<svg
width='240'
height='240'
>
<title>Grouped Drawing</title>
<desc>Stick-figure drawings of a house and people</desc>
<g id="house" style="fill: none; stroke: black;">
<desc>House with door</desc>
<rect x='6' y='50' width='60' height='60'/>
<polyline points='6 50, 36 9, 66 50'/>
<polyline points='36 110, 36 80, 50 80, 50 110'/>
</g>
<g id="man" style="fill: none; stroke: black;">
<desc>Male Human</desc>
<circle cx='85' cy='56' r='10' />
<line x1='85' y1='66' x2='85' y2='80' />
<polyline points='76 104, 85 80, 94 104'/>
<polyline points='76 70, 85 76, 94 70'/>
</g>
<g id="woman" style="fill: none; stroke: black;">
<desc>Female Human</desc>
<circle cx='110' cy='56' r='10' />
<polyline points='110 66, 110 80, 100 90, 120 90, 110 80'/>
<polyline points='101 70, 110 76, 119 70' />
<line x1='104' y1='104' x2='108' y2='90' />
<line x1='112' y1='90' x2='116' y2='104' />
</g>
</svg>
symbol 还可以指定 viewBox 和 preserveAspectRatio ,通过给
引用对象
<use xlink:href='#house' x='70' y='100'/>
<use xlink:href='#woman' x='-80' y='100'/>
<use xlink:href='#woman' x='-50' y='100'/>
这种方式会有三个缺点:
- 复用 man 和 woman 组合时,需要知道原始图像中这些图形的位置,并以此位置作为复用的基础
- 房子的填充和笔画颜色由原始图形建立,并且不能通过
元素覆盖。这意味着我们不能构造一行彩色的房子 - 文档中会画出所有的三个元素 woman、man、house。我们不能将它们单独“存储”下来,然后只绘制一排房子或者只绘制一组人。
SVG 规范推荐我们将所有想要复用的对象放置在<defs>
元素内,这样SVG阅读器进入流式环境中就能更高效地处理数据。由于组合在<defs>
内,它们不会立刻绘制到屏幕上,而是作为“模板”供其它地方使用。
<svg
width='240'
height='240'
>
<title>Grouped Drawing</title>
<desc>Stick-figure drawings of a house and people</desc>
<defs>
<g id="house" style="stroke: black;">
<desc>House with door</desc>
<rect x='6' y='50' width='60' height='60'/>
<polyline points='6 50, 36 9, 66 50'/>
<polyline points='36 110, 36 80, 50 80, 50 110'/>
</g>
<g id="man" style="stroke: black;">
<desc>Male Human</desc>
<circle cx='85' cy='56' r='10' />
<line x1='85' y1='66' x2='85' y2='80' />
<polyline points='76 104, 85 80, 94 104'/>
<polyline points='76 70, 85 76, 94 70'/>
</g>
<g id="woman" style="stroke: black;">
<desc>Female Human</desc>
<circle cx='110' cy='56' r='10' />
<polyline points='110 66, 110 80, 100 90, 120 90, 110 80'/>
<polyline points='101 70, 110 76, 119 70' />
<line x1='104' y1='104' x2='108' y2='90' />
<line x1='112' y1='90' x2='116' y2='104' />
</g>
<g id="couple">
<desc>Male and female Stick figures</desc>
<use xlink:href='#man' x='0' y='0'/>
<use xlink:href='#woman' x='0' y='0'/>
</g>
</defs>
<!-- 利用组合定义 -->
<use xlink:href='#house' x='0' y='0' style="fill: #cfc;"/>
<use xlink:href='#couple' x='0' y='0'/>
<use xlink:href='#house' x='120' y='0' style="fill: #99f;"/>
<use xlink:href='#couple' x='120' y='0' />
<use xlink:href='#woman' x='-68' y='145' />
<use xlink:href='#man' x='-68' y='145' />
<use xlink:href='#house' x='50' y='145' style="fill: #c00"/>
</svg>
坐标系统变换
translate
看上去是这个样子的:
实际上是这个样子的:translate 会获取整个网络,然后把它移动到画布的新位置,而不是移动正方形,就正方形而言,它仍然绘制在左上角(0,0)。你可以理解为为了让沙发远离房子的外墙,移动了整个起居室、墙壁即所有东西到新的位置。
scale
transform=”scale(x-value, y-value)
所有 x 坐标乘以给定的 x-value,所有 y 坐标乘以给定的 y-value.
缩放变换永远不会改变图形对象的网络坐标或者笔画宽度,但是它会改变对应画布上的坐标系统(网格)的大小。
<svg>
<g id="squrae">
<rect x='10' y='10' width='20' height='20' style='fill: none; stroke:black;' />
</g>
<use xlink:href='#squrae' transform='scale(2)' />
</svg>
网格并没有被移动,坐标系统的点(0, 0)仍然在相同的位置,但是每个用户坐标都变成原来的两倍了。
从网格线上可以看到,矩形的左上角在更大的新网格中仍然在(10, 10)位置,对象并没有移动。stroke-width仍然是一个用户单位,但是这个单位已经是原来的两倍了,因此其笔画变粗了。
变换序列
多个变换只需通过空格或逗号分隔,依次放入 transform 属性即可,一般情况下,变换序列的顺序会影响结果。
变换总结
变换 | 描述 |
---|---|
translate(x, y) | 按照指定的x和y值移动用户坐标系统。注意:如果没有指定 y 值,则假定为0 |
scale(xFactor, yFactor) | 使用指定的 xFactor 和 yFactor 乘以所有的用户坐标系统。比例值可以是小数或者负值。 |
rotate(angle, certerX, centerY) | 按照指定的 angle 旋转用户坐标。旋转中心为原点(0,0)。在默认系统中,旋转角度按顺时针方向递增,水平线的角度为0度。 |
skewX(angle) | 根据指定的 angle 倾斜所有x坐标。从视觉上讲,这会让垂直线出现角度。 |
skewY(angle) | 根据指定的 angle 倾斜所有y坐标。从视觉上讲,这会让水平线出现角度。 |
matrix(a b c d e f) | 指定一个六个值组成的矩阵变换。 |