HTML 笔记(八):SVG
HTML 笔记(八):SVG
介绍
和 Canvas 相同,SVG 也是用与绘图的标签,区别在于 canvas 用于绘制位图、而 svg 用于绘制矢量图,示例如下:
位图(jpg、png、gif)是由一块块小方格组成,一个方格表示一个像素,优点是色彩丰富,缺点是放大失真、体积较大,矢量图用 XML 格式定义,通过各种「路径」和「填充颜色」来描述渲染的图片,优点是放大后不会失真、体积较小,缺点是不易制作色彩丰富的图片
<svg>
<circle cx="50" cy="50" r="50" />
</svg>
svg 与 canvas 的不同之处在于,svg 可以通过 css 样式或行内样式自定义元素宽高
导入方式
svg 代码除了可以内嵌至 HTML 中之外,也可以保存在以 .svg 扩展名结尾的文件中,示例如下:
<svg width="500" height="400" xmlns="http://www.w3.org/2000/svg">
<circle cx="150" cy="150" r="50" />
</svg>
SVG 使用 XML 格式定义图形,xmlns 属性定义 SVG 命名空间
以 .svg 扩展名结尾的文件本质上是一个图片,所以可以:
- 浏览器预览
- img 标签引用 svg 图片
- css 图片属性
示例如下:
<style>
* {
margin: 0;
padding: 0;
}
div {
height: 400px;
background: url(./svg-sample.svg) no-repeat;
}
</style>
<img src="./svg-sample.svg" alt="">
<div></div>
绘制图形
SVG 通过在根标签中定义各种图形标签来绘制图形,此外,必须说明的是,fill 属性表示图形填充的颜色、stroke 表示图形边框的颜色,以下是常用图形的示例:
矩形
<svg>
<rect x="50" y="50" width="200" height="100" fill="none" stroke="black" />
</svg>
SVG 中的 rect 标签可以通过指定属性 rx/ry 设置矩形的圆角半径,示例如下:
<svg>
<rect x="50" y="50" width="200" height="100" fill="none" stroke="black" rx="20" ry="20"/>
</svg>
rx/ry 的原理与 CSS 中 border-radius 属性的原理相同
圆
<svg>
<circle cx="250" cy="250" r="50" fill="none" stroke="black" />
</svg>
椭圆
<svg>
<ellipse cx="150" cy="100" rx="100" ry="50" fill="none" stroke="black" />
</svg>
直线
<svg>
<line x1="170" y1="150" x2="400" y2="150" stroke="black" />
</svg>
在 line 标签中 stroke 属性是必要的
折线
在 points 属性中两个相邻值为一组表示若干个被相连的坐标
非闭合
<svg>
<polyline points="100 100 300 100 300 200" fill="none" stroke="black" />
</svg>
闭合
<svg>
<polygon points="100 100 300 100 300 200" fill="none" stroke="black" />
</svg>
常用属性
在 SVG 中有一些常用的属性,大部分可以被用于任何图形标签中,也可以被用到 CSS 样式表中,内容如下:
属性 | 描述 |
---|---|
fill | 填充颜色 |
fill-opacity | 填充颜色的透明度(0 ~ 1) |
stroke | 边框颜色 |
stroke-width | 边框宽度 |
stroke-opacity | 边框颜色的透明度(0 ~ 1) |
stroke-linecap | 线条两侧的额外图形(butt / square / round) |
stroke-dasharray | 虚线 |
stroke-dashoffset | 虚线的偏移位 |
stroke-linejoin | 折线转角的样式(miter / bevel / round) |
示例如下:
rect {
fill: blue;
fill-opacity: 0.5;
stroke: red;
stroke-width: 20;
stroke-opacity: 0.2;
}
<svg width="500" height="400">
<rect x="50" y="50" width="300" height="100" />
</svg>
由于上述表格中的所有属性与 Canvas 中的含义相同,所以不再演示所有属性
绘制路径
在 SVG 中,可以通过 path 标签以及相应的指令绘制各种复杂的路径
线条
SVG 路径中线条的指令与 canvas 中常用的各种函数相似,内容如下:
指令 | 含义 |
---|---|
M | 起点坐标(moveTo) |
L | 下一个坐标(lineTo) |
H | 和上一个坐标的 Y 相等的坐标(horizontal lineTo) |
V | 和上一个坐标的 X 相等的坐标(vertical lineTo) |
Z | 关闭路径(closePath) |
示例如下:
<svg width="500" height="400">
<path d="M 100 100 L 300 100 L 300 300" fill="none" stroke="red" stroke-width="20" />
</svg>
如果一个坐标的 x 坐标或横坐标与上一个坐标的相应值相同,那么可以使用 H 或 V 指令简写,示例如下:
<svg width="500" height="400">
<path d="M 100 100 H 300 V 300" fill="none" stroke="red" stroke-width="20" />
</svg>
类似于 canvas 中的闭合问题,可以通过闭合路径解决,示例如下;
<svg width="500" height="400">
<path d="M 100 100 H 300 V 300 Z" fill="none" stroke="red" stroke-width="20" stroke-linejoin="round" />
</svg>
必须注意的是,指令的大小写区别:大写指令表示绝对位置、小写指令表示相对于上一个点的相对位置,示例如下:
<svg width="500" height="400">
<path d="M 100 100 l 300 100" fill="none" stroke="red" />
</svg>
圆弧
SVG 中绘制圆弧可以使用 A
指令,从当前位置绘制弧线到特定位置,原型如下:
A (rx, ry, xr, laf, sf, x, y)
各个参数的含义如下:
参数 | 含义 |
---|---|
rx | 椭圆的 X 半径 |
ry | 椭圆的 Y 半径 |
xr | 椭圆的旋转角度 |
laf | 是否选择弧长较长的那一段 |
sf | 是否顺时针绘制 |
x | 终点 X 坐标 |
y | 终点 Y 坐标 |
先绘制以 rx 和 ry 为半径的椭圆,将椭圆旋转 xr 度,将此椭圆平移至某个位置,此位置的弧线上包含初始坐标和终点坐标(x, y),通过 laf 和 sf 确定椭圆上的某一段弧长,示例如下:
<svg width="500" height="400">
<path d="M 100 100 A 100 50 60 1 0 300 200" fill="none" stroke="orange" />
</svg>
贝塞尔曲线
贝塞尔曲线是绘制弧线的一种方式,此处不讨论原理,将演示如何使用贝塞尔曲线指令
二次方
二次方贝塞尔曲线必须有起始点、控制点和终点,SVG 中使用 Q
指令从当前位置绘制二次贝塞尔曲线到指定位置,原型如下:
Q (x1, y1, x, y)
各个参数含义如下:
参数 | 含义 |
---|---|
x1 | 控制点 X 坐标 |
y1 | 控制点 Y 坐标 |
x | 终点 X 坐标 |
y | 终点 Y 坐标 |
示例如下:
<svg width="500" height="400">
<path d="M 100 100 Q 150 0 300 100" fill="none" stroke="red" />
</svg>
三次方
三次方贝塞尔曲线必须有起始点、控制点 1、控制点 2 和终点,SVG 中使用 C
指令从当前位置绘制三次贝塞尔曲线到指定位置,原型如下:
C (x1, y1, x2, y2, x, y)
各个参数含义如下:
参数 | 含义 |
---|---|
x1 | 控制点 1 的 X 坐标 |
y1 | 控制点 1 的 Y 坐标 |
x2 | 控制点 2 的 X 坐标 |
y2 | 控制点 2 的 Y 坐标 |
x | 终点 X 坐标 |
y | 终点 Y 坐标 |
示例如下:
<svg width="500" height="400">
<path d="M 100 100 C 150 0 250 0 300 100" fill="none" stroke="red" />
</svg>
绘制文本
类似于在 Canvas 中绘制文本,在 SVG 中绘制文本使用 text 标签,示例如下:
<svg width="500" height="400">
<line x1="0" y1="200" x2="500" y2="200" stroke="red" />
<line x1="250" y1="0" x2="250" y2="500" stroke="red" />
<text x="250" y="200" style="font-size: 20px;" text-anchor="middle" dominant-baseline="middle">Reyn Morales</text>
</svg>
在上述示例中,使用 text-anchor 属性设置文本的水平对齐方式,使用 dominant-baseline 设置文本的垂直对齐方式,此外参考点和 canvas 中类似(左下角),style 属性设置文本大小和字体
此外,SVG 中也可以绘制多行文本,示例如下:
<svg width="500" height="400">
<text stroke="blue">
<tspan x="100" y="100">R</tspan>
<tspan x="100" y="150">E</tspan>
<tspan x="100" y="200" stroke="red">y</tspan>
<tspan x="100" y="250">N</tspan>
</text>
</svg>
路径文本
在 SVG 中实现路径文本的步骤如下:
- 定义路径
- 关联路径
示例如下:
<svg width="500" height="400">
<defs> <!-- 1. 定义路径 -->
<path id="rainbow" d="M 100 100 Q 150 50 200 100" fill="none" stroke="red" />
</defs>
<text> <!-- 2. 关联路径 -->
<textPath xlink:href="#rainbow">Reyn Morales</textPath>
</text>
</svg>
SVG 中 defs 标签可以隐藏路径,此外,如果文本内容的长度大于路径长度,那么多余的文本内容将被省略
超链接
在 SVG 中可以使用 a 标签为文本或图形添加超链接,示例如下:
<svg width="500" height="400">
<a xlink:href="https://blog.csdn.net/Raymiles?spm=1019.2139.3001.5343" xlink:title="CSDN" target="blank">
<text x="100" y="100" style="font-size: 20px;">Reyn's blog</text>
<circle cx="200" cy="200" r="50" />
</a>
</svg>
绘制图片
在 SVG 中可以使用 image 标签绘制图片,示例如下:
<svg width="500" height="400">
<image xlink:href="./images/SpiderMan.jpg" x="50" y="50" width="200" height="400" />
</svg>
在上述示例中,为 image 标签设置宽高后,图片并不是严格以指定宽高显示:总是在某个方向上保持不变
结构元素
SVG 中提供了一系列结构元素,专门用于保存代码,从而简化程序
g
g 标签是 group 的简称,即用于将一系列标签分组保存以便统一操作,示例如下:
<g id="circles" fill="yellowgreen">
<circle cx="50" cy="100" r="50" />
<circle cx="50" cy="200" r="50" />
<circle cx="50" cy="300" r="50" />
</g>
defs
defs 标签的作用类似于 g 标签,不同之处在于 defs 标签默认情况下不显示,示例如下:
<defs id="rects">
<g>
<rect x="50" y="100" width="50" height="50" />
<rect x="50" y="200" width="50" height="50" />
<rect x="50" y="300" width="50" height="50" />
</g>
</defs>
use
use 标签可以引用 g 标签以及 defs 标签中的元素,并且可以在引用时自定义样式,示例如下:
<use xlink:href="#circles" x="400" />
<use xlink:href="#rects" x="150" fill="orangered" />
裁剪
SVG 中通过 clipPath 标签描述裁剪路径,位于路径范围之外的内容将被裁剪(不显示),示例如下:
<svg width="500" height="400">
<clipPath id="clip">
<circle cx="250" cy="200" r="100" />
</clipPath>
<rect x="100" y="100" width="300" height="200" clip-path="url(#clip)" />
</svg>
蒙版
SVG 中通过 mask 标签描述蒙版路径,位于路径范围之外的内容将被裁剪(不显示),位于路径范围之内的内容以透明显示,示例如下:
<svg width="500" height="400">
<mask id="mask">
<circle cx="250" cy="200" r="100" fill="orange" />
</mask>
<rect x="100" y="100" width="300" height="200" fill="blue" mask="url(#mask)" />
</svg>
渐变
SVG 中通过 linearGradient 和 radialGradient 标签分别描述线性渐变以及径向渐变,此处说明线性渐变,径向渐变是类似的,示例如下:
<svg width="500" height="400">
<linearGradient id="myColor" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="red" />
<stop offset="1" stop-color="blue" />
</linearGradient>
<rect x="100" y="100" width="300" height="200" fill="url(#myColor)" />
</svg>
类似于 canvas 中的渐变属性,SVG 中也使用两个坐标表示渐变方向以及范围,此处坐标以百分比的形式描述,坐标形式由 gradientUnits 属性描述,默认取值为 objectBoundingBox,如果取值为 userSpaceOnUse,那么坐标以用户自定义坐标描述,示例如下:
<linearGradient id="myColor" x1="100" y1="100" x2="400" y2="100" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="red" />
<stop offset="1" stop-color="blue" />
</linearGradient>
<rect x="100" y="100" width="300" height="200" fill="url(#myColor)" />
此外,stop 标签中的 offset 属性以及 stop-color 属性类似于 canvas 中的 addColorStop 方法
画笔
在 SVG 中通过 pattern 标签实现以自定义图形填充,示例如下:
<svg width="500" height="400">
<defs>
<pattern id="myPattern" width="0.2" height="0.2" patternUnits="objectBoundingBox">
<circle cx="10" cy="10" r="10" fill="red" />
</pattern>
</defs>
<rect x="100" y="100" width="300" height="200" fill="url(#myPattern)" />
</svg>
类似于渐变,SVG 中 pattern 标签的 width 和 height 属性在默认情况下以百分比的形式描述,形式由 patternUnits 属性决定,默认取值为 objectBoundingBox,如果取值为 userSpaceOnUse,那么宽高以用户自定义坐标描述,示例如下:
<defs>
<pattern id="myPattern" width="20" height="20" patternUnits="userSpaceOnUse">
<circle cx="10" cy="10" r="10" fill="red" />
</pattern>
</defs>
<rect x="100" y="100" width="300" height="200" fill="url(#myPattern)" />
pattern 标签中 width 和 height 的取值决定了填充图案的密度
transform 相关
SVG 中 transform 相关的属性与 canvas 中的类似,均是调整坐标系的位置、角度以及缩放,示例如下:
<svg width="500" height="400">
<rect x="100" y="50" width="300" height="100" />
<rect x="100" y="250" width="300" height="100" transform="translate(50, 0) scale(0.5, 1) rotate(5)" />
</svg>
ViewBox
SVG 中,ViewBox 的含义是可视区域,默认情况下,内容区域即为可视区域,可以通过 svg 标签的 viewBox 属性设置可视区域的位置和大小,示例如下:
<svg>
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 默认情况 -->
<svg viewBox="0 0 200 200">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 等比例放大 -->
<svg viewBox="0 0 400 400">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 等比例缩小 -->
<svg viewBox="0 0 100 100">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 非等比例 width 缩小 -->
<svg viewBox="0 0 100 200">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 非等比例 height 缩小 -->
<svg viewBox="0 0 200 100">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 非等比例 width 放大 -->
<svg viewBox="0 0 400 200">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- 非等比例 height 放大 -->
<svg viewBox="0 0 200 400">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- X -->
<svg viewBox="50 0 200 200">
<circle cx="100" cy="100" r="50" />
</svg>
<!-- Y -->
<svg viewBox="0 50 200 200">
<circle cx="100" cy="100" r="50" />
</svg>
在上述示例中,所有 svg 标签的宽高均为 200px,viewBox 属性中的 4 个取值分别表示可视区域的 x、y、width 和 height,如果 x、y 被更改,那么可视区域将以原内容区域的原点为参考移动,如果 width、height 属性被等比例放大或缩小,那么内容区域也将被缩小或放大,类似于近大远小的效果,而此时可视区域的坐标系与内容区域的坐标系相同,若 width、height 属性不是被等比例放大或缩小的,那么系统将自动调整 viewBox 的位置, 自定义的 x、y 属性将失效,此时如果可视区域的坐标系和内容区域的坐标系必须保持相同, 那么必须使用 preserveAspectRatio 属性设置对齐方式,属性值如下所示:
属性值 | 描述 |
---|---|
xMin | viewport 和 viewBox 左对齐 |
xMid | viewport 和 viewBox x 轴中心对齐 |
xMax | viewport 和 viewBox 右对齐 |
YMin | viewport 和 viewBox 上对齐 |
YMid | viewport 和 viewBox y 轴中心对齐 |
YMax | viewport 和 viewBox 下对齐 |
上述表格中,xM-- 和 YM-- 必须连写,示例如下:
<!-- 不规则 -->
<svg viewBox="50 50 100 400" preserveAspectRatio="xMinYMin">
<circle cx="100" cy="100" r="50" />
</svg>
动画
SVG 中可以通过 animate 相关的一系列标签实现动画效果
简单动画
SVG 中通过 animate 标签创建简单动画,示例如下:
<svg width="500" height="400">
<animate attributeName="r" from="50" to="100" dur="2s" fill="freeze" xlink:href="#circle" />
<circle id="circle" cx="100" cy="100" r="50" />
</svg>
animate 标签的属性描述如下:
属性 | 描述 |
---|---|
attributeName | 属性名称 |
from | 初始值 |
to | 终末值 |
dur | 持续时间 |
fill | 终末状态(remove【默认】、freeze) |
此外,SVG 也可以将 animate 标签置于动画元素中,此时可以省略 xlink:href 属性,示例如下:
<svg width="500" height="400">
<circle cx="100" cy="100" r="50">
<animate attributeName="r" from="50" to="100" dur="2s" fill="freeze" />
</circle>
</svg>
常用属性
SVG 中常用的 animate 标签属性描述如下所示:
属性 | 描述 |
---|---|
repeatCount | 执行次数 |
repeatDur | 总时长 |
begin | 延迟时间 |
restart | 元素开始动画之后,是否可以再次执行(always【默认】、whenNotActive、never) |
calcMode | 每一个动画片段的动画表现(linear【默认】、discrete、paced、spline) |
keyTimes | 划分动画时间片段 |
values | 划分相应片段的属性值 |
示例如下:
<svg width="500" height="400">
<circle cx="100" cy="100" r="50">
<animate attributeName="r" from="50" to="100" dur="2s" repeatCount="2" begin="click + 2s"
restart="whenNotActive" fill="freeze" />
</circle>
</svg>
联合动画
SVG 中可以将若干 animate 标签置于动画元素中,从而实现联合动画,示例如下:
<svg width="500" height="400">
<circle cx="100" cy="100" r="50">
<animate attributeName="r" from="50" to="100" dur="2s" fill="freeze" />
<animate attributeName="fill" from="yellowgreen" to="orangered" dur="2s" fill="freeze" />
</circle>
</svg>
下一个示例演示了如何实现往返动画:
<svg width="500" height="400">
<circle cx="100" cy="100" r="50">
<animate id="toLeft" attributeName="cx" from="100" to="300" dur="2s" begin="0;toRight.end" fill="freeze" />
<animate id="toRight" attributeName="cx" from="300" to="100" dur="2s" begin="toLeft.end" fill="freeze" />
</circle>
</svg>
在上述示例中,begin 属性值
toLeft.end
表示在 toLeft 动画结束后立即执行当前动画,而0;
则表示第一次无延迟时间、之后在 toRight 动画结束后立即执行此动画
transform 动画
SVG 中通过 animateTransform 标签实现 transform 属性相关的动画,示例如下:
<rect x="100" y="100" width="300" height="100">
<animateTransform id="translate" attributeName="transform" type="translate" from="0 0" to="0 100"
dur="2s" />
<animateTransform id="scale" attributeName="transform" type="scale" from="1 1" to="0.5 1" dur="2s"
begin="translate.end" />
<animateTransform id="rotate" attributeName="transform" type="rotate" from="0" to="30" dur="2s"
begin="scale.end" />
</rect>
路径动画
SVG 中通过 animateMotion 标签实现路径动画,示例如下:
<svg width="500" height="400">
<path d="M 100 100 L 300 200" fill="none" stroke="red" />
<rect x="100" y="100" width="10" height="10" fill="blue">
<animateMotion path="M 0 0 L 200 100" begin="click" dur="4s" fill="freeze"></animateMotion>
</rect>
</svg>
在上述示例中,path 标签不是必须的,绘制出来可以作为一个参考,此外,animateMotion 标签中的 path 属性和 path 标签中 d 属性用法相同,关键在于 animateMotion 中 path 属性的坐标系以动画元素为原点
脚本编程
如下是一个 SVG 示例:
<svg width="500" height="400">
<circle cx="100" cy="100" r="50" fill="orange" />
<image xlink:href="./images/JavaScript.jpg" x="300" y="200"/>
</svg>
如下示例演示了如何使用 JavaScript 动态实现上述效果:
window.onload = function () {
const SVG_NS = "http://www.w3.org/2000/svg";
let oSvg = document.createElementNS(SVG_NS, "svg");
oSvg.setAttribute("width", "500");
oSvg.setAttribute("height", "400");
document.body.appendChild(oSvg);
let oCircle = document.createElementNS(SVG_NS, "circle");
oCircle.setAttribute("cx", "100");
oCircle.setAttribute("cy", "100");
oCircle.setAttribute("r", "50");
oCircle.setAttribute("fill", "orange");
oSvg.appendChild(oCircle);
const XLINK_NS = "http://www.w3.org/1999/xlink";
let oImage = document.createElementNS(SVG_NS, "image");
oImage.setAttributeNS(XLINK_NS, "xlink:href", "./images/JavaScript.jpg");
oImage.setAttribute("x", "300");
oImage.setAttribute("y", "200");
oSvg.appendChild(oImage);
}
SVG 脚本编程的关键在于,凡是创建 SVG 元素时,必须使用方法 createElementNS,且在调用时传入相应的命名空间,xlink:href 属性亦是如此,必须使用方法 setAttributeNS,如果必须使用脚本编程,那么建议学习如下框架:
- SVG.js
- Snap.svg