这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等.
富文本编辑器万里长征的第一步: 我们先开发一个基于canvas的富文本编辑器. 之后, 这个编辑器可以用在我们所有类型的文档中(文档, 表格, 幻灯片...).
对应的Github repo 地址: https://github.com/zhaokang555/canvas-text-editor
工欲善其事, 必先利其器. 首先我们来配置项目环境
1.1 初步构想我们的富文本编辑器项目包含两大部分:
编辑器本体
可以单独打包发布到npm上
暂定使用TypeScript开发
demo
若干纯静态网页, 用于展示编辑器的功能
暂定使用React + TypeScript开发
1.2 Vite我们使用Vite (https://cn.vitejs.dev/)作为我们的打包工具.
为什么使用Vite, 而不是Webpack呢? 可以看这里: https://cn.vitejs.dev/guide/why.html
我们新建2个文件夹:
src/demo:
用于存放所有的demo页
将原先src目录下的所有文件挪到这里
src/core: 用于存放编辑器本体
1.5 Hello, world!在src/core目录下, 新建一个文件: CanvasTextEditor.ts. 写上最简单的代码, 在canvas上渲染出一行Hello, world!:
修改src/demo/App.tsx, 初始化CanvasTextEditor:
添加SASS依赖, 并重置浏览器重置样式
添加文件 src/demo/main.scss
修改文件 src/demo/main.tsx, 引入main.scss
效果:
2. 富文本编辑器(MVP) 2.1 计算文字包围盒首先, 我们要找到一种方法, 来确定任意一段文字的包围盒. 为什么要确定包围盒呢? 因为:
当我们的鼠标hover在文字上方的时候, 需要产生相应的样式变化. 在DOM中, 这个功能是浏览器帮我们实现的. 但是现在在canvas中, 因为整个canvas对于浏览器来说, 就是一个栅格图像, 所以我们需要自己计算, 实现这个功能.
当我们在文字上方点击的时候, 需要在对应位置插入闪烁的光标.
CanvasRenderingContext2D 提供了 measureText API, 可以帮我们度量文字尺寸:
https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/measureText
https://developer.mozilla.org/zh-CN/docs/Web/API/TextMetrics
接下来, 我们来看一下这个API都返回了哪些有用的信息.
修改src/core/CanvasTextEditor.ts, 将measureText接口返回结果打印出来:
问题来了, fontBoundingBox和actualBoundingBox的区别是什么呢? MDN是这样描述的:
actualBoundingBox: 渲染文本的矩形边界
fontBoundingBox: 渲染文本的所有字体的矩形边界
看完文档, 还是不确定哪一个使我们想要的. 所以, 我们来给canvas上添加一些辅助线, 来帮助我们更形象地对比下两者的区别. 我们用红色画出actualBoundingBox, 用绿色画出fontBoundingBox:
注意, 为了方便计算, 我们将textBaseLine设置为top. 如果有小伙伴不熟悉textBaseLine, 可以看MDN提供的这张图: