《從零開始, 開發(fā)一個 Web Office 套件》系列博客目錄

這是一個系列博客, 最終" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運營 > 從零開始, 開發(fā)一個 Web Office 套件 (1): 富文本編輯器

從零開始, 開發(fā)一個 Web Office 套件 (1): 富文本編輯器

時間:2023-07-23 22:12:02 | 來源:網(wǎng)站運營

時間:2023-07-23 22:12:02 來源:網(wǎng)站運營

從零開始, 開發(fā)一個 Web Office 套件 (1): 富文本編輯器:原文首發(fā)自我的博客: 從零開始, 開發(fā)一個 Web Office 套件 (1): 富文本編輯器
《從零開始, 開發(fā)一個 Web Office 套件》系列博客目錄

這是一個系列博客, 最終目的是要做一個基于HTML Canvas 的, 類似于微軟 Office 的 Web Office 套件, 包括: 文檔, 表格, 幻燈片... 等等.

富文本編輯器

萬里長征的第一步: 我們先開發(fā)一個基于canvas的富文本編輯器. 之后, 這個編輯器可以用在我們所有類型的文檔中(文檔, 表格, 幻燈片...).
對應(yīng)的Github repo 地址: https://github.com/zhaokang555/canvas-text-editor

富文本編輯器 在線 Demo:https://zhaokang555.github.io/canvas-text-editor/

1. Environment setup

工欲善其事, 必先利其器. 首先我們來配置項目環(huán)境

1.1 初步構(gòu)想

我們的富文本編輯器項目包含兩大部分:







1.2 Vite

我們使用Vite (https://cn.vitejs.dev/)作為我們的打包工具.
為什么使用Vite, 而不是Webpack呢? 可以看這里: https://cn.vitejs.dev/guide/why.html

1.3 使用Vite初始化項目

1.4 調(diào)整項目目錄結(jié)構(gòu)

我們新建2個文件夾:




1.5 Hello, world!

  1. src/core目錄下, 新建一個文件: CanvasTextEditor.ts. 寫上最簡單的代碼, 在canvas上渲染出一行Hello, world!:



2. 修改src/demo/App.tsx, 初始化CanvasTextEditor:




3. 添加SASS依賴, 并重置瀏覽器重置樣式



添加文件 src/demo/main.scss



修改文件 src/demo/main.tsx, 引入main.scss





效果:







2. 富文本編輯器(MVP)

2.1 計算文字包圍盒

首先, 我們要找到一種方法, 來確定任意一段文字的包圍盒. 為什么要確定包圍盒呢? 因為:

CanvasRenderingContext2D 提供了 measureText API, 可以幫我們度量文字尺寸:

接下來, 我們來看一下這個API都返回了哪些有用的信息.

修改src/core/CanvasTextEditor.ts, 將measureText接口返回結(jié)果打印出來:











問題來了, fontBoundingBox和actualBoundingBox的區(qū)別是什么呢? MDN是這樣描述的:




看完文檔, 還是不確定哪一個使我們想要的. 所以, 我們來給canvas上添加一些輔助線, 來幫助我們更形象地對比下兩者的區(qū)別. 我們用紅色畫出actualBoundingBox, 用綠色畫出fontBoundingBox:







注意, 為了方便計算, 我們將textBaseLine設(shè)置為top. 如果有小伙伴不熟悉textBaseLine, 可以看MDN提供的這張圖:







回到正題, 渲染結(jié)果如下:







問題來了, fontBoundingBoxDescent 多出來的那一部分究竟是什么呢? 讓我們修改文字內(nèi)容再試一次:







這次兩個矩形基本重合了. 所以, actualBoundingBoxDescent中的actual的意思就很明顯了: 實際渲染出的字符距離baseLine的最大距離. 而fontBoundingBoxDescent是不關(guān)心實際渲染字符的, 它只關(guān)心所有可用的字符.

所以, 為了一致性, 我們使用后者.

2.2 緩存(記錄)文字包圍盒

既然找到了計算文字包圍盒的方法, 接下來, 我們需要在每次繪制文字的時候, 將其緩存起來, 方便我們后續(xù)使用. 新建文件src/core/CanvasTextEditorText.ts:







修改src/core/CanvasTextEditor.ts, 使用一個數(shù)組將我們想要渲染的文字都儲存起來:







2.3 根據(jù)鼠標(biāo)位置, 修改鼠標(biāo)樣式

接下來, 我們要實現(xiàn)的是這個功能:

當(dāng)我們的鼠標(biāo)hover到文字上的時候, 需要修改鼠標(biāo)的樣式, 類似CSS中的cursor: text;







我暫時想到了一種簡單的方案: 就是當(dāng)鼠標(biāo)移動到某些區(qū)域的時候, 修改canvas的style, 加上cursor: text. 當(dāng)鼠標(biāo)移出這些區(qū)域的時候, 去掉cursor: text;

問題來了, 如何獲取到鼠標(biāo)在canvas中的坐標(biāo)呢? 我們可以先用一種簡單的方案: 監(jiān)聽mousemove, 并且和canvas的位置作差.
修改src/core/CanvasTextEditor.ts:



重構(gòu)src/core/CanvasTextEditorText.ts:





最終效果:







2.4 文本自動折行

截止到目前, 一切似乎都很正常. 但是, 當(dāng)我們的文本很長的時候, 它并不會折行. 這就導(dǎo)致過長的文字會顯示不全. 因此, 我們需要實現(xiàn)一個功能: 當(dāng)文字觸碰到canvas邊緣的時候, 可以自動折行.

實現(xiàn)這個功能之前, 我們先對現(xiàn)有代碼進行一下重構(gòu), 讓我們可以清晰地看到canvas的邊緣:

修改src/demo/main.scss, 給body一個背景色:







修改src/core/CanvasTextEditor.ts, 給canvas一個白色背景色:







重構(gòu)src/core/CanvasTextEditorText.ts, 給文字設(shè)置一個黑色默認(rèn)顏色:







這樣, 我們可以清晰地看到, 文字后半段沒有顯示:







接下來, 我們來解決文字顯示不全的問題. 我暫時想到了一種算法:

當(dāng)渲染一段文字之前, 我們先測量一下這段文字的長度a, 再計算一下文字起點距離canvas邊緣的距離b

1. 如果a <= b, 那么直接渲染即可.2. 如果a > b, 那么就需要將文字分成多行. 先找到一個符合要求的最長第一行. 以此類推, 直到第n行. 3. 如果后期遇到了性能問題, 我們就使用二分法, 來確定每一行的字符數(shù), 優(yōu)化算法性能.然后, 我們來實現(xiàn)這個算法:







然后, 我們在CanvasTextEditorText的構(gòu)造函數(shù)中調(diào)用這個算法, 用來:
1. 獲取到分割后的lines
2. 計算出多行文字的真實高度
3. 在render中渲染出每一行







然后看一下最終效果:







文字折了兩次, 變成了三行, 很棒!

(未完待續(xù))

關(guān)鍵詞:編輯,文本

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點擊下載Chrome瀏覽器
關(guān)閉