从零开始, 开发一个 Web Office 套件 (2): 富文本编辑器
书接前文: 从零开始, 开发一个 Web Office 套件 (1): 富文本编辑器
这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等.
对应的Github repo 地址: https://github.com/zhaokang555/canvas-text-editor
2.5 观察一下幻灯片中的文本框

我们发现:
- 一个文本框中有若干行文字
- 一行文字中每个字符的大小, 样式都可能不一样 (废话)
- 但是, 上一篇文章中, 我们设置样式, 是以行为对象的
- 任意一个单独的字符, 都可以用鼠标选中 (废话)
- 但是, 上一篇文章中, 我们计算文字包围盒, 是以行为整体计算的
- 一行文字如果过长, 可以自动折行(默认行为, 可以修改)
- 当我调整文本框的宽度, 折行位置随之改变
- 文本框的位置和宽高都是可以调整的.
为了将来我们的web slides中能够用上CanvasTextEditor, 我们需要重构一下我们的代码.
2.6 重构Editor
- 修改
src/core/CanvasTextEditor.ts, 为编辑器加上位置属性, 宽高属性, 样式属性:

- 修改
src/demo/App.tsx, 给编辑器传入位置信息:

- 修改
src/core/CanvasTextEditor.ts:
实现render函数, 渲染一个临时边框:

添加renderBorderCirclor函数, 渲染边框上的8个圆形控制点:

- 最终效果:

2.7 设计Editor的整体架构
如下图所示:

一张幻灯片(Slide)中可能有多个编辑器(Editor), 一个编辑器中可能有多个段落(Paragraph), 一个段落中可能有多行(SoftLine), 一行中可能有多个字符(Char).
2.8 自顶向下实现
接下来, 我们按照自顶向下的方式, 来一步步实现这个架构:
2.8.1 Paragraph
- 修改
src/core/CanvasTextEditor.ts, 添加一个字段 paragraphs:

其中, 每个Paragraph要接收这几个参数:
chars: Char[]- canvas context
- left
- top
- maxWidth
为什么Paragraph的构造函数里, 要直接接收Char列表, 而不是SoftLine列表呢?
因为一个SoftLine并不是真正的一行, 而是根据每个Char的宽度和Paragraph的maxWidth, 实时计算出来的.
我们以后将会实现这样的feature: 如果用户调整了Editor的大小, Paragraph的maxWidth随之改变, 所有的SoftLine都会重新计算. 类似下图一样:

- 新建文件
src/core/CanvasTextEditorParagraph.ts

如上图, 在构造Paragraph时, 我们需要实现2个逻辑:
calcLayoutForSoftLines:- 根据maxWidth, 将所有的Char进行分组, 得到softLines. (类似我们上一篇中的splitContentIntoLines方法)
- 根据每个softLine中的Chars的大小, 计算每个softLine的大小
calcLayout:- 根据每个softLine的大小, 计算Paragraph的大小
然后, 我们来实现这两个逻辑:


2.8.2 SoftLine
新建src/core/CanvasTextEditorSoftLine.ts文件, 并在其构造函数中, 计算传入的所有chars的位置:

2.8.3 Char
- 新建
src/core/CanvasTextEditorChar.ts文件:

- 目前暂时先支持定制
color和fontSize两个样式:

- 另外, 要对外暴露
setPosition方法, 方便在SoftLine中为每个Char设置位置:

2.8.4 删除CanvasTextEditorText
由于之前src/core/CanvasTextEditorText.ts中的逻辑现在已经分散到了Paragraph, SoftLine, Char中, 所以现在可以删除这个文件.
2.8.5 最终效果

2.9 行内文字底部对齐
截止到目前为止, 出现了一个小问题: 一行内不同大小的文字, 他们的纵向对齐方式, 是以顶部为基线的.

为了看得更清楚, 我们给每个字符加上辅助边框和背景色, 修改src/core/CanvasTextEditorChar.ts:

修改src/core/CanvasTextEditor.ts, 再加上几个汉字:

这样, 可以更清晰地看出, 不同大小的文字是顶部对齐的:

为什么会出现行内文字纵向顶部对齐呢? 因为我们之前为了方便, 将textBaseline设置为了top:

这样设置之后, 包围盒顶部坐标 和 fillText(text, x, y)中的y坐标就相等了. 我们之前把它们统一记作top.
现在, 我们不得不放弃之前的偷懒方式, 将两者分别记录:
- 将
fillText(text, x, y)中的y记作top - 将包围盒顶部坐标记作
boundingBoxTop
修改src/core/CanvasTextEditorChar.ts:

看一下效果:

