在第一篇笔记里简单介绍了SVG,SVG(Scalable Vector Graphics,可伸缩矢量图形)是HTML里的一种标签,也可以独立保存为.svg的文件,SVG 基于 XML 格式定义图像,通常使用SVG作为d3绘图的容器。
个人认为熟悉SVG中各种图形元素的属性对于学习D3是磨刀不误砍柴工。而且svg的应用场景广泛,不止于D3,也方便自己理解其他库或者软件生成的svg图形文档。
SVG元素的基础写法:
1 | <svg width="500" height="400" version="1.1"> |
单纯以上语句只是声明了一个500x400的空白画布,还需要添加形状,
SVG预定义形状有6种基本形状,分别为rect(矩形)、circle(圆形)、ellipse(椭圆)、line(线段)、polyline(折线)、polygon(多边形)以及功能强大的path(路径),在SVG里也可以添加text(文本)元素。一个包含矩形的SVG标签如下:
1 | <svg width="500" height="400" version="1.1"> |
可以将其保存为后缀为.svg的独立文件,也可以在html文档里使用。
SVG 坐标系统原点位于画布的左上角,也就是说增大 x 的值,图形是向右移动;增大 y 值,图形会向下移动。
以下对SVG预定义形状进行枚举。
矩形
矩形的标签为<rect>
。
<rect x="50" y="10" width="60" height="40"/>
声明一个矩形。
在绘制柱状图、条形图、直方图、堆叠柱状图等统计图时,广泛地用到了<rect>
标签。
<rect>
的属性有:
- x:矩形左上角的x坐标,注意是左上角不是中心点的坐标;
- y:矩形左上角的y坐标;
- width:矩形宽度;
- height:矩形高;
- rx:缺省是正常矩形,否则是圆角矩形,圆角处椭圆在x方向的半径;
- ry:圆角矩形的圆角在y方向的半径;
sytle用于指定矩形的样式,如填充色,透明度,边框;写作<rect style="fill:#1EAFAE; opacity:0.6">
,这些在svg的其他图形中也适用,就不再重复。
- fill:表示要填充的颜色,css颜色,常用的是3种,可以是blue这种名称,也可以是16进制颜色值
#1EAFAE
或者是rgb(30, 175, 174)
; - stroke:表示边框的颜色;
- stroke-width:边框宽度;
- opacity:透明度。数值在[0,1]之间,值越小越透明;
一个SVG矩形的例子:
1 | <svg width="500" height="400" version="1.1"> |
渐变表示一种颜色平滑过渡到另一种颜色。SVG中有<linearGradient>
线性渐变和<radialGradient>
放射性渐变。渐变的标签写在<defs></defs>
标签内,defs用于定义可重复利用的图形元素,在图形中通过id引用defs标签里定义的效果,达到重用的目的。
1 | <svg width="500" height="400" version="1.1"> |
linearGradient标签里,x1、y1、x2、y2定义渐变的方向,x1="0%" y1="0%" x2="100%" y2="0%"
是水平渐变,改为x2="0%" y2="100%"
则为垂直渐变,offset定义渐变开始的位置,stop-color定义边界位置的颜色。
滤镜<filter>
能使图形更具有艺术效果,对源图形使用滤镜能修改其显示结果。滤镜也是写在<defs></defs>
标签内。例如以下代码定义了一个高斯模糊的滤镜,并应用到矩形rect上。
1 | <svg width="500" height="400" version="1.1"> |
feGaussianBlur标签定义了一个高斯模糊的滤镜,in是使用滤镜的对象,此处是源图形用SourceGraphic表示,
stdDeviation是高斯模糊唯一的参数,数值越大,模糊程度越高。在矩形中通过 filter = "url(#gaussianBlur)"
代码使用我们创建的滤镜。
滤镜的种类很多,例如feMorphology、feGaussianBlur、feFlood等等,还有定义光源的滤镜feDistantLight、fePointLight、feSpotLight,都是以fe开头的。feOffset用于生成图形的阴影效果,结合高斯模糊可以构建图形的投射阴影,增强表现力。
圆形
用<circle>
标签绘制圆形,圆形的参数是3个:
- cx:圆心的x坐标,可以记为circle-x;
- cy:圆心的y坐标;
- r:圆的半径;
椭圆
ellipse
表示椭圆,椭圆的参数与圆形类似,但半径分为了水平半径和垂直半径;
- cx:椭圆圆心的x坐标;
- cy:圆心的y坐标;
- rx:椭圆的水平半径;
- ry:椭圆的垂直半径;
圆和椭圆的示例:
1 | <svg width="500" height="400" version="1.1"> |
<svg>
标签里有多个形状时,会按照顺序渲染,也就是写在后面的就覆盖到之前的图形上。利用覆盖和叠加可以形成很多有趣实用的效果,例如点的涟漪效果等。
线段
用<line>
标签绘制一条线,用D3绘制柱状图时,坐标轴就需要用到line标签,各种统计图表普遍用到了line在坐标轴等元素中;
线段<line>
的参数有4个:
- x1:起点的x坐标;
- y1:起点的y坐标;
- x2:终点的x坐标;
- y2:终点的y坐标;
一个线段的例子:
1 | <svg width="500" height="400" version="1.1"> |
折线和多边形
折线<polyline>
和多边形<polygon>
的参数是一样的,因此放一起对比着看,它们都是只有一个points参数,表示一系列的点坐标,效果的不同之处在于多边形会将终点和起点连接起来。
1 | <svg width="500" height="400" version="1.1"> |
折线通常用来绘制折线图,多边形可以用来绘制面积图、区间注释等等。上面代码中transform="translate(180,0)"
将polyline折线的坐标原点移动到svg元素的[180,0]处,效果就是polyline整体向右边平移了180像素。
路径
<path>
标签的功能最丰富也最强大,表示一段路径,前面列举的图形都可以用路径画出来。与折线类似,path也是通过给定的一系列点坐标来绘制。在D3中绘制地图时,会经常用到此标签,读取geojson数据,然后绘制一段段路径。如果使用过Python里的turtle库,就会对SVG绘制路径的过程感到轻车熟路,当然没用过也不难去理解绘制的过程。<path>
的写法是:给出一个坐标点,在坐标点前面添加一个英文字母,用于标识如何运动到此坐标点。英文字母按照功能可分为五类。大写表示绝对坐标,小写表示相对坐标。
- 移动类: M即moveto,表示将画笔移动到指定坐标,不绘制移动的路径;
- 直线类:L,画直线到指定坐标(lineto);H,画水平直线到指定坐标(horizontal lineto);V,画垂直直线到指定坐标(vertical lineto);
- 曲线类:C,curveto,画三次贝塞尔曲线经两个指定控制点到达终点坐标;S,smooth curveto,与前一条三次贝塞尔曲线相连,第一个控制点为前一条曲线第二个控制点的对称点,只需输入第二个控制点和终点,即可绘制一个三次贝塞尔曲线;Q,quadratic Bézier curveto,画二次贝塞尔曲线经一个指定控制点到达终点坐标;T,Shorthand/smooth quadratic Bézier curveto,与前一条二次贝塞尔曲线相连,控制点为前一条二次贝塞尔曲线控制点的对称点,只需输入终点,即可绘制一个二次贝塞尔曲线;
- 弧线类:A,elliptical arc,画椭圆曲线到指定坐标;
- 闭合类:Z,closepath,绘制一条直线连接终点和起点,用来封闭图形;
一个路径的例子如下:
1 | <svg width="500" height="400" version="1.1"> |
文本
在SVG中可以使用<text>
标签绘制文字,其属性有:
- x:文字位置的x坐标。
- y:文字位置的y坐标。
- dx:相对于当前位置在x方向上平移的距离(值为正则往右,负则往左);
- dy:相对于当前位置在y方向上平移的距离(值为正则往下,负则往上)。
- textLength:文字的显示长度(不足则拉长,足则压缩)
- rotate:旋转角度(顺时针为正,逆时针为负)。
因为文本内容是写在标签外的,因此用的是成对显示的标签,不是写<text x="20" y="30"/>
而是写``
用rotate参数的旋转是每个字符都旋转,因此要整体旋转还是用transform里的rotete。两者对比效果如下:
1 | <svg width="500" height="400" version="1.1"> |
文本内容可以用到html其他标签,用<tspan>
对文本里的某一部分文字单独定义样式,示例如下:
1 | <text x="30" y="50" dx="-5" dy="5" textLength="100" > |
标记
标记<marker>
是SVG中一个重要的概念,增强了svg基本形状的表达力,标记贴附于path、line、polyline、
polygon元素上。和滤镜filter一样,标记marker也是定义在<defs></defs>
中,defs用于定义可重复利用的图形元素。一个典型的应用是基于路径排列文本。
1 | <svg width="500" height="400" version="1.1"> |
还有就是给线段添加箭头:
1 | <svg width="500" height="400" version="1.1"> |
效果如下图,在<defs>
里定义了id为arrow的标记,在path里通过marker-end="url(#arrow)"
调用。标记的位置属性有marker-start、marker-mid和marker-end。
总结
SVG是HTML里的一种标签,D3的可视化功能大部分通过操纵SVG里的图形元素达成,虽然D3可以直接操作div或其他原生HTML元素来绘图,但操纵SVG更简便,也更可靠,SVG生成的图形效果更一致,对各种浏览器都兼容,而操纵div则不然,可能在某些版本的浏览器里就解析出期待之外的效果。而且SVG很强大,绘图速度更快,因此不难选择。SVG的标签和规范有很多内容,还能深入学习的有各种滤镜、放射性渐变、强大的路径<path>
标签等,文中的内容对于D3可视化基本够用,后续再深入。