踏足SVG | 深入浅出全方位介绍SVG的功能及特性 - 基础篇(二)

1,142 阅读8分钟

前言

上一篇文章中介绍了什么是SVG、发展历史及如何引入和使用。本篇文章将介绍常用的图形元素的使用及常见的 stroke 描边与 fill 填充的用法。

往期文章

踏足SVG | 深入浅出全方位介绍SVG的功能及特性 - 基础篇(一)

常用的基本图形元素

在日常的开发过程中,经常会使用到以下元素:

  • <text>
  • <image>
  • <circle>
  • <ellipse>
  • <line>
  • <polygon>
  • <polyline>
  • <rect>
  • <path>

Text 文本

text元素定义了一个由文字组成的图形

基本属性:

  • x: 文本所在 x 坐标
  • y: 文本所在 y 坐标
  • dx: 文本所在 x 的偏移量
  • dy: 文档所在 y 的偏移量
  • text-anchor: 文本的对齐方式
    • start
    • middle
    • end
    • inherit(默认) 继承,会继承外层的 start 属性(外层没设置的话)
  • rotate: 文字旋转角度。每个文字
  • textLength: 文本的长度
  • lengthAdjust: 文本长度调整
    • spacing (默认) 用空格填充间隔。内容区不足时,间隔为负值,文字重叠
    • spacingAndGlyphs 拉伸文字来填充间隔。内容区不足时,文字被压缩

PS: 需要注意的是文字图形是以左下角为起点。所以通常需要设置一个 dy 的偏移量

例1:文字图形的字体及绘制的起始点

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <!-- 设置一个字体大小为 16 的文字图形 -->
    <text 
      x="0" y="0"
      font-size="16"
    >
      嘿嘿嘿!
    </text>
    <!-- 详细偏移 16 让图形能够看到 -->
    <text 
      x="50" y="0"
      dy="16"
      font-size="16"
    >
      嘿嘿嘿!
    </text>
    <!-- 换一个字体 -->
    <text 
      x="110" y="0"
      dy="16"
      font-family="宋体"
      font-size="16"
    >
      嘿嘿嘿!
    </text>
  </svg>

text_1.png

例2:文字图形的偏移、对齐方式、旋转和长度调整

  <svg class="border" width="200" height="300" viewBox="0 0 200 300">
    <text x="10" y="25"> 嘿嘿嘿!</text>
    <!-- x 方向偏移 10 y 方向上偏移 -10 -->
    <text x="10" y="50" dx="10" dy="-10"> 嘿嘿嘿!</text>
    <!-- 对齐方式默认 start -->
    <text x="100" y="75"> 对齐方式!</text>
    <!-- 对齐方式: start -->
    <text x="100" y="100" text-anchor="start"> 对齐方式!</text>
    <!-- 对齐方式: middle -->
    <text x="100" y="125" text-anchor="middle"> 对齐方式!</text>
    <!-- 对齐方式: end -->
    <text x="100" y="150" text-anchor="end"> 对齐方式!</text>
    <!-- 旋转 65 ° -->
    <text x="10" y="175" rotate="65"> 旋转一下!</text>

    <!-- spacing 模式下 文字图形长度被拉伸  -->
    <text x="10" y="200" textLength="8em" lengthAdjust="spacing"> 长度调整!</text>
    <!-- spacing 模式下 文字图形长度被压缩  -->
    <text x="10" y="225" textLength="2em" lengthAdjust="spacing"> 长度调整!</text>
    <!-- spacingAndGlyphs 模式下 文字图形长度被拉伸  -->
    <text x="10" y="250" textLength="8em" lengthAdjust="spacingAndGlyphs"> 长度调整!</text>
    <!-- spacingAndGlyphs 模式下 文字图形长度被压缩  -->
    <text x="10" y="275" textLength="2em" lengthAdjust="spacingAndGlyphs"> 长度调整!</text>
  </svg>

text_2.png

Image 图片

定义了一个图片的图形

基本属性:

  • x:x 坐标
  • y:y 坐标
  • width:图像宽度。可以不传,如果不传使用的是原始像素
  • height:图像高度。可以不传,如果不传使用的是原始像素
  • xlink:href:图像的URL指向

例: 通过 image 标签引入图片

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <image x="10" y="10" width="80" height="80" xlink:href="../../image/1.jpg"></image>
    <!-- 也可引入 svg -->
    <image x="10" y="100" width="80" height="80" xlink:href="../../static/PPT.svg#ppt"></image>
  </svg>

image_1.png

circle 圆形

基本属性:

  • r: 圆的半径
  • cx: 圆心的 x 位置
  • cy: 圆心的 y 位置

例:简单的来画一个圆形

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
   <circle cx="50" cy="50" r="40"/>
</svg>

