從零開始, 開發一個 Web Office 套件(4):新的問題—— z-index

趙康發表於2022-02-21

《從零開始, 開發一個 Web Office 套件》系列部落格目錄
這是一個系列部落格, 最終目的是要做一個基於HTML Canvas 的, 類似於微軟 Office 的 Web Office 套件, 包括: 文件, 表格, 幻燈片... 等等.
對應的Github repo 地址: https://github.com/zhaokang555/canvas-text-editor

2. 富文字編輯器(MVP)

2.13 z-index

2.13.1 新的問題

上一篇部落格中, 我們實現了mouse hover on SizeControlPoint的feature. 現在, 問題來了: SizeControlPoint和editor border會有重疊的部分, 當滑鼠hover到這個位置時, 應該怎麼處理?

我暫時想到了一種解決方案: 引入z-index的概念, 為SizeControlPoint和editor border分配不同的z-index. 當滑鼠hover到元素重疊的部分時, 尋找最大的z-index對應的元素.

2.13.2 實現

修改src/core/ResponsiveToMouseHover.ts:

  • 新增屬性zIndex
  • constructor新增形參options, 用來設定zIndex
  • 新增兩個靜態屬性topLayerZIndextopLayerCursorType, 用來記錄最上層圖層對應的zIndex值和滑鼠樣式
  • 修改render函式, 記錄topLayerZIndextopLayerCursorType

同時, 修改src/core/SizeControlPoint.ts, 讓它支援設定zIndex:
image

最後, 修改src/coreCanvasTextEditor.ts:

  • 修改render函式, 在所有的sizeControlPoints render結束之後, 再設定canvas.style.cursor
  • 修改clearCanvas函式, 重置ResponsiveToMouseHover.topLayerZIndexResponsiveToMouseHover.topLayerCursorType

2.14 Mouse hover on editor border

處理完z-index的問題, 我們就可以實現這個feature了: 當滑鼠hover到編輯器邊緣的虛線邊框上時, 滑鼠形狀隨之變化

2.14.1 重構: Extract component: CanvasTextEditorBorder

新建檔案src/core/CanvasTextEditorBorder.ts:

其中, Victor是一個開源數學庫: http://victorjs.org/, 可以做一些二維向量計算, 可以通過npm安裝:

npm install victor --save
npm install @types/victor --save-dev

然後重構檔案src/core/CanvasTextEditor.ts:

  • 修改constructor, 抽出initParagraphsinitSizeControlPoints函式
  • 新增initBorder函式, 並在constructor中呼叫
  • 刪除renderBorder函式
  • 修改render函式

image

2.14.2 實現

實現這個feature之前, 我們需要思考如何擴充border的響應範圍(responsive zone). 為什麼要這樣呢? 因為border是一條很細的線, 要讓滑鼠精確地hover上去非常困難, 所以要擴大它的responsive zone. 如下圖所示, 我們把border橫向擴充, 灰色的範圍就是擴充後的responsive zone.

然後, 我們動手來實現. 修改src/core/CanvasTextEditorBorder.ts:

  • 繼承ResponsiveToMouseHover
  • 新增常量borderResponsiveWidth, 用來表示擴充後的responsive box的寬度
  • 新增常量defaultCanvasTextEditorBorderZIndex, 用來表示border預設的zIndex
  • constructor中:
    • 計算border的法向量normalVector
    • 然後計算responsive zone的四角座標, 存入points
    • 然後利用四角座標, 計算responsive zoneleft, top, width, height, 傳入super()

上圖中,我們使用了Victorhttp://victorjs.org)這個二位向量運算庫的若干API:

  • .clone(): 克隆一個二維向量,並返回
  • .substract(vector): 用自己減去另一個二維向量,並將結果賦值給自己
  • .add(vector): 用自己加上另一個二維向量,並將結果賦值給自己
  • .rotate(angle): 將自己沿原點旋轉若干弧度,並將結果賦值給自己
  • .normalize(): 將自己標準化,並將結果賦值給自己
  • .multiplyScalar(scalar): 將自己乘以一個數量,並將結果賦值給自己

同時, 在src/core/CursorType.ts中, 新增十字滑鼠樣式(see: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor) :

2.14.3 效果

responsive zone加上灰色背景, 看一下它的範圍是否合適:

(未完待續)

相關文章