Canvas 比較特殊,Transform 和 Scroll 策略都不是最佳選擇。最適合的是 Canvas 原生重繪。
transform: scale3d(2, 2, 1);
// 不改 CSS,改 canvas 內部的繪圖座標系
ctx.save();
ctx.scale(scale, scale);
ctx.translate(offsetX, offsetY);
// 重新繪製所有內容
drawEverything(ctx);
ctx.restore();
| Transform | Canvas 重繪 | |
|---|---|---|
| 放大後畫質 | 模糊(拉伸像素) | 清晰(重新繪製) |
| 平移 | translate3d | ctx.translate |
| 效能 | GPU 處理,但浪費(模糊的圖放大) | 需重繪,但可優化(只畫可見區域) |
| 互動偵測 | 需反算座標 | 需反算座標(兩者都要) |
// 螢幕座標 → Canvas 世界座標(用於點擊偵測)
function screenToWorld(screenX: number, screenY: number) {
return {
x: (screenX - offsetX) / scale,
y: (screenY - offsetY) / scale,
};
}
// pinch 中心點不動,周圍內容縮放
function zoomAt(newScale: number, centerX: number, centerY: number) {
offsetX = centerX - (centerX - offsetX) * (newScale / scale);
offsetY = centerY - (centerY - offsetY) * (newScale / scale);
scale = newScale;
redraw();
}
這是地圖類應用的標準做法:pinch 的中心點保持不動。
| 主題 | 資源 |
|---|---|
| Canvas 座標變換 | MDN: Transformations |
| Canvas 效能 | MDN: Optimizing canvas |
| 實作範例 | Canvas zoom and pan (GitHub) |
| 進階:Figma 架構 | Figma’s Engineering Blog |
ctx.scale() + ctx.translate() 重繪