这里在一个宽高 200 的画布上画了了一个圆心在(50,50)半径为 40 的圆

circle_1.png

Ellipse 椭圆

Ellipse 是circle元素更通用的形式,你可以分别缩放圆的x半径和y半径(通常数学家称之为长轴半径和短轴半径)。

基本属性:

  • rx: 椭圆的 x 半径
  • ry: 椭圆的 y 半径
  • cx: 圆心的 x 位置
  • cy: 圆心的 y 位置

例:简单的来画一个椭圆

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <ellipse cx="50" cy="90" rx="40" ry="80" />
  </svg>

ellipse_1.png

React 矩形

基本属性:

  • x: 矩形左上角的 x 位置
  • y: 矩形左上角的 y 位置
  • width: 矩形的宽度
  • height: 矩形的高度
  • rx: 圆角属性 圆角圆的x方向的半径
  • ry: 圆角属性 圆角圆的y方向的半径

例:简单的来画一些矩形

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
   <!-- 宽 60 高 40 的矩形  -->
   <rect x="10" y="10" width="60" height="40" />
   <!-- 宽 60 高 40 的矩形, 圆角圆 x 方向半径为 10, y 方向半径为 10-->
   <rect x="10" y="60" rx="10" ry="10" width="60" height="40" />
   <!-- 当宽高相同即为正方形 -->
   <rect x="10" y="120" rx="20" ry="20" width="40" height="40" />
   <!-- 如果圆角圆的半径 rx|ry 为对应 宽|高 的一半,则得到了一个圆或者椭圆 -->
   <rect x="10" y="120" rx="20" ry="20" width="40" height="40" />
   <rect x="100" y="120" rx="30" ry="20" width="60" height="40" />
 </svg>

rect_1.png

下图可以更加直观的看到通过 rx ry 定义的圆角圆切圆角的情况

rect_2.png

Line 线条

基本属性:

  • x1: 起点的 x 位置
  • y1: 起点的 y 位置
  • x2: 终点的 x 位置
  • y2: 终点的 y 位置

线是默认没有颜色的,这里通过 stroke 属性给线设置颜色,通过 stroke-width 来设置线条的宽度

例: 画一条线

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
   <line x1="10" y1="50" x2="180" y2="150" stroke="orange" stroke-width="3"/>
 </svg>

line_1.png

Polyline 折线

Polyline是一组连接在一起的直线。因为它可以有很多的点,折线的的所有点位置都放在一个points属性中

基本属性:

  • points:点集数列。每个数字用空白、逗号、终止命令符或者换行符分隔开。每个点必须包含2个数字,一个是x坐标,一个是y坐标。所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”。

例: 画一条折线

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <polyline points="20,110 80,160 40,60" stroke="orange"  stroke-width="3"/>
    <polyline points="100,110 160,160 140,60" stroke="orange" fill="none" stroke-width="3"/>
  </svg>

polyline_1.png

通过上面的图片不难发现,虽然折线没有闭合,但是依然出现了黑色的填充区,这时需要给 fill 属性设置 none 来取消填充颜色

Polygon 多边形

polygon和折线很像,它们都是由连接一组点集的直线构成。不同的是,polygon的路径在最后一个点处自动回到第一个点。需要注意的是,矩形也是一种多边形,如果需要更多灵活性的话,你也可以用多边形创建一个矩形。

基本属性:

  • points:点集数列。每个数字用空白符、逗号、终止命令或者换行符分隔开。每个点必须包含2个数字,一个是x坐标,一个是y坐标。所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”。路径绘制完后闭合图形,所以最终的直线将从位置(2,2)连接到位置(0,0)。

例: 画一个多边形

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <polygon points="50,60 55,80 70,80 60,90 65,105 50,95 35,105 40,90 30,80 45,80"
      stroke="red" fill="none" stroke-width="3"/>
  </svg>

polygon_1.png

修饰图形的属性

通过上面的图形示例可以发现,图形是画出来了,但是颜色为什么是黑的的呢,如何修改颜色呢

这就要提到两个常用的属性 stroke 和 fill

stroke 描边

stroke属性定义了给定图形元素的外轮廓的颜色。

可用值:

stroke: green | #00FFFF | rgb(0,0,255) | rgba(0,0,255,0.6) | none

可指定颜色值格式支持

  • 颜色字符
  • 颜色 16 进制
  • rgb
  • rgba

例子: 为圆设置一个描边

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <circle cx="50" cy="50" r="40" stroke="rgba(0,255,255,.6)" stroke-width="20"/>
</svg>

stroke-width: number 可以设置描边线的宽度

circle_2.png

可以明显的看到 stroke 描边是由中心向两侧进行伸展。

stroke-opacity: 0-1 也可以设置描边的透明度

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <circle cx="50" cy="50" r="40" stroke="rgb(0,255,255)" stroke-width="20" stroke-opacity="0.6"/>
</svg>

