本文是对流程图形化 Node & Flow— 流程图 技术选择与抽象设计(作者:雷文宇)一文的批注解读。
Web实现图形方式有3种:纯DOM节点、SVG矢量图和Canvas方式。纯DOM节点这种方式是一个基于旧版本浏览器,非主流Web绘图方式,并且性能不高的。当现主流的实现方式有两种:SVG和Canvas,SVG矢量DOM节点绘制技术,由于其类似于DOM的工作方式,所有绘制出的图形都是以DOM节点的形态存在的。当图形不复杂并且单位面积内所需要绘制的节点数少的时候,它的效率很高实现代价最小。而Canvas是最典型的像素绘制技术,也就是位图(Bitmap)绘制技术。它基础就是通过算法去绘制所有的点,当图形复杂且有堆叠时,它的效率会比较高。值得注意的是,当显示区域越大时,也就是分辨率越大时,它所需要的性能资源也就越多。
SVG是基于盒模型的每一次绘制都有可能改变文档节点之间的关系,不太适用绘制真正的矢量场景。典型的例子就是画布的缩放。使用SVG方式缩放画布,只能改变画布的大小(就是改变画布坐标系单位与标准参考坐标系的比率)。虽然,SVG节点本身不会失真(因为,SVG节点自身是个矢量图)。但SVG内的节点图标,或者其它非矢量元素都会随着自己的参考坐标系变化而失真(所以需要所有节点图标或其他元素作同比例缩放-transform)。即使所有的节点都用矢量图形。也会有一个更严重的问题就是,SVG画布缩放最终看到的结果就是所有的东西都变大了,或者变小了。节点间的关系并不会随着缩放产生变化。比如,当节点很多的时候。你想看一下全局的流程执行情况,于是就把画布缩小,这时你就会发现,所有东西都变小了,甚至线也变小了,节点也小的都看不清楚了。如果可以像地图那样进行矢量缩放,就可以解决这个问题。也就是在不同的缩放情况下,只突出最想表现的东西或者节点关系。还有一点,缩放并不会改变图元的真正x,y,所以依赖图元坐标而判断的点击事件也需要对图元坐标乘以相应缩放比例。
想要做到矢量缩放,就要使用矢量缩放算法。这是绘图技术的基础算法。由于要实时绘制(屏幕更新技术的绘制也能做到非实时)节点关系。这样的工作很不适合在以解析文档描述为基础的DOM形态节点上完成。因为,DOM文档是解释性的,性能本来就不高。它的主要还是突出静态块的关系。
HTML5推出了一个更适合绘图的技术Canvas。什么是Canvas。官方的解释是:元素提供了一个空白绘图区域,可以使用 APIs (比如 Canvas 2D 或 WebGL)来绘制图形。这个区域是专门用来绘制图形的。并且,提供了专门的API来完成更高效的绘制。从兼容性的角度看。Canvas完全不用考虑在不同设备或不同浏览器的表现差异。因为,Canvas的绘制是基于像素与算法的。本质上说,如果你要绘制图形。在任何设备上你能使用的单位都是基于像素的(当然,你可以通过单位换算转化成你要的任何长度单位)。Canvas没有节点的概念,所有的业务逻辑节点,都是算法上的节点,不是像DOM节点那样的文档节点。既然节点都是逻辑上,这样算法可优化的途径就变的非常多了。本质上在Canvas上画图就是在计算像素或坐标点的集合。是线性的几何绘制,会比单纯的盒子模型来的更直接。
现在很多浏览器都专门针对Canvas绘图进行了性能优化。甚至可以直接使用目标设备上的GPU资源。Canvas这种绘图方式,很早就有了。各种图形技术细节也已经很成熟。所以,Canvas一定是绘图的最佳方式。
以Canvas方式绘图的库很多。比如D3JS、PaperJS、RaphaelJS、GoJS等。也有很多已经对流程图进行基础封装的库。大多都是开源的。
绘图方式的重构肯定是不可逃避的。SVG只是一个过度方式。Canvas才是最终解决绘图问题的途径。