笔记来源:极客时间 月影 可视化基础课程

HTML+CSS

实际上很多常见的可视化图表我们都可以用 HTML 和 CSS 来实现,不需要用其他的绘图方式。但是,为什么在可视化领域很少有人直接用 HTML 和 CSS 来绘制图表呢?
这主要是因为,使用 HTML 和 CSS 绘图,有 2 个缺点。

用 HTML+CSS 实现可视化的缺点

首先,HTML 和 CSS 主要还是为网页布局而创造的,使用它们虽然能绘制可视化图表,但是绘制的方式并不简洁。这是因为,从 CSS 代码里,我们很难看出数据与图形的对应关系,有很多换算也需要开发人员自己来做。这样一来,一旦图表或数据发生改动,就需要我们重新计算,维护起来会很麻烦。
其次,HTML 和 CSS 作为浏览器渲染引擎的一部分,为了完成页面渲染的工作,除了绘制图形外,还要做很多额外的工作。比如说,浏览器的渲染引擎在工作时,要先解析 HTML、SVG、CSS,构建 DOM 树、RenderObject 树和 RenderLayer 树,然后用 HTML(或 SVG)绘图。当图形发生变化时,我们很可能要重新执行全部的工作,这样的性能开销是非常大的。
image.png
图形系统与浏览器渲染引擎工作对比

SVG

现代浏览器支持 SVG(Scalable Vector Graphics,可缩放矢量图),SVG 是一种基于 XML 语法的图像格式,可以用图片(img 元素)的 src 属性加载。而且,浏览器更强大的是,它还可以内嵌 SVG 标签,并且像操作普通的 HTML 元素一样,利用 DOM API 操作 SVG 元素。甚至,CSS 也可以作用于内嵌的 SVG 元素。

  1. <!--
  2. dataset = {
  3. total: [25, 26, 40, 45, 68],
  4. current: [15, 11, 17, 25, 37],
  5. }
  6. -->
  7. <svg xmlns="http://www.w3.org/2000/svg" width="120px" height="240px" viewBox="0 0 60 100">
  8. <g transform="translate(0, 100) scale(1, -1)">
  9. <g>
  10. <rect x="1" y="0" width="10" height="25" fill="#37c"/>
  11. <rect x="13" y="0" width="10" height="26" fill="#37c"/>
  12. <rect x="25" y="0" width="10" height="40" fill="#37c"/>
  13. <rect x="37" y="0" width="10" height="45" fill="#37c"/>
  14. <rect x="49" y="0" width="10" height="68" fill="#37c"/>
  15. </g>
  16. <g>
  17. <rect x="1" y="0" width="10" height="15" fill="#3c7"/>
  18. <rect x="13" y="0" width="10" height="11" fill="#3c7"/>
  19. <rect x="25" y="0" width="10" height="17" fill="#3c7"/>
  20. <rect x="37" y="0" width="10" height="25" fill="#3c7"/>
  21. <rect x="49" y="0" width="10" height="37" fill="#3c7"/>
  22. </g>
  23. </g>
  24. </svg>

HTML 的不足之处在于 HTML 元素的形状一般是矩形,虽然用 CSS 辅助,也能够绘制出各种其它形状的图形,甚至不规则图形,但是总体而言还是非常麻烦的。而 SVG 则弥补了这方面的不足,让不规则图形的绘制变得更简单了。因此,用 SVG 绘图比用 HTML 和 CSS 要便利得多。

Canvas3D

无论是使用 HTML/CSS 还是 SVG,它们都属于声明式绘图系统,也就是我们根据数据创建各种不同的图形元素(或者 CSS 规则),然后利用浏览器渲染引擎解析它们并渲染出来。但是 Canvas2D 不同,它是浏览器提供的一种可以直接用代码在一块平面的“画布”上绘制图形的 API,使用它来绘图更像是传统的“编写代码”,简单来说就是调用绘图指令,然后引擎直接在页面上绘制图形。这是一种指令式的绘图系统。
Canvas2D 是浏览器提供的简便快捷的指令式图形系统,它通过一些简单的指令就能快速绘制出复杂的图形。由于它直接操作绘图上下文,因此没有 HTML/CSS 和 SVG 绘图因为元素多导致消耗性能的问题,性能要比前两者快得多。
但是如果要绘制的图形太多,或者处理大量的像素计算时,Canvas2D 依然会遇到性能瓶颈。
此外,因为 HTML 和 SVG 一个元素对应一个基本图形,所以我们可以很方便地操作它们,比如在柱状图的某个柱子上注册点击事件。而同样的功能在 Canvas 上就比较难实现了,因为对于 Canvas 来说,绘制整个柱状图的过程就是一系列指令的执行过程,其中并没有区分“A 柱子”、“B 柱子”,这让我们很难单独对 Canvas 绘图的局部进行控制。不过,这并不代表我们就不能控制 Canvas 的局部了。实际上,通过数学计算我们是可以通过定位的方式来获取局部图形的,在后续的课程中我们会解决这个问题。
Canvas 和 SVG 的使用也不是非此即彼的,它们可以结合使用。因为 SVG 作为一种图形格式,也可以作为 image 元素绘制到 Canvas 中。举个例子,我们可以先使用 SVG 生成某些图形,然后用 Canvas 来渲染。这样,我们就既可以享受 SVG 的便利性,又可以享受 Canvas 的高性能了。

WebGL

WebGL 是浏览器提供的功能强大的绘图系统,它使用比较复杂,但是功能强大,能够充分利用 GPU 并行计算的能力,来快速、精准地操作图像的像素,在同一时间完成数十万或数百万次计算。另外,它还内置了对 3D 物体的投影、深度检测等处理,这让它更适合绘制 3D 场景。

什么情况下使用WebGL

第一种情况,如果我们要绘制的图形数量非常多,比如有多达数万个几何图形需要绘制,而且它们的位置和方向都在不停地变化,那我们即使用 Canvas2D 绘制了,性能还是会达到瓶颈。这个时候,我们就需要使用 GPU 能力,直接用 WebGL 来绘制。
第二种情况,如果我们要对较大图像的细节做像素处理,比如,实现物体的光影、流体效果和一些复杂的像素滤镜。由于这些效果往往要精准地改变一个图像全局或局部区域的所有像素点,要计算的像素点数量非常的多(一般是数十万甚至上百万数量级的)。这时,即使采用 Canvas2D 操作,也会达到性能瓶颈,所以我们也要用 WebGL 来绘制。
第三种情况是绘制 3D 物体。因为 WebGL 内置了对 3D 物体的投影、深度检测等特性,所以用它来渲染 3D 物体就不需要我们自己对坐标做底层的处理了。那在这种情况下,WebGL 无论是在使用上还是性能上都有很大优势。