JS数据可视化技术选型之Canvas与SVG

Canvas 是HTML5新增的标签元素,它就像一个画布,JS通过操作HTML5提供的绘图 API在Canvas标签上绘制图形,与SVG相反,Canvas绘制的是位图,也叫标量图、点阵图。

SVG全称Scalable Vector Graphics,可缩放矢量图,单看这名字就知道是用来绘制矢量图的。W3C上是这样描述的:SVG是一种基于XML语法的图像格式,通过XML文档描述绘图。什么意思?通俗点讲就是SVG是通过标签元素DOM来绘制图形。相比Canvas,SVG是位老前辈了,2003年这位前辈就已经是W3C 标准,但是由于它长相复杂而且有点不求上进,十几年来发展非常缓慢。

在HTML5还没有发布的年代,浏览器的内置功能在可视化方面可做的事情非常有限,不得不借助Flash。HTML5新增了Canvas标签、改进SVG特性并支持内联SVG,促使web前端数据可视化后来居上,成为数据可视化领域的网红利器。当前主流的JavaScript数据可视化库,比如D3、Echarts、HighCharts、AntV等均是基于Canvas或者SVG的绘图技术,而且D3、Echarts、AntV已经同时支持Canvas和SVG渲染。

Canvas与SVG虽说都是浏览器内置的2D图形绘制技术,在HTML5中感觉很相似,但是两者有着本质的不同,并且各有优缺点。WebGL是Canvas的3D绘图标准,能实现3D数据可视化,这里不详细说,说到Canvas通常指它的2D绘图功能。

举个例子,用Canvas和SVG分别绘制一个同样的散点图。
一个散点图例子
使用Canvas绘制散点图HTML代码

1
2
<canvas data-zr-dom-id="zr_0" width="1600" height="1200"
style="position: absolute; left: 0px; top: 0px; width: 800px; height: 600px; user-select: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); padding: 0px; margin: 0px; border-width: 0px;"></canvas>

​使用SVG绘制散点图HTML代码
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
<svg width="1600" height="1200" preserveAspectRatio="xMidYMid meet" viewBox="0 0 998 577">
<g class="main" transform="translate(499,288.5) scale(1)">
<g class="base" transform="translate(-1.9987640206820743,0.6762029975734265) scale(0.9917167307382942)">
<g class="axis" fill="none" font-size="10" font-family="sans-serif" text-anchor="middle"
transform="translate(0,-24.041666666666686)">
<path class="domain" stroke="currentColor" d="M-373.75,4V0.5H374.75V4"></path>
<g class="tick" opacity="1" transform="translate(-373.75,0)">
<line stroke="currentColor" y2="4"></line><text fill="currentColor" y="7" dy="0.71em">0</text>
</g>
<!--..... -->
<!-- 此处省略10行g标签 -->
</g>
<g class="axis" fill="none" font-size="10" font-family="sans-serif" text-anchor="end"
transform="translate(-213.59320669671604,0)">
<path class="domain" stroke="currentColor" d="M-4,-215.875H0.5V216.875H-4"></path>
<g class="tick" opacity="1" transform="translate(0,-215.875)">
<line stroke="currentColor" x2="-4"></line><text fill="currentColor" x="-7" dy="0.32em">6</text>
</g>
<!--..... -->
<!-- 此处省略10行g标签 -->
</g>
<g class="rect">
<rect width="748.5" height="432.75" transform="translate(-374.25,-216.375)"></rect>
</g>
<g class="texts"><text transform="translate(0,231.375)" style="text-anchor: middle;">学科产出专利数量(件)</text></g>
<g class="texts"><text transform="translate(-389.25,0) rotate(-90)"
style="text-anchor: middle;">被引频次增长率(%)</text></g>
</g>
<g class="points">
<circle r="5" transform="translate(-103.09112994504476,-28.888525606953024)"
style="fill: rgb(24, 144, 255);"></circle>
<circle r="5" transform="translate(-286.31606424452,-23.166320070593084)" style="fill: rgb(47, 194, 91);">
</circle>
<circle r="5" transform="translate(-362.4739065011714,-34.13388068194967)" style="fill: rgb(47, 194, 91);">
</circle>
<!--..... -->
<!-- 此处省略19行circle标签 -->
</g>
</g>
</svg>

比较两种渲染代码,显而易见 canvas体型小,无论什么样的可视化图表,在页面上一个canvas标签元素就够了;svg相对体型巨大,一个简单的可视化图表就需要数十个标签。这样的结构差异造成了canvas和svg的四点区别:

① 事件监听

canvas的事件触发是粗粒度的,仅支持在canvas元素级别;svg图形中的每一个DOM都可以绑定事件。因此,要实现图表交互,canvas必须通过鼠标坐标进行手动编程设置,svg在相应的DOM上监听事件即可。

② 图形保存

canvas上绘制的图形是一个位图,能够以.png或者jpg格式保存成图像;svg本身就是一个图像格式,把svg标签内容保存成.svg格式文件就是一个图像文件了(注意svg标签里需要声明命名空间)。

③ 动画制作

canvas中的图形绘制完成就得不到浏览器的继续关注了,如果要让图形运动就需要擦除图形然后重新绘制,利用人眼睛的视觉误差来形成动画;svg图形创建后,其内部图形元素(DOM)是真实存在的,支持可访问性,可以通过改变图形元素的属性来形成动画。

④ 渲染性能

canvas是对单个标签的渲染,svg是对多标签的渲染;因此,canvas适用于小面积大数据量(10k以上)的应用场景,而svg更适用于大面积小数据量的应用场景。

因此,实时大规模数据可视化优先使用Canvas;高保真度的复杂静态图形可视化,如建筑图、工程图、大规模地图(百度地图、谷歌地图等)等优先使用SVG;普通交互式图表和图形可视化方面,SVG与Canvas都能胜任,此时需要结合其他客观因素(如平台:移动端 or PC端、学习成本等)进行技术选型。

大概就这么多了~~~