开源白板工具 Excalidraw 架构解读

2023-10-03 13:06

本文主要是介绍开源白板工具 Excalidraw 架构解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文讲解开源白板工具 Excalidraw 的架构设计。

版本 0.16.1

技术栈

Vite + React + TypeScript + Yarn + Husky。

脚手架原来是用的是 Create React App,但这个脚手架已经不维护了,一年多没发布新版本了。

目前市面上比较流行的 React 脚手架是 Vite,所以几个月前 Excalidraw 把脚手架替换为了 Vite,很合理。

使用了 React 去实现 UI 层,国外还是 React 流行一些。

TypeScript 用于类型标注,减少一些类型错误。

Yarn 是包管理器,没有使用 monorepo。

Husky 是 git hook 库,会在本地 git commit 做一些校验。

架构设计

模块耦合比较严重,基本核心逻辑都放在 App 类组件里,导致其所在的 App.tsx 文件行数达到 8000+ 行。

数据状态大多保存在 App 类组件的 state 属性中。

在这里插入图片描述

可以看到,编辑器的内核和 UI 是强绑定的,完完全全耦合在一起了。

如果你想把这个项目的 UI 层改成基于其他框架,比如 Vue,那基本是要重写了。

但一些复杂的方法也是会抽离出来放到一个单独的文件里,比如 group.js 里放的都是和编组相关的逻辑,但使用的是函数风格,里面全是零散的函数,没有使用面向对象的写法。

渲染方案

Excalidraw 选择了 Canvas 2D 渲染方案。

Canvas 2D 的优点是 API 做了高级封装,对开发者非常友好,缺点是其并不是为了高性能而设计的,很多底层图形计算是基于 CPU,不能很好地利用 GPU 的并行计算能力。

一句话就是性能较差,但比 SVG 好。

图形库使用了开源库 rough,一款基于 Canvas 2D 和 SVG 的手绘风图形库。

图形工具

this.state.activeTool.type 会记录当前使用的是哪个工具。

工具没有抽成类,它们的逻辑混合写在鼠标事件响应函数 handleCanvasPointerDown、handleCanvasPointerMove、handleCanvasPointerUp 中。

完全耦合在一起了。

如果我来做,我会抽一个工具管理类,然后实现各种工具类,把它们注册到工具管理类里。

在这里插入图片描述

这样写维护性非常差,你要改某一个工具,比如创建矩形的逻辑,你不得不看其他工具的逻辑,要从这一坨分支里面找到创建矩形操作会走的逻辑。

图形树

图形树的状态保存在 Scene 类中:

  • nonDeletedElements:一个拍平的图形元素数组;
  • elements:历史创建的所有图形,被删除的图形还能在这里找到。

有组的概念,图形对象的 groupIds 数组属性表示当前元素在哪些组下。

渲染

渲染图形树的入口方法是 renderStaticScene。

会顺序递归图形树的图形,将它们渲染出来。

没有使用脏矩形局部渲染。

图形拾取方案

图形拾取使用了几何法

不同图形的的渲染逻辑的判断逻辑是写在一起的。

历史记录

历史记录的逻辑在 History 类中。

Excalidraw 维护了两棵树,当图形树发生了变更时,会对一一比两棵树中图形的版本号。

如果相同,说明没发生变更,不添加新的历史记录项;否则,就创建一个历史记录项。

被更新的图形会拷贝一份,保存到 elementCache 里。

stateHistory 和 redoStack 记录的是整棵树的图形 id 和新的版本号,撤销重做时,会从中取出,去更新对应的图形为指定的版本。

国际化方案

国际化代码在 i18n.ts 文件中。

使用了状态管理库 jotai,去通知组件更新。

渲染性能优化

剔除, 视口外的图形不渲染,很基本的操作。

缓存, 图形到手绘风是需要计算的,Excalidraw 会把这个结果缓存下来,如果只是几何属性的改变,就能直接使用缓存可以减少计算量。

缩放进行防抖,延迟图形树的重渲染。

滚动事件频率很高,每一帧都重渲染,对于图形很多的情况下,Excalidraw 是吃不消的,因为 Canvas 2D 性能并不高,这时候可以考虑节流或防抖去减少重渲染的次数。

我们发现,通过滚轮放大画布时,Excalidraw 的图形是模糊的,鼠标释放时才真正重渲染。

结尾

Excalidraw 作为一款白板工具,功能很完善,美中不足的地方就是代码写得太面条。

本文透析了 Excalidraw 在图形编辑器上几个比较基础但很重要的功能,希望对你进行图形编辑器的架构有帮助。

我是前端西瓜哥,欢迎关注我,学习更多图形编辑器知识。

这篇关于开源白板工具 Excalidraw 架构解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/345

相关文章

对Django中时区的解读

《对Django中时区的解读》:本文主要介绍对Django中时区的解读方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景前端数据库中存储接口返回AI的解释问题:这样设置的作用答案获取当前时间(自动带时区)转换为北京时间显示总结背景设置时区为北京时间 TIM

Maven 插件配置分层架构深度解析

《Maven插件配置分层架构深度解析》:本文主要介绍Maven插件配置分层架构深度解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Maven 插件配置分层架构深度解析引言:当构建逻辑遇上复杂配置第一章 Maven插件配置的三重境界1.1 插件配置的拓扑

Java中的内部类和常用类用法解读

《Java中的内部类和常用类用法解读》:本文主要介绍Java中的内部类和常用类用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录内部类和常用类内部类成员内部类静态内部类局部内部类匿名内部类常用类Object类包装类String类StringBuffer和Stri

Spring Validation中9个数据校验工具使用指南

《SpringValidation中9个数据校验工具使用指南》SpringValidation作为Spring生态系统的重要组成部分,提供了一套强大而灵活的数据校验机制,本文给大家介绍了Spring... 目录1. Bean Validation基础注解常用注解示例在控制器中应用2. 自定义约束验证器定义自

Linux系统调试之ltrace工具使用与调试过程

《Linux系统调试之ltrace工具使用与调试过程》:本文主要介绍Linux系统调试之ltrace工具使用与调试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、ltrace 定义与作用二、ltrace 工作原理1. 劫持进程的 PLT/GOT 表2. 重定

使用Java编写一个字符脱敏工具类

《使用Java编写一个字符脱敏工具类》这篇文章主要为大家详细介绍了如何使用Java编写一个字符脱敏工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、字符脱敏工具类2、测试工具类3、测试结果1、字符脱敏工具类import lombok.extern.slf4j.Slf4j

JVM垃圾回收机制之GC解读

《JVM垃圾回收机制之GC解读》:本文主要介绍JVM垃圾回收机制之GC,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、死亡对象的判断算法1.1 引用计数算法1.2 可达性分析算法二、垃圾回收算法2.1 标记-清除算法2.2 复制算法2.3 标记-整理算法2.4

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Java中的工具类命名方法

《Java中的工具类命名方法》:本文主要介绍Java中的工具类究竟如何命名,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java中的工具类究竟如何命名?先来几个例子几种命名方式的比较到底如何命名 ?总结Java中的工具类究竟如何命名?先来几个例子JD