效果与上图一致

fill 填充

fill 用来填充图形内部的颜色,对于复杂的图形,图形内部的界定需要用 fill-rule 来控制

可用值:

fill: green | #00FFFF | rgb(0,0,255) | rgba(0,0,255,0.6) | remove | freeze

可指定颜色值格式支持

  • 颜色字符
  • 颜色 16 进制
  • rgb
  • rgba

目前 rgba 格式现阶段所以主流浏览的都支持,IE 11 也支持这个格式

对于动画元素可以指定动画结束后 fill 的状态

  • remove 动画结束后移除
  • freeze 动画结束后冻结

例子: 为圆设置填充色

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <circle cx="20" cy="20" r="20" fill="green"/>
    <circle cx="70" cy="20" r="20" fill="#008000"/>
    <circle cx="120" cy="20" r="20" fill="rgb(0,128,0)"/>
    <circle cx="170" cy="20" r="20" fill="rgba(0,128,0,.6)"/>
    <circle cx="20" cy="70" r="20" fill="#008000" fill-opacity="0.6"/>
</svg>

circle_3.png

fill-opacity: 0-1 也可以设置填充的透明度

fill-rule 确定图形的内部

fill 是对于一个图形的内部进行填充。在 SVG 当中规定了两个算法来确定图形的内部,通过 fill-rule 属性来定义

fill-rule 规定使用什么规则来确定图形内部区域。作为一个外观属性,它可以被应用于任何元素,但只会在这八个元素中有效:<altGlyph>、<path>、<polygon>、<polyline>、<text>、<textPath>、<tref> 和 <tspan>。

可用值:

fill-rule: nonzero(默认值) | evenodd

nonzero 算法

nonzero 算法确定了某点属于该形状的“内部”还是“外部”:从该点向任意方向的无限远处绘制射线,然后检测形状与射线相交的位置。从 0 开始统计,路径上每一条从左到右(顺时针)跨过射线的线段都会让结果加 1,每条从右向左(逆时针)跨过射线的线段都会让结果减 1。当统计结束后,如果结果为 0,则点在外部;如果结果不为 0,则点在内部。

举个例子来说明:

fill_rule_nonzero.PNG

如图所示:

A点:图中由 A 点发出的射线

  • 先经过 4-5 path,由射线左至射线右,统计值 + 1
  • 再经过 1-2 path,由射线左至射线右,统计值 + 1
  • 再经过 3-4 path,由射线右至射线左,统计值 - 1
  • 最后经过 5-1 path(闭合),由射线右至射线左,统计值 - 1
  • 最后的统计值为 0,所以 A 点在外部

B点:同A

C点:图中由 C 点发出的射线

  • 先经过 2-3 path, 由射线左至射线右,统计值 + 1
  • 再经过 5-1 path,由射线左至射线右,统计值 + 1
  • 最后的统计值为 2,所以 C 点在内部

例子:使用 nonzero 实现空心图形

这里 path 由于篇幅的关系,放在后面一篇文章单独说明。这个 path 实际上画了内外两个矩形。两个矩形的路径方向不一致。

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
  <path fill="yellow" stroke="red"
      d="M50,50 v80 h80 v-80 z
         M70,70 h40 v40 h-40 z"/>
</svg>

nonzero.png

实现空心的关键就是内部矩形的路径方向要和外部相反,这里 path 外部是顺时针,内部是逆时针

evenodd 算法

evenodd 算法确定了某点属于该形状的“内部”还是“外部”:从该点向任意方向无限远处绘制射线,并统计这个形状所有的路径段中,与射线相交的路径段的数量。如果有奇数个路径段与射线相交,则点在内部;如果有偶数个,则点在外部。

fill_rule_evenodd.PNG

如图所示:

  • A点: 相交 path: 4-5, 1-2, 3-4, 5-1。偶数在外部
  • B点: 相交 path: 1-2。奇数在内部
  • C点: 相交 path: 2-3, 5-1。偶数在外部

例子:使用 nonzero 实现空心图形

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
  <path fill="yellow" fill-rule="evenodd" stroke="red"
      d="M50,50 v80 h80 v-80 z
         M70,70 v40 h40 v-40 z"/>
</svg>
<svg class="border" width="200" height="200" viewBox="0 0 200 200">
  <path fill="yellow" fill-rule="evenodd" stroke="red"
      d="M50,50 v80 h80 v-80 z
         M70,70 h40 v40 h-40 z"/>
</svg>

evenodd.png

evenodd算法,路径的方向就不用管了

写在最后

如果有出现问题或者错误,还望指正。path 由于篇幅的关系,我会放在下一篇文章中进行介绍。

参考资料

参考来源 - MDN