Canvas与SVG
前端图形化技术,主要包括Canvas绘图和SVG绘图两类。
Canvas早在十几年前就被火狐浏览器引入。Canvas通过Canvas.getContext(2d/3d)获得绘图上下文,采用绘制路径、填充路径、描边路径等操作绘制像素图片,并带有一定的矩阵旋转和偏移功能,总体与传统绘图流程一致。经过几年的发展,Canvas具备了3D上下文接口,其背后的WebGL,实际是OpenGL-ES的一个子集,可使用GPU渲染内容。实际上,通过改变视觉场的perspective,我们可以在3D的场景中获得一个伪2D的视角,实现2D的图形绘制的GPU加速。前几年这种方式甚为流行,但是苦于兼容性的问题,未被大量推广。
SVG图像是一种矢量图,采用XML方式标记和绘制。由于SVG是一种ML,所以操作、调试都非常容易,并且可以直接交互。与Canvas相比,SVG的最大不同在于:它不但是View,而且也是Model,算是一个真正的ViewModel。所以,SVG的体积与数据量级有直接关系,而Canvas所形成的图片体积只与尺寸有关,是一个恒定值。所以当我们面临一个未知场景的时候,使用SVG或Canvas,或者是SVG+Canvas,需要谨慎权衡。
总体来讲,无论是Canvas还是SVG,不管间接或者直接,它们能做的事情都差不多。
数据模型与图形交互
我们所熟悉的前端交互方式,比如click事件,实际是对一个DOM节点的操作,背后是浏览器DOM树接口提供的支持。
以Canvas为例,如果我们要在Canvas中实现数据展示和交互,应该如何去做?
上面我们提到了,Canvas会形成一张图片,但是一张“合并层”图片的所有像素是无差别的,所以Canvas本身并不能为我们提供图形交互的任何帮助。
所以我们应当把Canvas视为一个View的窗口,构造虚拟图层的树结构模型,再将Canvas相关事件映射模型中,驱动虚拟图层变化和重绘。
一个虚拟图层应包含的基本信息有:
· 矩阵信息(left|top|width|height|rotate)
· 样式信息(color|bgColor|opacity)
· 父节点、子节点(parent|children)
· 层排序(index)
在这个模型中,矩阵信息和样式信息都是可视信息,都可以成为数据表达的出口。
交互系统应具备:
· 事件系统(events|propagation)
· 节点查询(query)
· 动画系统(如果你有时间的话)
当Canvas的事件的发生位置映射到模型中时,应当根据矩阵信息进行虚拟图层捕捉查询(query),所以在模型设计中,将矩阵信息单独列出。
渲染工厂应做的事情:
· 调用Canvas渲染器,将模型绘制到
Canvas。
· 将Canvas的DOM层事件映射到虚拟模型,模拟事件捕获、冒泡等传递方式。
这样,你就可以有一个舞台对数据做可视化展示,并与数据进行互动。
需要注意的坑:
1. 当模型样式或者矩阵改变时,应当全图重绘。不要妄想局部重绘,那种计算开销或者研发时间开销性价比太低。
2. 事件系统真的没有捷径,要认真对待。
3. 如果你的模型中含有多边形节点(尤其是凹的),捕捉多边形有两条路:外包盒,或者,去看看图形学的书。如果你选择后者,做好了请给我发简历。