一、概述
SVN 是一种图像格式.网页中可以使用的图片分为矢量图和位图,平时我们经常使用的jpg,png,gif图片是位图(基于像素点处理的),放大或缩小都会影响图片的清晰度,SVG图片是矢量图,全称是可缩放矢量图(Scalable Vector Graphics),如果你用记事本打开它,将会发现里面是一段可读的基于XML 语法的文本,这些文本就是对图像的描述,所以SVN图像本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
上一个w3c上的例子看一看,下面是一个svg格式的图片用记事本打开后的文本内容(我格式化了一下)。
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>
可能你注意到了,代码里有个网址,这个网址是W3C的网址,意味着这段代码引用了W3C的外部的 SVG DTD(文档类型定义),在我们定义xhtml网页的时候也有类似的代码,有兴趣可以自行百度。
引入方式
既然SVG是图像,我们就可以和其他格式图片一样,将它引入网页,和进行base64的转码,这些内容在图片优化的章节讲过了。
1、用<img>、<object>、<embed>、<iframe>等标签的src属性引入到网页中。
<img src="book.svg">
<object id="object" data="book.svg" type="image/svg+xml"></object>
<embed id="embed" src="book.svg" type="image/svg+xml">
<iframe id="iframe" src="book.svg"></iframe>
2、CSS 也可以使用 SVG 文件。
.logo { background: url(icon.svg); }
3、同位图一样,SVG 文件也可以转为 BASE64编码,然后作为Data URI 写入网页。
<img src="data:image/svg+xml;base64,[data]">
上面的引入方式和位图是一样的,更美好的是HTML5 支持内联 SVG,能够将 SVG 元素直接嵌入 HTML 页面中。SVG元素作为DOM 的一部分,使前端彻底的获得了SVG图像的控制权。
4、 SVG 作为HTML5的一个新标签直接插入网页
<!DOCTYPE html>
<html>
<head></head>
<body>
<svg width="300" height="180">
<circle id="mycircle" cx="400" cy="300" r="50" style="fill:red" />
</svg>
</body>
</html>
二、语法
SVG图像是二维图像,由点、线、面组成,SVG的语法依然很简单,无外乎就是点线面的结合,通过代码要绘制出复杂的图像绝非易事,视乎更需要我们拥有几何学的知识,好在现在有很多工具能够只做出很好的SVG图像。
<svg>标签
svg元素的width属性和height属性,实际上是定义了svg图像的视口(viewport),内部的图像如果超出视窗,将会被剪裁掉,这一点和PS是一样的,不同的是svg元素的视窗可以根据使用百分比,这样使SVG的视窗有了可伸缩性。
和所有的可视HTML元素一样,SVG图像的视口也是一个矩形,默认情况下矩形的左上顶点,是坐标的顶点(0,0),向右是横轴x轴,向下是纵轴y轴,通过横坐标和纵坐标,可以定位到svg元素的任何一点。
viewBox属性
通过定义<viewBox>属性的值,可以自定义图像的顶点和大小,有四个数字,分别是左上角的横坐标和纵坐标、视口的宽度和高度。如果定义了viewBox属性,相当于剪裁了图像,但视口的大小还是那么大,所以图像会放大去适配 SVG 视口的大小,相当于放大了图像。
SVG 内部元素
SVG 的内部元素有很多共似的属性,下面不再累述。
属性 | 属性 值 | 说明 |
---|---|---|
含x属性 | 数值 | 如:x,x1,cx等,表示横坐标的值 |
含y属性 | 数值 | 如:y,y1,cy等,表示纵坐标的值 |
class | class属性用来指定对应的 CSS 类。 | |
fill | 填充色 | |
stroke | 描边色 | |
stroke-width | 边框宽度 |
fill,stroke,stroke-width的属性值,也可以通过css定义。
绘制不同的形状,需要不同的属性,如矩形需要起点的坐标,宽度和高度,而正圆需要圆心的坐标和半径,线段需要起点和终点的坐标等等。
预定义的形状
SVG元素中可以使用一些预定义的形状元素,可被开发者使用和操作:
1.矩形 <rect> 2.圆形<circle> 3.椭圆 <ellipse>4.线 <line>5.折线 <polyline>6.多边形 <polygon>7.路径 <path>
1、rect标签用于绘制矩形
<svg width="300" height="180">
<rect x="0" y="0" height="100" width="200" style="fill: red" />
</svg>
2、circle绘制圆形
<svg width="300" height="180">
<circle cx="30" cy="50" r="25" fill="blue" />
</svg>
circle标签的cx、cy、r属性分别为横坐标、纵坐标和半径,单位为像素。
3、ellipse标签用于绘制椭圆。
<svg width="300" height="180">
<ellipse cx="60" cy="60" ry="40" rx="20" />
</svg>
ellipse的cx属性和cy属性,指定了椭圆中心的横坐标和纵坐标(单位像素);
rx属性和ry属性,指定了椭圆横向轴和纵向轴的半径(单位像素)。
4、line绘制线段
line标签的x1属性和y1属性,表示线段起点的横坐标和纵坐标;x2属性和y2属性表示线段终点的横坐标和纵坐标
<svg width="300" height="180">
<line x1="0" y1="0" x2="200" y2="0" />
</svg>
5、polyline标签用于绘制一根折线
<svg width="300" height="180">
<polyline points="3,3 30,28 3,53" fill="none" stroke="black" />
</svg>
polyline标签的points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。
6、polygon用于绘制多边形
<svg width="300" height="180">
<polygon fill="green" stroke="orange" stroke-width="1" points="0,0 100,0 100,100 0,100 0,0"/>
</svg>
polygon的points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。
7、path标签用于制路径。
<svg width="300" height="180">
<path d="
M 18,3
L 46,3
L 46,40
L 61,40
L 32,68
L 3,40
L 18,40
Z
"></path>
</svg>
path的d属性表示绘制顺序,它的值是一个长字符串,每个字母表示一个绘制动作,后面跟着坐标。
M:移动到(moveto)
L:画直线到(lineto)
Z:闭合路径
自定义的形状
1、defs标签用于自定义形状,它内部的代码不会显示,仅供引用。
<svg width="300" height="100">
<defs>
<g id="myCircle">
<text x="25" y="20">圆形</text>
<circle cx="50" cy="50" r="20"/>
</g>
</defs>
<use href="#myCircle" x="0" y="0" />
<use href="#myCircle" x="100" y="0" fill="blue" />
<use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>
pattern标签用于自定义一个形状,该形状可以被引用来平铺一个区域。
<svg width="500" height="500">
<defs>
<pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<circle fill="#bee9e8" cx="50" cy="50" r="35" />
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>
pattern标签将一个圆形定义为dots模式。patternUnits="userSpaceOnUse"表示pattern的宽度和长度是实际的像素值。然后,指定这个模式去填充下面的矩形。
text标签用于绘制文本
<svg width="100" height="100">
<text x="10" y="10">Hello World</text>
</svg>
text的x属性和y属性,表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用class或style属性指定。
use标签用于复制一个形状。
<svg viewBox="0 0 30 10">
<circle id="myCircle" cx="5" cy="5" r="4"/>
<use href="#myCircle" x="10" y="0" fill="blue" />
<use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>
use标签的href属性指定所要复制的节点,x属性和y属性是use标签左上角的坐标。另外,还可以指定width和height坐标。
g标签用于将多个形状组成一个组(group),方便复用。
<svg width="300" height="100">
<g id="myCircle">
<text x="25" y="20">圆形</text>
<circle cx="50" cy="50" r="20"/>
</g>
<use href="#myCircle" x="100" y="0" fill="blue" />
<use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>
image标签用于插入图片文件。
<svg viewBox="150 50 400 200" width="400" height="200">
<image xlink:href="https://www.baidu.com/img/bd_logo1.png?where=super"
width="50%" height="50%"/>
</svg>
xlink:href属性表示图像的来源。
animate标签用于产生动画效果。
<svg width="500px" height="120px">
<rect x="0" y="10" width="100" height="100" fill="red">
<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
</rect>
</svg>
animate的属性含义如下:
attributeName:发生动画效果的属性名。
from:单次动画的初始值。
to:单次动画的结束值。
dur:单次动画的持续时间。
repeatCount:动画的循环模式。
可以在多个属性上面定义动画。
<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
<animate attributeName="width" to="500" dur="2s" repeatCount="indefinite" />
animateTransform标签产生变形动画效果
<svg width="500px" height="500px">
<rect x="250" y="250" width="50" height="50" fill="#4bc0c8">
<animateTransform attributeName="transform" type="rotate" begin="0s" dur="10s" from="0 200 200" to="360 400 400" repeatCount="indefinite" />
</rect>
</svg>
animateTransform的效果为旋转(rotate),这时from和to属性值有三个数字,第一个数字是角度值,第二个值和第三个值是旋转中心的坐标。from="0 200 200"表示开始时,角度为0,围绕(200, 200)开始旋转;to="360 400 400"表示结束时,角度为360,围绕(400, 400)旋转。
注意:animate标签对 CSS 的transform属性不起作用
三、JavaScript 操作
1、DOM 操作
如果 SVG 代码直接写在 HTML 网页之中,它就成为网页 DOM 的一部分,可以直接用 DOM 操作。
<svg
id="mysvg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 800 600"
preserveAspectRatio="xMidYMid meet"
>
<circle id="mycircle" cx="400" cy="300" r="50" />
</svg>
上面代码插入网页之后,就可以用 CSS 定制样式。
circle {
stroke-width: 5;
stroke: #f00;
fill: #ff0;
}
circle:hover {
stroke: #090;
fill: #fff;
}
然后,可以用 JavaScript 代码操作 SVG。
var mycircle = document.getElementById('mycircle');
mycircle.addEventListener('click', function(e) {
console.log('circle clicked - enlarging');
mycircle.setAttribute('r', 60);
}, false);
上面代码指定,如果点击图形,就改写circle元素的r属性。
2、获取 SVG DOM
使用<object>、<iframe>、<embed>标签插入 SVG 文件,可以获取 SVG DOM。
var svgObject = document.getElementById('object').contentDocument;
var svgIframe = document.getElementById('iframe').contentDocument;
var svgEmbed = document.getElementById('embed').getSVGDocument();
注意,如果使用<img>标签插入 SVG 文件,就无法获取 SVG DOM。
3、读取 SVG 源码
由于 SVG 文件就是一段 XML 文本,因此可以通过读取 XML 代码的方式,读取 SVG 源码。
<div id="svg-container">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve" width="500" height="440"
>
<!-- svg code -->
</svg>
</div>
使用XMLSerializer实例的serializeToString()方法,获取 SVG 元素的代码。
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
4、SVG 图像转为 Canvas 图像
首先,需要新建一个Image对象,将 SVG 图像指定到该Image对象的src属性。
var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var DOMURL = self.URL || self.webkitURL || self;
var url = DOMURL.createObjectURL(svg);
img.src = url;
然后,当图像加载完成后,再将它绘制到<canvas>元素。
img.onload = function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
};