在 2018 年初的时候,因为要组建可视化团队,接手公司内部的一些可视化项目,做了一些技术调研。
之前的一些可视化项目或者一些内部系统中的可视化功能,奇舞团主要是使用 d3.js 或 echarts 实现的。d3.js 由于使用上比较灵活,因此也应用的比 echarts 更广。
但是 d3 有一个缺点,就是虽然它主要的功能是处理基于数据的文档,其实对如何具体展示并没有特别限定,但是它的官方例子多半是使用 SVG 和 DOM 实现的,而考虑性能和跨平台性,我们的项目使用 Canvas 渲染要优于使用 SVG 和 DOM。
但是因为 Canvas 的 API 和 DOM/SVG 差别较大,因此要把例子移植为 Canvas 渲染,改动比较大,这样不利于开发人员快速学习和使用 D3 完成项目。
因此最初我们只是想实现一个很简单的库,封装 Canvas,让它对外暴露和 DOM/SVG 较一直的 API,这也就是实现 SpriteJS 这个库的初衷。
SpriteJS+d3 实现的地图效果及代码
在后来,随着库的设计不断深入和我们对可视化探索的不断深入,SpriteJS 逐渐完善成为一个独立的用于可视化底层的渲染库。与其他同类库相比,SpriteJS 主要有以下几个优势:
与 DOM 高度一致的盒模型以及 API,使得它与 d3.js 和其他适合操作 DOM 的库非常友好
支持属性继承,font、lineHeight、color 等许多属性为可继承属性,适合实现可视化的 UI 组件化
支持 CSS,可无缝对接文档中的样式,使用样式来控制 SpriteJS 的节点元素
支持标准 Flex 布局,也支持扩展其他类型的布局
支持 Web Animation API,也支持 CSS3 Animation 和 Transition
支持文字的排版,支持 line-break、word-break 等相关属性
支持外部时钟,可以很好地和其他 Canvas 库无缝集成
支持 React、PReact、Vue 等现代前端框架
跨平台,支持 Node.js 服务端渲染、支持微信小程序
SpriteJS 有与 DOM 高度一致的模型,它的对象以树状结构组织:
SpriteJS 的默认元素类型有 6 种,分别是 Scene、Layer、Group、Sprite、Label 和 Path。
其中 Sprite、Label 和 Path 分别是可带图片纹理的元素、可带文字的元素和可带 SVG Path 的矢量元素,Group 是容器,Layer 可以分层渲染,Scene 是根元素。
我们也可以使用 React 框架:
或者使用 Vue:
我们还可以使用文档中的 CSS 来控制 SpriteJS 元素的样式:
这些特性使得我们能够使用 DOM 的方式来构建我们的图表和 UI 组件库,实际上我们也正是使用 SpriteJS 的这一系列特性来实现类似于 element-ui 这样的 UI 设计系统的。
基于 SpriteJS 的图表库
那么如何实现上面这些特性,尤其是高性能地实现这些特性呢?
SpriteJS 对上述特性的具体实现比较复杂,有兴趣的同学可以自己去浏览 GitHub 仓库的源代码,在这里将简化的流程试解释一二。
一、渲染时机
SpriteJS 的更新机制与传统的 Canvas 框架不同,不是固定时间刷新的,而是采用类似 DOM 的方式在属性更新的时候才刷新:
SpriteJS 有属性比较机制,当属性变化的时候,标记更新并通知 Layer,这时候 Layer 会启动一个 Promise 任务等待下一帧并更新画布。
如果涉及到 Label 或带有 Layout 的 Group,还有可能会触发 retypesetting 和 relayout 操作,如果使用文档中的 CSS,涉及到的属性恰好包含在 CSS 规则中,那么还可能会触发更复杂的 updateStyles 操作。
总之,SpriteJS 有一套判断机制,控制 Canvas 更新的时机,并确保 retypesetting、relayout、updateStyles 等耗性能的操作尽可能减少,以保证渲染性能。
文字排版
Flex 布局
二、缓存和批次
为了提升性能,SpriteJS 支持自定义缓存策略和批次渲染。
如果渲染对象的形态可枚举,我们可以采用自定义的缓存策略,利用少量的缓存对象来大大提升性能:
缓存策略
或者通过批次渲染的方式,使用起来更加方便:
批次渲染
三、SVG 和过渡动画
SpriteJS 对 SVG-Path 的支持非常的好,不仅能支持 Path 的绘制,还能支持过渡动画:
SpriteJS 支持 Web Animation API,因此可以用标准的 Web Animation 动画,也可以用 CSS3 的 keyframe 动画:
四、选择器和 CSS
在对 CSS 的支持方面,SpriteJS 支持几乎所有的 CSS3 选择器,包括元素选择器、类选择器、属性选择器和伪类选择器。而且在文档里可以将 DOM 和 SpriteJS 的选择器混合使用,就像是使用原生的 DOM 一样操作 SpriteJS 的元素。
用 CSS 定义样式
SpriteJS 支持大部分 DOM 的 CSS 属性,对于一部分 SpriteJS 独有的属性,可以使用–sprite-属性名的方式设置。
五、外部时钟
SpriteJS 支持外部时钟,因此可以很好地和第三方库联合使用:
SpriteJS 与 CurveJS 一同使用
SpriteJS 与粒子系统
六、跨平台
SpriteJS 依赖于独立 Canvas 环境而不依赖于 DOM,因此它有很好的跨平台属性,可以在 Node.js 中通过 node-canvas 渲染使用,也可以支持微信小程序。
SpriteJS 与微信小程序
目前 SpriteJS 主要用于 360 可视化项目中,作为底层渲染库使用,在未来会进一步提升它的跨平台能力,以及渲染性能,还会集成 WebGL 增加 3D 渲染的能力。
除了上面介绍的这些之外,SpriteJS 还有许多有用的能力,比如屏幕适配、资源预加载、css 雪碧图、.9 背景图片等等,具体可以参考官方文档。如果有做可视化项目的小伙伴,可以试试这个库,相信你们会有惊喜的~
GitHub 仓库地址:
(点击阅读原文直达)
作者介绍:
月影(十年踪迹),360 前端技术委员会委员。奇舞团技术总监,JavaScript 程序猿,目前重点关注前端框架和新技术应用。
本文转载自公众号携程技术(ID:ctriptech)。
原文链接:
https://mp.weixin.qq.com/s/8J-uDw0qwDbj21UkQch2KA
评论