svg学习记录
Star Sea

常用形状

矩形

1
<rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>
参数名 描述
x 矩形左上角的x位置
y 矩形左上角的y位置
width 矩形的宽度
height 矩形的高度
rx 圆角的x方位的半径
ry 圆角的y方位的半径

圆形

1
<circle cx="25" cy="75" r="20"/>
参数名 描述
r 圆的半径
cx 圆心的x位置
cy 圆心的y位置

椭圆

1
<ellipse cx="75" cy="75" rx="20" ry="5"/>
参数名 描述
rx 椭圆的x半径
ry 椭圆的y半径
cx 椭圆中心的x位置
cy 椭圆中心的y位置

线条

1
<line x1="10" x2="50" y1="110" y2="150"/>
参数名 描述
x1 起点的x位置
y1 起点的y位置
x2 终点的x位置
y2 终点的y位置

折线

1
<polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>

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

多边形

1
<polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>

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

路径

1
<path d="M150 0 L75 200 L225 200 Z" />

参数含义:

  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Bézier curve
  • T = smooth quadratic Bézier curveto
  • A = elliptical Arc
  • Z = closepath

    以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。

贝塞尔曲线

  1. 三次贝塞尔曲线

    1
    2
    3
    4
    5
    // 语法
    C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)

    // 举例
    <path d="M70 10 C 70 20, 120 20, 120 10" stroke="black" fill="transparent"/>

    最后一个坐标(x,y)表示的是曲线的终点,另外两个坐标是控制点,(x1,y1)是起点的控制点,(x2,y2)是终点的控制点

  2. 三次贝塞尔曲线简化

一般情况下,三次贝塞尔曲线的两个控制点对称,因此可以简化只写一个控制点。语法如下:

1
S x2 y2, x y (or s dx2 dy2, dx dy)

当S命令之前是C或者S命令的时候,这里的第一个控制点将是前面曲线的第二个控制点的中心对称点。

1
<path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/>
  1. 二次贝塞尔曲线

二次贝塞尔曲线仅需要一个控制点,来确认起点和终点的曲线斜率

1
2
3
4
5
// 语法
Q x1 y1, x y (or q dx1 dy1, dx dy)

// 举例
<path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
  1. 二次贝塞尔曲线简化

当此前已有Q命令的时候,可以省去控制点,自动推算出一个新的控制点。如果此前无Q命令,则推算的控制点为终点,画出来的为直线。

1
2
3
4
5
// 语法
T x y (or t dx dy)

// 举例
<path d="M10 80 Q 52.5 10, 95 80 T 180 80" stroke="black" fill="transparent"/>

弧形

1
2
3
4
5
6
7
8
9
10
11
// 语法
A rx ry x-axis-rotation large-arc-flag sweep-flag x y
a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy

// 举例
<path d="M10 315
L 110 215
A 30 50 0 0 1 162.55 162.45
L 172.55 152.45
A 30 50 -45 0 1 215.1 109.9
L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/>

参数的含义:
rx、ry表示椭圆的x轴和y轴的半径
x-axis-rotation表示x轴旋转角度,0则表示弧形所在的椭圆是正置的
large-arc-flag决定弧线是大于还是小于180度,0表示小角度弧,1表示大角度弧
sweep-flag表示弧线的方向,0表示从起点到终点沿逆时针画弧,1表示从起点到终点沿顺时针画弧

填充与边框

常用参数列举:

参数名 描述
fill 填充色
stroke 描边色
fill-opacity 填充色的不透明度
stroke-opacity 描边色的不透明度
stroke-width 描边宽度
stroke-linecap 边框终点的形状:
butt直边结束线段,它是常规做法,线段边界90度垂直于描边的方向、贯穿它的终点
square的效果差不多,但是会稍微超出实际路径的范围,超出的大小由stroke-width控制
round表示边框的终点是圆角,圆角的半径也是由stroke-width控制的
stroke-linejoin miter是默认值,表示用方形画笔在连接处形成尖角,round表示用圆角连接,实现平滑效果。bevel,连接处会形成一个斜接
stroke-dasharray 定义描边虚线类型,由一组用逗号分隔的数字组成。交替表示填色单位长度、空白单位长度。

举例

1
2
3
4
5
6
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg" version="1.1">
<path d="M 10 75 Q 50 10 100 75 T 190 75" stroke="black"
stroke-linecap="round" stroke-dasharray="5,10,5" fill="none"/>
<path d="M 10 75 L 190 75" stroke="red"
stroke-linecap="round" stroke-width="1" stroke-dasharray="5,5" fill="none"/>
</svg>

渐变

定义在<defs>标签内,指定id,其他元素通过id引用。可以用于fillstroke

线性渐变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
// 默认水平渐变
<linearGradient id="Gradient1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="50%"/>
<stop class="stop3" offset="100%"/>
</linearGradient>

// 垂直渐变
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="red"/>
<stop offset="50%" stop-color="black" stop-opacity="0"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>

