Airbnb 爱彼迎 visx 项目介绍
Airbnb 爱彼迎 visx 项目介绍
历经四年的研发,三年爱彼迎生产环境的实战,在使用 Typescript 重新编写之后,我们的 Airbnb 爱彼迎 visx 已经迭代到v1.6.1版本!
今天,我们想围绕 React 底层可视化编程的话题,和大家分享 visx 项目研究的心路历程。
在爱彼迎,我们以统一可视化技术栈为目标一路探索,创造了 visx 。visx 是一套爱彼迎前端可视化编程的原语集,它将 D3 的强大和 React 的乐趣融为一体,具有以下显著优势:
- 轻量级的依赖包。visx 项目被分成了多个包,用户可以从小处着手,按需安装依赖包。
- 无预设使用的倾向。用户可以使用自定义的状态管理、动画库和 Css-in-JS 解决方案。大多数情况下,你的 React 应用已拥有了一套完善的动画、主题及风格样式的配置,visx 不会重复添加新的配置,可直接与现有方案集成。
- 非可视化图库。通过使用可视化原语,你可以从 0 到 1 制作一个属于自己的制图组件库。一切尽在掌控。
最赞的是,visx 就是 React!只要你会用 React ,就能很快上手用 visx 做出酷炫的可视化效果。visx 所有的 API 都是标准的 React API,两者的代码模式也很类似。对于任何一个 React 的代码库来讲,visx 都有一种“回家”的感觉。
前端开发者如何做可视化?
如今,越来越多拥有不同背景的人开始接触和研究数据可视化,我们需要一个更全面的可视化创作框架,来满足多样性的技能背景和项目需求。
前端开发者会接到越来越多的 Web 端可视化需求。虽然目前我们有很多现成的前端可视化框架,从D3,Highcharts,Plotly,ECharts,Victory,G2,Recharts,react-vis,vega,vega-lite,再到 Semiotic 等等,但我们在评估完这些现成的可视化库在爱彼迎平台的使用后,发现它们至少在某一方面存在着不足。
我们的前端工程师会关注这三个方面:
- 容易上手(创作和维护一个可视化需要多大的学习成本?)---- 很多的前端工程师并不是可视化专家,像 D3 的 imperative API(命令式编程API)或者 vega 自定义的语法都需要一定的学习成本和思维模式的转换。对于大公司而言,学习成本是不可忽视的。我们期望的理想状态是工程师可以像上手其他的前端库一样,快速上手一个可视化的开发库。
- 表现力强(是不是所有的想法都可以快速落地和呈现出来?) ---- 为了在大型公司运用统一的可视化框架,我们希望它既能支持简单的图表,比如在爱彼迎官网上的一些应用组件,又能支持高度定制化的内部数据产品。我们不希望制图组件库本身的局限性限制我们的设计能力。
- 高性能 ---- 开发像爱彼迎这样的产品应用,前端开发者必须能够优化运行速度和控制包大小。我们不想要那种「全家桶」式的可视化框架,它包含了内置动画,自定义风格组件及特殊事件,会降低运行速度,而且很容易让捆绑包的尺寸变得过大。
有人曾提到,可视化工具经常要在表现力强和容易上手之间进行权衡。如何创建一个「鱼和熊掌可以兼得」且高性能的组件库呢?答案就是 React 。
以 React 为核心的可视化原语
近年来,React 已经成为了主流 Web 开发框架,这主要归功于它拥有简洁明了的 API 。前端开发者普遍对于 React 很熟悉,并且现在已经有大量关于 React 应用性能调优的资源了。合理利用 React 和它的生态系统可以降低学习成本,提高性能,呈现更强的表达能力。
当我们描述这个愿景的时候,有两个常见的问题:
“D3 的表现力已经很强了 —— 为什么不在 React 里使用 D3?”
当然,你可以使用 D3!但是 D3 和 React 都会进行 DOM 的操作,最好的办法是使用 D3 来进行数学运算、使用 React 来进行 DOM 操作。需要注意的是,只使用 D3 来做数学运算的话,将导致 D3 中很多基于 DOM 的功能无法使用:比如选择连接(selection.join),缩放(zoom), 拖拽(drag), 刷子(brush), 和过渡效果(transitions)。另外,就像我们上面提到的,D3 本身也有它的学习曲线。我们还是希望开发者们能像写源生 React 代码一样,运用标准的 API 和他们熟悉的模式来完成可视化编程。
“为什么不使用现成的 React 可视化库?”
我们在调研中发现(图1),现成的 React 可视化库都是高级抽象的,并且为了方便使用,它们都被优化过(几行代码就能绘制出很炫酷的可视化),这样做的代价是牺牲了表现力。目前还没有一个库能提供 D3 原语那样强大的表达能力,而且很多库的计算、动画、状态管理、样式和渲染都是被封装过的,并不允许我们在产品里实现优化。
图1. 为了容易上手,大多数 Web 端的可视化库都进行过优化,但缺点就是会限制可视化图表的表现力。visx 在表达能力和 React 的支持方面可谓是独具一格。通过图 1 里的白色区域可以看出,我们有很大的空间来设计一个表达能力强的 React 库。我们希望可以使用 React 顶级 API 创造出底层的可视化原语,让前端可视化变得“容易上手”,“表现力强”和“性能流畅”,让任何前端开发者都能触手可及。于是,我们的 visx 诞生了 。
visx 到底是什么?
visx (又名 vx)代表可视化组件(Visualization Components),它是一套包含 30 多个独立 React 可视化原语包的集合。这些包分为几个类别(图 2)。它对于状态管理、动画和样式等没有预设使用的倾向,因此可以与任意 React 代码库集成。此外,它对模块化的强调(类似于 D3)可以让你仅通过添加所需的包就能创建出可复用的图表库或自定义的一次性图表,以此减少编译之后的总包大小。
图2. visx 是一个包含 30 多个独立包的模块化套件,用于抽象 React 可视化工程中常见任务的解决方案。FAQS
Visx 是如何使用 D3 的?
有一些包使用 D3 进行数学和布局计算,使用声明性的 React API 在功能上映射底层的 D3 包——例如 @visx/axis、@visx/geo、@visx/hierarchy 和 @visx/shape。另一些包则取代了 D3 的 DOM 操作功能,并为 React 带来了顶级交互原语——例如 @visx/brush、@visx/drag 和 @visx/zoom。
什么事情是 visx 能做,但是 D3 做不了?
当我们在 React 中构建“完美像素”级的可视化任务时,会设计一些常见工程问题的抽象解决方案,它们和 D3 完全不同。其中许多包抽象和简化了 React 中具有挑战性的测量任务,并且简化了 SVG 的 API。以下是具体的例子:
@visx/tooltip
Tooltip(工具提示)是很常见的可视化元素,但是落实到交互细节上非常复杂。这个包通过 React hooks (useTooltip)和 HOC 高阶组件(withTooltip)抽象了工具提示内容、坐标和是否可见等状态管理。此外,它还简化了 Tooltip 的渲染复杂度,例如为了避免被容器裁剪的问题,它能够实现自动定位;为了避免 z-index 堆叠问题,它能够在 React Portal 内完成渲染。
@visx/text
在HTML里,长文本可以很容易地通过 CSS 实现文字换行,但是原生的 SVG 1.1 并不支持文本换行。如果想在 React 里以及纯 JavaScript 里实现类似效果,通常需要先渲染隐形的 DOM 元素来测量字体大小,并且手动计算行拆分。而@visx/text 这个包对这个问题进行了抽象化,使得在可视化编程中处理冗长文本变得轻松优雅。
@visx/responsive
使用HTML创建响应式 Web 界面应用很容易,但要让基于 SVG 和 Canvas 的图表支持响应式布局,则需要精确到像素的测量。在 React 里,这会涉及很大的工作量。@visx/responsive 这个包提供了各种辅助工具来获取屏幕以及图表容器的大小尺寸,你的图表可以轻松地调整为可响应模式。
@visx/gradient , @visx/pattern
颜色渐变和图案填充大大地扩展了图表的设计空间,使图表获得独具一格的美感。但在 SVG 里定义这些样式是冗长且复杂的。@visx/gradient 和 @visx/pattern 这些包极大地简化了样式定义的语法,让更多人能享受到高颜值的图表。
我们可以用 visx 做啥?
在过去的几年中,我们在很多的内部数据工具及爱彼迎(http://Airbnb.com)都用到了 visx(图 3)。
图3. 这是我们使用 visx 做出的可视化图(从左上角顺时针顺序分别是:包含依赖关系的数据管道任务分析 Gantt 图;用来解释组织结构的 Donut 图;彩虹径向时间线图;度量业务报告图;服务之间的通信可视化图)对于一些常见的、简单的应用,我们用 visx 做了高阶、可复用的图表库,这可以减少重复代码(图4)。
图4. visx 本身很底层,但可以使用它构造出高阶、可复用的图表。它可以为你的 Web 应用创建自定义的可视化。visx 很有趣,但是我喜欢 D3
我们同样喜欢D3!
visx 项目的演进过程是什么样的?
四年以来,visx 的演变围绕三个主要的工作展开:
- 功能: 我们将 visx 整合进爱彼迎 Web 应用的时候,不可避免地遇到了很多限制(例如,交互的不支持,图表类型和布局的缺失),同时发现我们一直在「重复造轮子」。随着时间的推进,我们在已有的包里添加了很多新功能,又以新包的形式贡献了一些新的解决方案。
- 文档:只有当我们使用的时候,visx 30 多个包的功能才实现了它们的价值。更加简单易读、完善的文档一直是 visx 社区中的一大需求。我们近期在不断地完善文档,增加了对所有包的覆盖;每个包里的 API 都有相关的示例(类似于 http://bl.ocks.org 社区);为了便于修改和分享,每个示例都有 codesandbox 的链接。此外,为了品牌重塑,我们还重新设计了我们的项目网站(图5)。
- 质量:visx 最开始是一个 JavaScript 项目,后来为了提高类型安全性和开发体验,我们使用 TypeScript 重新编写了该项目。TypeScript 现在是爱彼迎 Web 端开发使用的官方语言,我们用 ts-migration 工具简化了语言的转换。最近,我们还提高了 visx 单元测试的覆盖率,并添加了 Happo 屏幕截图测试。
原文作者:Chris C Williams,翻译:Carl Liu, 校对:Yiqi Jia,Tony Jiang,Chongfu Peng,Hengyu Zhou。
感谢阅读!如果你想了解关于 visx 的更多进展,可以在 Github 上关注此项目(https://github.com/airbnb/visx),或在 http://Airbnb.io 上查看相关文档和样例。
如果你想了解关于爱彼迎技术团队的更多进展,欢迎关注我们的 Github 账号以及爱彼迎技术团队微信公众号。