开源白板工具 Excalidraw 架构解读

news2024/11/23 13:36:25

本文讲解开源白板工具 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 在图形编辑器上几个比较基础但很重要的功能,希望对你进行图形编辑器的架构有帮助。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pycharm一直没显示运行步骤,只是出现waiting for process detach

pycharm一直没显示运行步骤,只是出现waiting for process detach;各类音乐免费软件;最棒的下载torch-geometric-CSDN博客(不太推荐)我强烈推荐这个:_waiting for process detachhttps://blog.csdn.net/weix…

APScheduler框架使用

目录 概述架构重要概念Job 作业Trigger 触发器Executor 执行器JobstoreEvent 事件调度器 工作流程使用 概述 APScheduler(advanceded python scheduler)基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能,使用起来十分…

网络层常见协议——IPV4、IPV6、ARP、ICMP、QoS

目录 1、IPV4 协议 IPV4 地址的组成: IPV4地址的分类: 关于多播和组播: 常见组播地址分类: 特殊的 IPV4 地址: 私有地址和公有地址: 私有地址的范围: 子网划分: 子网掩码&…

Codeforces Round 665 (Div. 2) (A-F)

A.Problem - A - Codeforces (1)题意 给你个X轴,初始A点在n这个位置,O在源点0,问你要把B放在哪才能让|AB-BO| k,最小化A需要移动多少次。 (2)思路 直接分情况套路即可。 &#xff0…

uwb人员定位系统:人员轨迹实时定位

UWB定位系统是一种基于超宽带技术的定位系统。它与传统的通信技术不同,不需要使用载波,而是通过发送和接收具有纳秒或微妙级以下的极窄脉冲来实现无线传输。这种系统的优势包括低功耗、对信道衰落不敏感、抗环境能力强、不会对同一环境下的其他设备造成影…

LINUX 基本命令

​ 一 展示当前目录下的内容 $ ls查看当前目录 pwd // /home/winnie二 mkdir 三 touch-cat-more 进入翻页后 通过键盘 q 退出翻页 b 翻上一页 四 cp mv rm mv 如果 mv 2.txt 5.txt (因为5.txt不存在,或者说他是个文件不是路径),故此操作将2.txt更名…

openfire 4.7.5 Web插件开发

文章目录 1、openfire服务端下载安装1.1、openfire解压运行1.2、Spark安装和登录 2、openfire插件开发2.1、基于servlet开发http接口2.2、基于Jersey开发http接口2.3、WEB UI页面开发2.4、上传插件2.4.1、访问servlet接口效果2.4.2、访问Jersey接口效果2.4.3、访问页面效果 Ope…

撰写博客的工具记录

文章目录 前言TyporaPicgoGitee 免费图床ScreenToGifPointofix和Snipaste墨滴社区小结 前言 本文主要目的是记录和分析自己在写博客和相关文档时所用到的工具,单纯记录。按照一篇文章从0到发布的场景进行叙述。 Typora Typora是一款Markdown编辑器。Markdown的优…

游戏制作资源推荐

教程 创建僵尸第一人称射击游戏 | 虚幻引擎 5 初学者教程https://www.youtube.com/watch?vqOam3QjGE8g ​​​​​​​ 虚幻商城免费资产 人物资产 各种角色应有尽有 关键词:paragon ;推荐程度:三颗星

C. MEX Repetition

题目:样例: 输入 5 1 2 1 3 1 0 1 3 2 2 0 2 5 5 1 2 3 4 5 10 100 5 3 0 4 2 1 6 9 10 8输出 1 2 0 1 2 1 2 3 4 5 0 7 5 3 0 4 2 1 6 9 10 思路: 从题目和样例中,我们可以知道,从一个数组中,按照包括0的自…

leetCode 121. 买卖股票的最佳时机 贪心算法

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…

2023年汉字小达人市级比赛在线模拟题来了,四种练习助力好成绩

2023年第十届汉字小达人比赛区级自由报名活动已于9月30日结束,尽管最终晋级市级比赛的名单还需要在11月初发布(有一些学校的校级选拔还没结束),但是许多小朋友已经开始准备市级比赛了。 根据往年的经验,实际比赛也是在…

软断言你也学不会

断言是测试用例的一部分,也是测试工程师开发测试用例的核心。断言通常集成在单元测试和集成测试中,断言分为硬断言和软断言。 硬断言是我们狭义上听到的普通断言:当用例运行后得到的[实际]结果与预期结果不匹配时,测试框架将停止测试执行并抛…

华为云云耀云服务器L实例评测|ClickHouse部署及压测

文章目录 前言📣 1.前言概述📣 2.安全设置📣 3.ClickHouse安装✨ 3.1 申请服务器✨ 3.2 安装前准备✨ 3.3 RPM安装包✨ 3.4 配置文件✨ 3.5 使用ClickHouse 📣 4.ClickHouse压测✨ 4.1 下载数据✨ 4.2 解压数据✨ 4.3 创建数据库和…

(c++)类和对象 下篇

目录 1.再次了解构造函数 2. Static成员 3. 友元 4. 内部类 5.匿名对象 6.拷贝对象时的一些编译器优化 1.再次了解构造函数 1.1 构造函数体赋值 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。 class Date { pub…

火山引擎 ByteHouse:如何提升 18000 节点的 ClickHouse 可用性?

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 ClickHouse 是业内被广泛使用的 OLAP 引擎。当集群规模过大时,ClickHouse 则面临使用局限性的问题。如何提升 ClickHouse 的可用性,成为困扰…

Python实时采集Windows CPU\MEMORY\HDD使用率

文章目录 安装psutil库在Python脚本中导入psutil库获取CPU当前使用率,并打印结果获取内存当前使用率,并打印结果获取磁盘当前使用情况,并打印结果推荐阅读 要通过Python实时采集Windows性能计数器的数据,你可以使用psutil库。psut…

怎么通过portainer部署一个vue项目

这篇文章分享一下今天通过docker打包vue项目,并使用打包的镜像在portainer上部署运行,参考了vue-cli和docker的官方文档。 首先,阅读vue-cli关于docker部署的说明 vue-cli关于docker部署的说明https://cli.vuejs.org/guide/deployment.html#…

SpringCloudAlibaba 相关组件的学习一

目录 前言 系统架构演变 1、单体架构 2、垂直架构 3、分布式架构 4、SOA架构 5、微服务架构 一、微服务架构的介绍 1、微服务架构的常见问题 2 微服务架构的常见概念 2.1 服务治理 2.2 服务调用 2.3 服务网关 2.4 服务容错 2.5 链路追踪 3、微服务架构的常用解决…

第2篇 机器学习基础 —(1)机器学习方式及分类、回归

前言:Hello大家好,我是小哥谈。机器学习是一种人工智能的分支,它使用算法和数学模型来使计算机系统能够从经验数据中学习和改进,而无需显式地编程。机器学习的目标是通过从数据中发现模式和规律,从而使计算机能够自动进…