iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Software Development

從零打造網頁簡報編輯器系列 第 5

Day 05|選擇畫布的呈現方式

  • 分享至 

  • xImage
  •  

系列:一張投影片背後的工程:從零打造網頁簡報編輯器

對應程式版本:Git tag day-05

版本說明:本文記錄當日選型;目前版本仍沿用固定邏輯畫布與 DOM/CSS 渲染。

上一篇把文件裡的文字與圖片變成可見的投影片。接下來要決定更底層的問題:中央畫布應該使用一般 DOM 元素,還是把內容畫進 canvas

兩種方式都能做出簡報編輯器,選擇取決於第一版最重要的操作。這個專案需要直接編輯中文、拖曳少量圖文物件、產生縮圖,最後還要讓瀏覽器列印成 PDF。因此我先比較實際需求,而不是只看繪圖效能。

DOM/CSS 與 Canvas 的取捨

需求 DOM/CSS Canvas
文字輸入與選取 可直接使用 textarea 等原生元件 需要另外管理輸入框、游標和選字
中文輸入法 可接收 composition 事件 需要自行銜接隱藏或浮動輸入元件
物件位置與樣式 用 CSS 直接表達 每次變更都要重新繪製
點擊與拖曳 元素可直接接收指標事件 需要用座標自行判斷命中物件
語意與輔助技術 可使用 HTML 語意與 ARIA 需另做可存取的替代內容
大量圖形 DOM 數量多時可能增加版面與繪製成本 適合集中繪製大量像素或圖形

Canvas API 提供 JavaScript 繪圖表面,很適合遊戲、資料視覺化或大量圖形。不過它不會自動把畫面上的每個物件變成可互動的 HTML 元素。對目前以文字編輯為主、每頁物件數量有限的版本,DOM/CSS 可以少做一套輸入、命中測試與列印邏輯。

因此第一版選擇 DOM/CSS。這不是永遠不能改的架構承諾;如果未來加入數千個圖形、自由筆跡或複雜特效,可以再評估 Canvas,甚至只把特定圖層交給 Canvas。

文件尺寸固定,顯示比例另外計算

簡報文件使用固定的 1600 × 900 邏輯尺寸。視窗變小時,不縮小文件裡的座標,而是計算一個只供顯示的比例:

const scale = Math.min(
  1,
  availableWidth / canvasWidth,
  availableHeight / canvasHeight,
)

useCanvasScale 透過 ResizeObserver 取得可用空間,寬度與高度各自算出比例,再採用較小值,避免任何一邊超出容器。Math.min(1, ...) 讓「符合視窗」模式最多顯示為 100%;使用者仍可以用明確的縮放選項查看其他比例。

實際顯示時,內層仍維持 1600 × 900,只在渲染層套用 transform:

<div
  className="canvas-frame"
  style={{
    width: presentation.canvas.width * scale,
    height: presentation.canvas.height * scale,
  }}
>
  <SlideRenderer
    className="slide-canvas"
    style={{ transform: `scale(${scale})` }}
  />
</div>

CSS transform 改變的是元素的視覺呈現,不會替它在一般版面配置中重新保留縮放後的空間。因此外層 canvas-frame 明確使用縮放後的寬高,內層畫布則以左上角為縮放原點:

.slide-canvas {
  position: absolute;
  inset: 0;
  transform-origin: top left;
}

這樣畫布在 50% 時,外層實際占用 800 × 450;文件和物件仍保存原本的 1600 × 900 座標。

指標位移要轉回畫布座標

縮放只套在顯示上,也代表滑鼠移動距離不能直接寫回文件。換算公式是:

canvasDelta = screenDelta / scale

例如游標在螢幕上向右移動 100 像素:

  • 50% 顯示時,物件應在邏輯畫布移動 200 單位。
  • 125% 顯示時,物件應在邏輯畫布移動 80 單位。

screenDeltaToCanvas 集中處理這個公式,並拒絕零、負數或非有限的比例。拖曳時,每次換算出的新位置都會先經過 clampElementPosition 限制在畫布內,放開時提交的就是限制後的位置。座標測試同時覆蓋 0.5 與 1.25,避免只在 100% 時看似正確。

Edge 手動驗收也在不同縮放比例下實際拖曳物件,游標與物件位移一致,結果通過。day-05 當時的 6 個測試檔、24 個案例,以及 lint 與正式建置都已通過。

到這裡,第一版的畫布做法已經確定:文件只保存 1600 × 900 邏輯座標,縮放只影響畫面顯示與指標位移換算。下一篇會處理多張投影片的新增、切換、複製、排序與刪除。

參考資料


上一篇
Day 04|建立第一張可以呈現內容的投影片
下一篇
Day 06|新增切換與排序多張投影片
系列文
從零打造網頁簡報編輯器13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言