// 通过样式执行
<style type="text/css"><![CDATA[
#rect1 { fill: url(#Gradient1); }
.stop1 { stop-color: red; }
.stop2 { stop-color: black; stop-opacity: 0; }
.stop3 { stop-color: blue; }
]]></style>
</defs>

<rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>

</svg>

x1、x2、y1、y2指定了渐变的方向

径向渐变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="RadialGradient1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>

// 指定渐变焦点
<radialGradient id="Gradient"
cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>

<rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient1)"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient2)"/>
<rect x="10" y="10" rx="15" ry="15" width="100" height="100"
fill="url(#Gradient)" stroke="black" stroke-width="2"/>
</svg>

cx、cy、r 指定了镜像渐变的范围,fx、fy 指定了焦点,即渐变的中心点

文字

x、y指定文本在视口中显示的位置。属性text-anchor指定文本流的方向,可选sstart、middle、end、inherit

1
<text x="10" y="10">Hello World!</text>

可使用的属性:font-family、font-style、font-weight、font-variant、font-stretch、font-size、font-size-adjust、kerning、letter-spacing、word-spacing和text-decoration
其他用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// tspan指定子元素
<text>
<tspan font-weight="bold" fill="red">This is bold and red</tspan>
</text>

// tref引用已经定义的文本
<text id="example">This is an example text.</text>
<text>
<tref xlink:href="#example" />
</text>

// textPath指定文字沿着路径环绕
<path id="my_path" d="M 20,20 C 40,40 80,40 100,20" fill="transparent" />
<text>
<textPath xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#my_path">
This text follows a curve.
</textPath>
</text>

基础变形

元素

元素用于将属性赋给整个元素集合

1
2
3
4
<g fill="red">
<rect x="0" y="0" width="10" height="10" />
<rect x="20" y="0" width="10" height="10" />
</g>

平移translate

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

旋转rotate

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

其他变换

skewX()x轴斜切
skewY()y轴斜切
scale()缩放

剪切和遮罩

剪切

在剪切范围内的元素才会显示,如下代码仅显示上半部的圆形

1
2
3
4
5
6
7
8
9
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<clipPath id="cut-off-bottom">
<rect x="0" y="0" width="200" height="100" />
</clipPath>
</defs>

<circle cx="100" cy="100" r="100" clip-path="url(#cut-off-bottom)" />
</svg>

遮罩

以下代码使用渐变遮罩,水平方向不透明度从0到1,则红色的矩形从左到右逐渐显示,叠加后产生渐变效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="Gradient">
<stop offset="0" stop-color="white" stop-opacity="0" />
<stop offset="1" stop-color="white" stop-opacity="1" />
</linearGradient>
<mask id="Mask">
<rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" />
</mask>
</defs>

<rect x="0" y="0" width="200" height="200" fill="green" />
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#Mask)" />
</svg>

滤镜

滤镜元素可参考mdn文档:https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element#%E6%BB%A4%E9%95%9C%E5%85%83%E7%B4%A0
以下列举一个阴影效果的代码:

1
2
3
4
5
6
7
8
9
10
11
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="f1" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<rect width="90" height="90" stroke="green" stroke-width="3"
fill="yellow" filter="url(#f1)" />
</svg>

feOffset使用Alpha通道残影偏移,接着feGaussianBlur使用偏移的结果进行高斯模糊,最后feBlend将原图像和上一步模糊后的阴影结合生成最后的效果。

图片

1
2
3
4
<svg width="5cm" height="4cm" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
<image xlink:href="firefox.jpg" x="0" y="0" height="50px" width="50px"/>
</svg>
  • 如果你没有设置x属性或y属性,它们自动被设置为0。
  • 如果你没有设置height属性或width属性,它们自动被设置为0。
  • 如果width属性或height等于0,将不会呈现这个图像。

SVG.js的使用

以上了解了svg基本的语法,但是自己绘制svg还是比较麻烦,这里记录下SVG.js库的使用,可以简化绘制流程。

快速使用

可以cdn引入和npm安装,这里以Vue为例

1
npm install @svgdotjs/svg.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div id="svg">
</div>
</template>

<script setup>
import { onMounted } from 'vue'
import { SVG } from "@svgdotjs/svg.js"

onMounted(() => {
// 通过addTo方法将SVG挂载到dom上,通过size设置大小
let draw = SVG().addTo("#svg").size("100%", "100%");

// 这里绘制一个100大小的矩形,并绑定了点击事件
draw.rect(100, 100).attr({ fill: "#00B1B6" }).click(function() {
this.fill('#ff0000')
});
})
</script>

常用绘图

绘图方法名称和svg形状名称基本一致,然后通过attr可设置属性,同时也可以通过属性名直接设置。使用方式和jQuery类似,支持链式调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 绘制矩形,设置矩形圆角
var rect = draw.rect(100, 100)
rect.radius(10)

// 绘制占据100,直径半径50的圆
draw.circle(100).radius(50)

// 绘制长宽200/100的椭圆,x、y半径分别为75、50
var ellipse = draw.ellipse(200, 100).radius(75, 50)

// 直线绘制
var line = draw.line(0, 0, 100, 150).stroke({ width: 1 })

