书接前文: 从零开始, 开发一个 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

  1. 修改src/core/CanvasTextEditor.ts, 为编辑器加上位置属性, 宽高属性, 样式属性:

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

  1. 修改src/core/CanvasTextEditor.ts:

实现render函数, 渲染一个临时边框:

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

  1. 最终效果:

2.7 设计Editor的整体架构

如下图所示:

一张幻灯片(Slide)中可能有多个编辑器(Editor), 一个编辑器中可能有多个段落(Paragraph), 一个段落中可能有多行(SoftLine), 一行中可能有多个字符(Char).

2.8 自顶向下实现

接下来, 我们按照自顶向下的方式, 来一步步实现这个架构:

2.8.1 Paragraph

  1. 修改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都会重新计算. 类似下图一样:

  1. 新建文件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

  1. 新建src/core/CanvasTextEditorChar.ts文件:

  1. 目前暂时先支持定制colorfontSize两个样式:

  1. 另外, 要对外暴露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)没变, 所以相当于文字上移了.

为了解决这个问题, 我暂时想到了一种方法:

  1. 我们需要将每一行文字统一向下偏移一个长度offsetY
  2. 每一行的offsetY, 取决于行内所有字符fontBoundingBoxAscent的最大值
  3. 在渲染行内的每个字符时, 统一加上这个偏移值

接下来我们来实现, 修改src/core/CanvasTextEditorSoftLine.ts:

效果:

文字上移的问题解决了, 棒!

(未完待续)

从零开始, 开发一个 Web Office 套件 (2): 富文本编辑器的更多相关文章

  1. 从零开始, 开发一个 Web Office 套件 (1): 富文本编辑器

    这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 富文本编辑器 万里长征 ...

  2. 从零开始, 开发一个 Web Office 套件 (3): 鼠标事件

    这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 对应的Github r ...

  3. 《从零开始, 开发一个 Web Office 套件》系列博客目录

    这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 对应的Github r ...

  4. 从零开始, 开发一个 Web Office 套件(4):新的问题—— z-index

    <从零开始, 开发一个 Web Office 套件>系列博客目录 这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office ...

  5. 从零开始,开发一个 Web Office 套件(5):Mouse hover over text

    <从零开始, 开发一个 Web Office 套件>系列博客目录 这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office ...

  6. 从零开始,开发一个 Web Office 套件(6):光标 & Click 事件

    <从零开始, 开发一个 Web Office 套件>系列博客目录 这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office ...

  7. 从零开始,开发一个 Web Office 套件(7):新的问题—— Click 事件的 z-index

    这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office 套件(包括:文档.表格.幻灯片--等等). 博客园:<从零开始, 开发一 ...

  8. 从零开始,开发一个 Web Office 套件(9):拖动鼠标选中文字 Edge Case

    这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office 套件(包括:文档.表格.幻灯片--等等). 博客园:<从零开始, 开发一 ...

  9. 从零开始,开发一个 Web Office 套件(10):捕获键盘事件,输入文字

    这是一个系列博客,最终目的是要做一个基于 HTML Canvas 的.类似于微软 Office 的 Web Office 套件(包括:文档.表格.幻灯片--等等). 博客园:<从零开始, 开发一 ...

随机推荐

  1. 海康威视Java SDK拉流(一)初始化SDK

    19年的时候做了一个视频分析的产品,用户使用的安防摄像机基本的都是海康大华宇视,今天写一下关于Java调用海康威视摄像机的demo,当时也踩了很多坑.写个博客记录一下 测试环境: 系统:Centos ...

  2. MyEclipse编写jsp很卡的修改方法 (转载)

      原文来源   Post IP : 180.156.210.*       1,改默认编辑模式就可以了.将默认编辑器由"myeclipse visual jsp designer" ...

  3. uniapp医院预约挂号微信小程序

    开头感言:最近看小程序很火,也想弄一个看看,用了一些时间从0开始写,也记录了一些笔记,自己用框架写的模板,不是很精美,后面会慢慢优化,功能也是后面慢慢加上去的, 其中功能这块,起初只是一些简单的功能, ...

  4. Codeforces 855B:Marvolo Gaunt's Ring(枚举,前后缀)

    B. Marvolo Gaunt's Ring Professor Dumbledore is helping Harry destroy the Horcruxes. He went to Gaun ...

  5. 替代联阳IT6564方案|CS5262替代IT6564|设计DP转HDMI+VGA扩展坞方案

    联阳IT6564:带嵌入式MCU的单芯片4通道DisplayPort1.2到HDMI2.0/VGA转换器 联阳IT6564是一种高性能的单芯片显示端口到HDMI和VGA转换器.IT6564FN结合Di ...

  6. Vue.js高效前端开发 • 【Vue组件】

    全部章节 >>>> 文章目录 一.Vue组件介绍 1.组件概述 2.组件使用步骤 3.实践练习 一.Vue组件使用 1.组件注册 2.组件注册语法糖 3.使用script或te ...

  7. Android程序设计基础 • 【目录】

    章节 内容 实践练习 Android程序设计基础作业目录 (作业笔记) 第1章 Android程序设计基础 • [第1章 Android程序入门] 第2章 Android程序设计基础 • [第2章 基 ...

  8. 编写Java程序,定义一个类似于ArrayList集合类

    返回本章节 返回作业目录 需求说明: 设计一个类似于ArrayList的集合类ListArray. ListArray类模拟实现动态数组,在该类定义一个方法用于实现元素的添加功能,以及用于获取List ...

  9. 编写Java程序,使用日期处理类实现日期的格式化输出

    返回本章节 返回作业目录 需求说明: 按"yyyy-MM-dd"格式输入一个字符串型日期,然后输出这个日期为本年中的第几周. 实现思路: 使用SimpleDateFormat格式化 ...

  10. PingFang(苹方)字体的引用

    原文 链接:https://pan.baidu.com/s/1rw39Yqo9fv9BYz_JZ5lyRw 提取码:o7kf 苹方-简 常规体 font-family: pingFangSC-Regu ...