系列:一張投影片背後的工程:從零打造網頁簡報編輯器
對應程式版本:Git tag
v0.4.0版本說明:本文記錄矩形、橢圓、線段與箭頭共用資料模型與渲染元件的第一版。
加入圖形時,最容易形成兩套實作:編輯畫布畫一套,縮圖、播放與 PDF 再各畫一套。功能剛完成時看不出差異,之後調整顏色、線寬或箭頭造型,畫面就可能開始不一致。
文件只記錄圖形種類、位置、尺寸與樣式,不保存 JSX 或 DOM:
export type ShapeKind = 'rectangle' | 'ellipse' | 'line' | 'arrow'
export interface ShapeElement extends ElementFrame {
type: 'shape'
shape: ShapeKind
style: { fill: string; stroke: string; strokeWidth: number }
}
矩形與橢圓(選單中的「圓形」)預設為 360 × 220;線段(選單中的「直線」)與箭頭則使用較寬、較低的 420 × 80 frame。它們仍是一般投影片物件,因此選取、拖曳、調整大小、群組與圖層排序都能沿用既有流程。
ShapeGraphic 只負責依資料畫出圖形。矩形與橢圓都用背景色和邊框繪製,橢圓只多了 border-radius: 50%;線段與箭頭則在 frame 的垂直中央畫一條水平線,粗細等於線寬,箭頭再加上由 CSS 邊框形成的三角形尖端。
互動畫布由 ShapeElementView 包住 ShapeGraphic,加入選取框與拖曳控制;靜態的 SlideRenderer 也直接使用同一個元件:
if (element.type === 'shape') {
return (
<div key={element.id} className="static-slide-element" style={frameStyle}>
<ShapeGraphic element={element} />
</div>
)
}
縮圖、播放與列印都走 SlideRenderer,所以圖形外觀只需要維護一處。編輯介面的控制點仍留在外層,不會出現在播放或 PDF。
兩條路徑有一處不同:不透明度套用的位置。CSS 的 opacity 會連同子元素一起變淡,所以編輯畫布把它套在內層的 .element-visual,外層的選取框與控制點維持清楚;靜態渲染器沒有控制點,直接寫在物件外框的樣式上。圖形本身在兩邊呈現的透明度相同。
介面測試先從「新增圖形」加入矩形,和文字一起群組後按 Ctrl+D 建立副本,再複製貼上;另一個測試加入箭頭,框選文字與箭頭後剪下,貼到新的投影片。這些測試不只確認圖形能出現,也確認它能走過既有的多選與文件更新流程。
第一版的線段與箭頭只能水平,也不會連接到其他物件。箭頭尖端固定是寬 22、高 28 的 CSS 三角形,不會跟著線寬縮放:線寬超過 28 時線會比尖端還粗,設為 0 時線條消失、尖端仍在。線段與箭頭也只使用「外框」顏色與「外框寬度」,面板上的「填滿」對它們沒有作用。這幾點到 v0.15.0 仍未調整。
回頭看,共用資料與渲染路徑的效果在 v0.6.0 加入旋轉時最明顯:縮圖、播放與 PDF 只在 SlideRenderer 的 frame 樣式多了一行 transform,ShapeGraphic、PresentationMode 與 PrintDocument 都沒有修改;編輯畫布的三種物件元件也各只多一行。水平線旋轉之後,就能畫出斜線或垂直線。