2.10 再议textBaseLine
这次行内文字纵向对齐的问题解决了, 可是新的问题来了: 为什么所有的文字整体上移了?
因为我们已经把textBaseLine恢复成了默认值alphabetic. 绘制文字的基线下移了, 且文字的坐标(left, top)没变, 所以相当于文字上移了.


为了解决这个问题, 我暂时想到了一种方法:
- 我们需要将每一行文字统一向下偏移一个长度
offsetY - 每一行的
offsetY, 取决于行内所有字符fontBoundingBoxAscent的最大值 - 在渲染行内的每个字符时, 统一加上这个偏移值
接下来我们来实现, 修改src/core/CanvasTextEditorSoftLine.ts:

效果:

文字上移的问题解决了, 棒!
(未完待续)
从零开始, 开发一个 Web Office 套件 (2): 富文本编辑器的更多相关文章
- 从零开始, 开发一个 Web Office 套件 (1): 富文本编辑器
这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 富文本编辑器 万里长征 ...
- 从零开始, 开发一个 Web Office 套件 (3): 鼠标事件
这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 对应的Github r ...
- 《从零开始, 开发一个 Web Office 套件》系列博客目录
这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 对应的Github r ...
- 从零开始, 开发一个 Web Office 套件(4):新的问题—— z-index
<从零开始, 开发一个 Web Office 套件>系列博客目录 这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office ...
- 从零开始,开发一个 Web Office 套件(5):Mouse hover over text
<从零开始, 开发一个 Web Office 套件>系列博客目录 这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office ...
- 从零开始,开发一个 Web Office 套件(6):光标 & Click 事件
<从零开始, 开发一个 Web Office 套件>系列博客目录 这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office ...
- 从零开始,开发一个 Web Office 套件(7):新的问题—— Click 事件的 z-index
这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office 套件(包括:文档.表格.幻灯片--等等). 博客园:<从零开始, 开发一 ...
- 从零开始,开发一个 Web Office 套件(9):拖动鼠标选中文字 Edge Case
这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office 套件(包括:文档.表格.幻灯片--等等). 博客园:<从零开始, 开发一 ...
- 从零开始,开发一个 Web Office 套件(10):捕获键盘事件,输入文字
这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office 套件(包括:文档.表格.幻灯片--等等). 博客园:<从零开始, 开发一 ...
随机推荐
- VS2013 or up version +常用插件
!!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist 下载地址: https://github.com/mohistH/vs2013_extens ...
- 【LeetCode】264. Ugly Number II 解题报告(Java & Python)
标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ https://leetcode.com/prob ...
- 【LeetCode】404. Sum of Left Leaves 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目大意 题目大意 解题方法 递归 迭代 日期 [LeetCode] 题目地址:h ...
- toString()、String.valueOf、(String)强转
1.基本类型 (1)基本类型没有toString()方法 (2)推荐使用String.valueOf(); (3)无法强转 =========补========= (String)是标准的类型转换,将 ...
- 【Java笔记】applet和html注意
1.首先记得extends Applet 泪目 2.如果不分包,HTML可以写 <applet code="HelloWorldApplet.class" width=150 ...
- 使用.NET 6开发TodoList应用(11)——使用FluentValidation和MediatR实现接口请求验证
系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在响应请求处理的过程中,我们经常需要对请求参数的合法性进行校验,如果参数不合法,将不继续进行业务逻辑的处理.我们当然可以将每个 ...
- 基于机器学习和TFIDF的情感分类算法,详解自然语言处理
摘要:这篇文章将详细讲解自然语言处理过程,基于机器学习和TFIDF的情感分类算法,并进行了各种分类算法(SVM.RF.LR.Boosting)对比 本文分享自华为云社区<[Python人工智能] ...
- InnoDB学习(八)之 聚簇索引
InnoDB中,表数据文件本身就是以主键为索引的B+树,树的叶子节点存放一条条表数据,此索引树被称为表的聚簇索引.聚簇索引也称为聚集索引,聚类索引,簇集索引,聚簇索引确定表中数据的物理顺序. Inno ...
- 物理机异常断电,linux虚拟机系统磁盘mount失败,导致无法启动; kubectl 连接失败
虚拟机 CentOS 7 挂载文件系统失败 上周五下班前没有关闭虚拟机和物理机, 今天周一开了虚拟机之后,发现操作系统启动失败. 原因跟 这篇文章描述的一模一样. 解决操作系统的文件系统挂载的问题之后 ...
- 第10组 Beta冲刺 (3/5)
1.1基本情况 ·队名:今晚不睡觉 ·组长博客:https://www.cnblogs.com/cpandbb/p/14018630.html ·作业博客:https://edu.cnblogs.co ...