// 多线段绘制
var polyline = draw.polyline('0,0 100,50 50,100').fill('none').stroke({ width: 1 })
var polyline1 = draw.polyline([[0,0], [100,50], [50,100]])
var polyline2 = draw.polyline([0,0, 100,50, 50,100])

// 路径的绘制
draw.path('M0 0 H50 A20 20 0 1 0 100 50 v25 C50 125 0 85 0 85 z')

// 图片绘制,图片加载后的回调处理
var image = draw.image('/path/to/image.jpg', function (event) {
// image loaded
// this is the loading event for the underlying img element
// you can access the natural width and height of the image with
// event.target.naturalWidth, event.target.naturalHeight
})

// 线性渐变
var gradient = draw.gradient('linear', function(add) {
add.stop(0, '#333')
add.stop(1, '#fff')
})
rect.fill(gradient)

// 镜像渐变
var gradient = draw.gradient('radial', function(add) {
add.stop(0, '#333')
add.stop(1, '#fff')
})

gradient.from(0.5, 0.5).to(0.5, 0.5).radius(0.5)

位置

  1. 通过attr

    1
    2
    3
    4
    // 矩形根据左上角移动
    rect.attr({ x: 20, y: 60 })
    // 圆形根据中心点移动
    circle.attr({ cx: 50, cy: 40 })
  2. 通过x、y坐标设置

    1
    2
    3
    // 通过坐标轴移动方法时,均可以使用左上角和中心点,仅支持无单位坐标
    rect.cx(20).cy(60)
    circle.x(50).y(40)
  3. 通过move方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 通过move方法指定坐标,左上角基准
    rect.move(200, 350)
    // 等价于
    rect.x(200).y(350)

    // 中心点移动
    rect.center(150, 150)
    // 等价于
    rect.cx(200).cy(350)

    // 相对坐标移动
    rect.dmove(10, 30)
    // 等价于
    rect.dx(10).dy(30)

    动画

    动画使用animate方法,再调用attrmove等方法之前使用。以下为使用的举例:

  4. 默认

默认情况下duration将设置为400delay将设置为0when设置为after

1
rect.animate().move(150, 150)
  1. 常用参数

第一个是duration,第二个delay和第三个when
when参数的取值:

  • now:在此调用执行后立即播放动画
  • absolute或start:将动画安排到时间线上的绝对时间
  • relative:安排动画相对于其旧开始时间播放(对 animate() 调用无用)
  • last或after:在时间轴上最后一个动画之后播放动画。如果没有,则立即播放动画(请参阅now)
    1
    rect.animate(2000, 1000, 'now').attr({ fill: '#f03' })
  1. 对象形式多参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    rect.animate({
    duration: 2000,
    delay: 1000,
    when: 'now',
    swing: true,
    times: 5,
    wait: 200
    }).attr({ fill: '#f03' })

    // 多个动画链接在一起
    rect.animate().attr({ fill: '#f03' }).animate().dmove(50,50)

    // 动画之间添加延迟
    rect.animate().attr({ fill: '#f03' }).delay(200).animate().dmove(50,50)

    // 直接在动画里面加延迟
    rect.animate().attr({ fill: '#f03' }).animate({delay: 200}).dmove(50,50)
  2. 缓动设置

缓动类型包括:

  • <>: ease in and out
  • >: ease out
  • <: ease in
  • -: linear
  • 函数
  • beziere(x1, y1, x2, y2)
  • step(steps, stepPosition)
    1
    draw.circle(100).radius(50).fill("#ccB1B6").animate({ duration: 2000 }).ease('<').dmove(100);

    事件

    支持常见事件的绑定,例如:click、dblclick、mousedown、mouseup、mousemove、mouseout、mousemove、touchstart、touchmove、touchleave、touchend、touchcancel等

    单事件绑定

    可直接通过事件名绑定:
    1
    2
    3
    4
    5
    6
    element.click(function() {
    this.fill({ color: '#f06' })
    })

    // 解绑事件
    element.click(null)

    on绑定

    可通过on绑定单个或多个事件:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 单个事件绑定
    var click = function() {
    this.fill({ color: '#f06' })
    }
    element.on('click', click)

    // 多个事件绑定
    element.on(['click', 'mouseover'], handler)
    element.on('click mouseover', handler)

    // 指定上下文
    element.on('click', click, window)

    // 解绑事件
    element.off('click', click)
    element.off('click')
    element.off(['click', 'mouseover'])
    element.off('click mouseover')
    element.off()

    自定义事件

    自定义事件的绑定:
    1
    2
    3
    element.on('myevent', function() {
    alert('ta-da!')
    })
    事件和自定义事件可以通过firedispatch触发,区别在于fire返回element、而dispatch返回事件对象。
    1
    2
    3
    4
    5
    6
    7
    // 触发事件
    element.fire('myevent')
    // 携带参数
    element.fire('myevent', {some:'data'})

    // dispatch的使用
    var event = element.dispatch(event)

    结语

    除了SVG.js外还有其他的库可以方便操作svg,也可以自己封装一些常用的操作。这里再推荐一个草绘风格的绘图库,Rough.js