Weave.js:开源实时白板库
实时协作的可视化界面已经成为几乎每个人以某种形式使用的广泛采用的工具。虽然最终用户在Figma、Miro或Excalidraw等应用程序中享受生产级的精致体验,但开发团队仍然难以找到能够让他们从头开始构建自己的协作画布,而无需管理领域复杂性的库。
任何尝试过的人都知道这并不容易。构建真正实时、可扩展且适合生产的系统涉及解决渲染性能、共享状态的实时同步、复杂的用户交互,或棘手的问题,如冲突解决等挑战。
在探索了市场上可用的库后,没有一个能够完全满足我们设计团队的特定需求,因为我们需要更大的灵活性、更简单的状态管理,以及与我们的工作流程更深入的定制。
因此,我们决定自己构建。我们构建了Weave.js。
Weave.js是一个用于在HTML5画布上构建可视化协作工具应用程序的开源JavaScript库。
使用Weave.js库,团队可以开发:
- 在线白板
- 可视化脚本环境
- 图表编辑器
- 产品配置器
- 流程和旅程构建器
- 用于流程建模的内部可视化平台
- 或任何其他可视化编程工具。
1、需求:实时协作
Inditex的时尚设计师使用一个内部情绪板应用程序来创建可视化拼贴画,这些拼贴画捕捉了即将推出的时尚系列背后的想法、风格和灵感。
他们希望构建一个共享的情绪板,支持:来自图像、颜色、排版、纹理,偶尔还有文字的可视化组合,这些组合可以复制物理概念的感觉,允许团队成员之间的实时协作。
为了构建情绪板功能(以及团队未来可能需要的任何协作可视化工具),开发团队需要一个灵活的基础,能够处理画布渲染、实时状态同步和复杂的用户交互。
- 实时协作:它必须干净地处理冲突解决,以便多个用户可以一起进行编辑,而不会破坏共享状态。
- 用户界面(UI)组件灵活性:不同的团队需要不同类型的画布元素或交互,这需要一个可适应的界面。
- 渲染性能:在HTML5画布上绘制多个形状和元素(矩形、线条、自由绘制线条、文本、图像等)的简单且高性能的方式。
Weave.js成为了这个基础:一个端到端的库,用于为任何类型的团队构建自定义的实时可视化界面,从时尚设计师到物流部门、运输专业人员等。
2、面对四个技术挑战的四个抽象
无论是白板、情绪板、设计工具还是图表工具...当用户需要在可视化画布上实时协作时,所有交互式画布工具都有这些共同点:
- 渲染可视化元素:绘制基本图形如矩形、线条、文本、图像,甚至更复杂的元素,这些元素需要在HTML5画布上渲染。
- 自定义交互逻辑:由于Weave.js是无头的,用户如何在画布中添加、更新或删除元素可以根据可视化元素或应用程序的性质而变化。某些元素可能还需要自定义用户体验(UX)流程。
- 横向UI功能:基本功能(如缩放处理、移动、画布平移、元素选择或节点转换)需要保持一致,同时具有被编辑或增强的潜力。
- 同步状态模型:UI状态必须被共享和实时同步,这意味着:
- 高效的状态共享:整个状态不应在每次更新时传输。更改必须尽可能原子化。
- 冲突解决:来自不同用户的原子更改必须首先合并,然后与所有同行共享。这需要一个强大的冲突解决机制来维护一致性。
- 传输层:一个高效的传输层,用于将原子事务更改从客户端发送到中央单元,再返回给所有同行。
Weave.js通过四个可扩展的抽象解决了这些技术挑战:
- 通过节点渲染可视化元素,这些节点是将在HTML5画布上渲染的可视化元素(矩形、线条、文本、图像...)。
- 通过操作实现自定义交互逻辑,这些操作封装了用户交互逻辑流程,例如创建或与节点交互,或者将UX与UI和渲染生命周期解耦。
- 通过插件实现横向UI功能,这些插件是模块化的运行时扩展,添加或覆盖常见的横向功能(缩放处理、移动、画布平移、元素选择或节点转换)。
- 通过存储实现同步状态模型,这些存储处理共享模型状态(在客户端或服务器端),提供同步、传输、持久性以及感知和存在的逻辑。
3、解决方案:模块化架构
为了支持四个抽象(节点、操作、插件和存储)的凝聚力,Weave.js将它们组织在三个架构层中:
- 用于可视化输出和生命周期管理的画布渲染。
- 用于无冲突更新和通过CRDT算法离线支持的实时同步。
- 用于通过操作和插件处理输入事件和运行时行为的用户交互。
每个层都是隔离的、可扩展的,并且适合生产。这样,使用Weave.js的团队可以专注于产品功能和逻辑,而不必关注低级基础设施。
3.1 画布渲染:节点
节点是将在HTML5画布上渲染的可视化元素(矩形、线条、文本、图像...),经过增强以支持交互、样式和实时同步。
我们决定使用Konva.js,一个开源库,它提供了对HTML5画布API的抽象,以简化画布操作,使开发人员更容易创建交互式、动态的可视化元素。
为了高效地检测更改并更新它们,我们使用了一个自定义React Reconciler来管理渲染生命周期(无需JSX或手动渲染管理,因为Weave.js是UI无关的,不需要使用React)。
这种方法带来了:
- React的协调模型的性能和可靠性,这已经经过充分的战斗测试。
- 创建可视化组件的灵活性,允许组合。
- 每个画布元素的可预测生命周期。
3.2 实时同步:存储
Weave.js的 存储处理共享模型状态(在客户端和服务器端),提供逻辑用于:
- 同步:我们依赖于Yjs,一个开源库,它实现了CRDT(无冲突复制数据类型)算法,该算法允许由不同用户进行的原子更改被合并而无需冲突。
- 传输:Weave.js提供了自己的传输层,用于在客户端与中央服务器之间共享原子更改。
- 持久性:它支持一种解耦的方式,在不同的后端(数据库、存储解决方案等)上持久化共享状态。
- 感知和存在:Yjs还支持其他用户的实时感知,提供光标位置、选定元素或有人与画布上的特定项目交互等信息,使用户更容易协作和共同工作。
此外,在客户端,Weave.js集成了 SyncedStore API,以提供一种更简单的方式来通过JavaScript对象处理共享模型状态,同时为UI提供反应性。
所有同步逻辑都被抽象到Store中,它:
- 为客户端和服务器端提供API。
- 实现一个传输协议,允许客户端连接到服务器端。
- 管理原子更改到共享状态的合并,并将最终输出分发给所有协作工作的用户。
- 管理持久性(可选)。
- 共享感知和持久性事件(这些功能中的一些通过Weave.js内置插件开箱即用)。
3.3 用户交互:操作和插件
在Weave.js中,用户交互被实现为 操作,它们封装了用户交互逻辑流程,例如创建或与节点交互,或者将UX与UI和渲染逻辑解耦。
Weave.js还支持 插件,这是模块化的运行时扩展,可以:
- 增强用户交互(例如,上下文菜单、复制粘贴)
- 扩展画布行为(例如,缩放、平移、网格叠加)
- 添加协作功能(例如,实时光标、用户存在)
操作和插件都是隔离的、可配置的,并且易于扩展,因此交互逻辑保持清晰和可重用。
4、后端和前端架构
为了提供端到端的可靠性和控制,Weave.js将其三层架构扩展为前端和后端组件之间的明确分离。这种方法实现了强大的实时协作,同时为开发人员提供了对UI、交互和基础设施的完全控制。
4.1 后端:存储的服务器
Weave.js后端的主要职责是管理共享状态模型,并作为所有用户会话的真实来源。它围绕存储服务器构建,该服务器封装了同步、传输、持久性以及感知和存在。
存储是针对特定框架定制的,但也是可分叉的。默认情况下,Weave.js为Express.js提供了存储实现,它定义了一个通用API和核心职责。这种结构允许开发人员分叉并适应存储到其他框架,例如Koa、NestJS等。
4.2 前端:存储的客户端、节点、操作和插件
Weave.js前端主要负责UI渲染、处理用户交互,并连接到服务器端以提供实时同步。
由于Weave.js是UI框架无关的,它可以与React、Vue或任何其他前端堆栈清晰地集成。对于React,可选的辅助工具(提供者、钩子)是可用的...但不是必需的。
5、Weave.js是免费且开源的
在Inditex Tech,开源是我们构建方式的一部分。我们广泛使用开源解决方案,当内部工具解决更广泛的问题并达到适当的成熟度时,我们乐于回馈社区。
发布Weave.js遵循这一原则,因为它是经过维护的、开放扩展的,并且准备好实际使用:
- 可检查:同步层、渲染引擎和插件系统是完全可访问的。
- 可适应:与自定义后端集成,定义新的节点类型,或扩展交互。
- 可维护:模块化设计。
- 可靠:在实际生产场景中经过测试,并建立以持久使用。
这使得更容易构建协作画布工具,以适应您的堆栈、基础设施和产品逻辑,而没有架构约束。
我们还逐步发布其他项目,从基础设施层到AI工具,在Inditex Tech GitHub空间中。
6、尝试Weave.js,基于它构建,贡献
Weave.js的设计目的是为了让Inditex内外的任何人都能够扩展。如果它能帮助我们之外的团队,这正是我们的目标!
首先尝试我们的实时演示:
👉 https://weavejs.cloud.inditex.com/
这是一个使用Weave.js构建的白板应用程序示例,因此您可以与同行实时玩耍和测试它。
Weave.js提供了一个经过测试的、灵活的基础,用于构建协作白板、图表工具或任何需要实时同步和长期可维护性的基于画布的界面。该项目正在积极维护并建立以不断发展。
原文链接:Meet Weave.js: an open-source library to build whiteboards, canvas, and design applications
汇智网翻译整理,转载请标明出处