新視野行銷企劃

Canvas 基礎繪圖教學:從矩形到路徑

Canvas 基礎繪圖教學封面圖,採用扁平化設計風格,展示矩形與路徑曲線的範例,象徵 HTML5 Canvas 繪圖教學主題,適用於技術與前端教學網站的代表圖像。

前言

HTML5 Canvas 是網頁中可使用 JavaScript 進行即時繪圖的元素,它提供一個像畫布一樣的區域,讓我們能以程式碼繪製各種圖形、文字及影像。對於具有基礎 JavaScript 能力的開發者,Canvas 開啟了一扇創作視覺效果的大門。在這篇教學文章中,我們將從 繪製矩形 開始,一步步探討 Canvas 2D API 的基礎繪圖方法,逐漸深入到 繪製路徑 及其進階應用,包括畫直線、圓形與弧形、二次與三次貝茲曲線(Bezier 曲線)、自由手繪曲線,以及繪製文字及文字描邊等主題。整篇文章將以清晰易懂的方式循序漸進說明,每個章節都包含可直接執行的 Canvas + JavaScript 範例程式碼,方便讀者實際操作體驗。閱讀本教學後,您將能掌握如何在 Canvas 上畫出各種基本圖形和路徑,為日後製作更複雜的圖像效果打下良好基礎。

(註:以下範例程式碼可直接在 HTML 檔案中執行,每段範例包含一個 <canvas> 畫布元素以及對應的 JavaScript 繪圖代碼。)

繪製矩形

Canvas 和 SVG 不同,只內建支援一種基本圖形:矩形。為了方便繪製矩形,Canvas 2D API 提供了三個方法,分別用於填充矩形、繪製矩形邊框,以及清除矩形區域:

  • fillRect(x, y, width, height):繪製一個填滿顏色的矩形。
  • strokeRect(x, y, width, height):繪製一個矩形的邊框(只描邊,不填滿)。
  • clearRect(x, y, width, height):清除指定矩形區域的內容,將該區域變為透明。

上述方法的參數意義相同:x、y 是矩形左上角的座標位置,width 和 height 是矩形的寬度與高度。Canvas 的坐標原點在畫布的左上角,座標單位為像素。例如,x = 0, y = 0 代表畫布的左上角位置。

讓我們透過範例來看看如何使用這些矩形繪製方法。下方程式碼會在畫布上繪製一個藍色實心矩形、在其中清出一塊透明區域,並於透明區域內繪製一個紅色邊框矩形。

<canvas id="exampleRect" width="300" height="150"></canvas>
<script>
  const canvas = document.getElementById("exampleRect");
  const ctx = canvas.getContext("2d");

  // 設定填充與描邊樣式
  ctx.fillStyle = "blue";    // 填充色:藍色
  ctx.strokeStyle = "red";   // 邊框色:紅色

  // 繪製藍色填滿矩形
  ctx.fillRect(20, 20, 100, 100);

  // 清除一塊矩形區域(將其變透明)
  ctx.clearRect(40, 40, 60, 60);

  // 繪製紅色邊框矩形
  ctx.strokeRect(50, 50, 40, 40);
</script>

上述程式執行後,我們可以看到一個藍色實心的正方形,其中間被清除了 60x60 像素的區域變為透明,而在該透明區域的內部框出了紅色邊框。需要注意的是,這幾種矩形繪製方法呼叫後會立即在畫布上繪製出結果,不需要再呼叫其他函數來渲染。稍後介紹的路徑繪圖則不同,繪製路徑需要更多步驟才能將圖形渲染出來。

在繪製矩形的同時,我們也可以透過 ctx.fillStyle 和 ctx.strokeStyle 來設定填充和描邊的顏色(預設為黑色),用 ctx.lineWidth 設定描邊線條的粗細等樣式。良好地運用這些屬性可以讓圖形繪製更具彈性和美感。

結束矩形的介紹後,我們將繼續探索如何使用 路徑(Path) 來繪製任意形狀與線條。這使我們不再侷限於矩形,而能畫出各種不規則圖形和曲線。

繪製路徑與直線

在 Canvas 中繪製自訂的圖形需要運用「路徑」(path)的概念。簡單來說,路徑是一系列相連的點(由直線或曲線段連接)所構成的形狀輪廓。我們可以想像拿著畫筆在紙上畫線:先決定起筆的位置,然後依序畫出各段線條或曲線,最後(選擇性地)收筆閉合圖形。在 Canvas 裡,繪製路徑大致包含以下步驟:

  • 開始一條新路徑:使用 beginPath() 開始一個新的繪圖路徑。呼叫此方法後,先前的路徑狀態會被重置,我們即將開始繪製新的圖形。
  • 繪製路徑:使用各種繪圖命令將筆觸移動到指定座標並畫出線段或曲線,如 moveTo、lineTo、arc、quadraticCurveTo、bezierCurveTo 等等。這些命令會定義路徑的形狀。
  • (可選)封閉路徑:使用 closePath() 封閉路徑。如果當前的位置不在起點,closePath() 會自動繪製一直線段連回起始點,形成一個封閉形狀。若路徑已經封閉或僅有一個點,呼叫這個方法沒有效果。
  • 渲染圖形:路徑定義完成後,使用 stroke() 勾勒(描邊)或 fill() 填滿 來將路徑繪製到畫布上。stroke() 會繪製路徑的輪廓,而 fill() 會填充路徑圍成的區域。如果使用 fill() 來繪製未封閉的路徑,Canvas 會自動將端點相連以封閉該形狀;但使用 stroke() 則不會自動封閉未閉合路徑,因此若需要封閉可以在繪製前手動呼叫 closePath()。

以上步驟看起來抽象,我們以繪製一個簡單的三角形為例來瞭解。下方範例在 Canvas 上畫出兩個三角形:一個填滿的實心三角形,和一個只有邊框的空心三角形。

<canvas id="examplePath" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById("examplePath");
  const ctx = canvas.getContext("2d");

  // **繪製填滿的三角形**
  ctx.beginPath();          // 開始新路徑
  ctx.moveTo(50, 150);      // 移動畫筆至起點 (50,150)
  ctx.lineTo(150, 150);     // 畫線到 (150,150)
  ctx.lineTo(100, 50);      // 畫線到 (100,50) — 形成三角形的第三個點
  ctx.fill();               // 填滿路徑(自動封閉路徑並填充)

  // **繪製空心的三角形**
  ctx.beginPath();          // 開始新路徑(不與之前的路徑相連)
  ctx.moveTo(50, 50);       // 起點 (50,50)
  ctx.lineTo(150, 50);      // 畫線到 (150,50)
  ctx.lineTo(150, 150);     // 畫線到 (150,150)
  ctx.closePath();          // 手動封閉路徑(將最後一點連回起點)
  ctx.stroke();             // 描邊繪製三角形邊框
</script>

在上述程式碼中,第一次繪圖我們使用 fill() 來完成三角形,由於填充操作會自動將形狀閉合,無需特別呼叫 closePath() 就能得到完整的實心三角形。而第二次繪圖我們選擇 stroke() 來描邊,此時就必須在繪製結束前呼叫 ctx.closePath(),否則只會出現兩條相連的線段,而非一個封閉的三角形。

可以看到,moveTo(x, y) 在一開始指定了繪圖的起點位置,相當於把筆移到紙上的某點而不畫下任何痕跡;接著的 lineTo(x, y) 則會從前一個位置畫一條直線到新的座標點。利用這兩個基本操作組合,我們可以繪製各種折線和多邊形。若我們希望開始繪製一條新線而不與前一段相連,就需要再次呼叫 moveTo 或重新 beginPath() 來重設起點。

到此為止,我們已經能透過路徑畫出任意的折線圖形了。接下來,我們將介紹如何繪製圓形與弧形這類平滑曲線,以及進一步的貝茲曲線,讓繪圖更加多元。

繪製弧形與圓形

圓形和弧線是圖形繪製中常見的元素,例如鐘錶的錶盤、進度環、餅圖等。在 Canvas 中,可以使用 arc(x, y, radius, startAngle, endAngle, anticlockwise) 方法在當前路徑中新增一段弧形(arc)。它所繪製的可以是一整圈的圓,也可以是圓的一部分弧段。各個參數的意義如下:

  • x, y:圓心的座標位置。
  • radius:圓的半徑大小。
  • startAngle:弧形開始的位置角度(以弧度表示)。
  • endAngle:弧形結束的位置角度(同樣以弧度表示)。
  • anticlockwise:布林值,表示繪製方向。false 表示按順時針方向繪製弧(預設值),true 則表示按逆時針方向繪製。

需要特別注意,startAngle 和 endAngle 是用 弧度 (radians) 來表示角度而非一般的度數。例如,要畫出 90 度的四分之一圓弧,我們應使用 Math.PI/2 表示 90 度(因為 Math.PI 弧度等於 180 度)。如果需要在度數和弧度之間轉換,可以使用公式:radians = (Math.PI/180) * degrees。另外,起始角度是從圓的正右側方向(沿著 x 軸正方向)開始計算。例如,若 startAngle = 0,代表從圓心正右方開始畫弧。

下面透過範例來展示如何繪製圓形和弧形。我們將畫出一個圓形的輪廓以及一段彩色的圓弧。

<canvas id="exampleArc" width="250" height="150"></canvas>
<script>
  const canvas = document.getElementById("exampleArc");
  const ctx = canvas.getContext("2d");

  // 繪製一個圓形的邊框
  ctx.beginPath();
  ctx.arc(75, 75, 50, 0, Math.PI * 2, false);  // 從0到2π,即一整圈
  ctx.strokeStyle = "green";
  ctx.lineWidth = 5;
  ctx.stroke();  // 描邊出綠色圓形

  // 繪製一段圓弧(例如四分之一圓)
  ctx.beginPath();
  ctx.arc(175, 75, 50, 0, Math.PI / 2, false);  // 從0到 π/2,四分之一圓
  ctx.strokeStyle = "orange";
  ctx.lineWidth = 5;
  ctx.stroke();  // 描邊出橘色弧線
</script>

第一部分程式碼使用 arc(75, 75, 50, 0, 2 * Math.PI, false) 畫出一整圈的圓並用 stroke() 描邊成綠色,形成一個直徑 100 像素的空心圓形。第二部分程式則畫出一段從 0 弧度到 π/2 弧度的橘色弧線(也就是從正右方到正下方的四分之一圓弧)。在這兩個例子中,我們皆先呼叫 beginPath() 開始一條新路徑,確保每次繪製的形狀不會彼此連接影響。當需要畫一個完整的圓時,startAngle 可以是 0,endAngle 設為 2π(約等於 6.283),而弧線方向順時針或逆時針對完整圓形沒有影響(對於非完整圓則影響繪製的方向和形狀位置)。

透過 arc() 函數,我們可以輕鬆繪製圓形或圓弧等曲線圖形。而在某些情況下,我們需要繪製的不僅是單純的圓,而是更靈活的貝茲曲線,例如繪製不規則的曲線邊緣或平滑的波浪形狀。下一節將介紹 Canvas 中的二次與三次貝茲曲線繪製。

二次貝茲曲線

二次貝茲曲線(Quadratic Bézier curve)是一種類型的平滑曲線,由一個 控制點 和一個終點來定義曲線的形狀。Canvas 提供了 quadraticCurveTo(cp1x, cp1y, x, y) 方法來繪製二次貝茲曲線。其中參數 (cp1x, cp1y) 是控制點座標,決定曲線的彎曲方向和強度,而 (x, y) 是曲線的終點座標;曲線的起點則是當前路徑下上一個繪畫點(或使用 moveTo 設定的點)。

可以把二次貝茲曲線想像成從起點出發,朝向控制點的方向彎曲,最後在終點處結束。控制點有點像一顆"磁石",吸引著曲線朝它靠近,因此曲線的形狀會向控制點凸出。

我們來看一個範例,繪製一條簡單的二次貝茲曲線。此範例中,我們會標示出起點、終點和控制點的位置,以方便觀察曲線如何被控制點拉出彎曲。

<canvas id="exampleQuadCurve" width="300" height="200"></canvas>
<script>
  const canvas = document.getElementById("exampleQuadCurve");
  const ctx = canvas.getContext("2d");

  // 定義二次貝茲曲線的三個關鍵點
  const startX = 50, startY = 150;           // 起點
  const cp1X   = 150, cp1Y   = 50;           // 控制點
  const endX   = 250, endY   = 150;          // 終點

  // 繪製二次貝茲曲線
  ctx.beginPath();
  ctx.moveTo(startX, startY);                // 移動到起點
  ctx.quadraticCurveTo(cp1X, cp1Y, endX, endY);  // 繪製二次貝茲曲線到終點
  ctx.strokeStyle = "blue";
  ctx.lineWidth = 3;
  ctx.stroke();                             // 描邊繪製曲線

  // 繪製控制點和輔助線(幫助理解曲線形狀)
  ctx.fillStyle = "red";
  ctx.beginPath();                          // 繪製控制點(紅色圓點)
  ctx.arc(cp1X, cp1Y, 5, 0, Math.PI * 2);
  ctx.fill();
  ctx.fillStyle = "black";
  ctx.beginPath();                          // 繪製起點和終點(黑色圓點)
  ctx.arc(startX, startY, 5, 0, Math.PI * 2);
  ctx.arc(endX, endY, 5, 0, Math.PI * 2);
  ctx.fill();
  ctx.beginPath();                          // 畫出虛線輔助線連接控制點與兩端
  ctx.setLineDash([5, 5]);
  ctx.moveTo(startX, startY);
  ctx.lineTo(cp1X, cp1Y);
  ctx.lineTo(endX, endY);
  ctx.strokeStyle = "gray";
  ctx.stroke();
</script>

以上程式會畫出一條由左下方 (50,150) 出發,彎向上方 (150,50) 控制點,最後抵達右下方 (250,150) 的藍色平滑曲線。我們特地在圖中以紅點標示控制點位置,以黑點標示起點和終點,並用灰色虛線連接起點、控制點和終點,形成一種「三角形」的形狀輔助視覺化曲線參考。透過這些輔助標示,我們可以清楚看到藍色的貝茲曲線是如何朝紅色控制點凸出,然後落向終點的。

每次呼叫 quadraticCurveTo 時,都是從當前路徑位置繪製至指定的終點。我們也可以連續呼叫多次 quadraticCurveTo 來畫出由多段二次曲線組成的複雜圖形。例如,可以用多段曲線繪製出對話框的圓角邊框、雲朵般的不規則圖案等等。二次貝茲曲線因只有一個控制點,形狀相對容易預測,但在更複雜的情況下,一個控制點可能不足以精細地控制曲線形態,這時就需要用到有兩個控制點的 三次貝茲曲線

三次貝茲曲線

三次貝茲曲線(Cubic Bézier curve)提供了兩個控制點,因而能繪製出更加靈活多變的曲線形狀。Canvas 使用 bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) 來繪製三次貝茲曲線。相比二次曲線,函式多了第二組控制點參數 (cp2x, cp2y),其 (x, y) 終點參數的意義則相同。曲線的起點仍然是目前路徑的最後一個座標點。

兩個控制點決定了曲線在起點和終點處的方向和離散程度:曲線從起點出發時朝向第一個控制點靠近,並在接近終點時受到第二個控制點的拉引。因此,三次貝茲曲線通常能達到比二次曲線更複雜的彎折效果。我們可以將其想像成"從起點朝控制點1方向出發,途中轉向控制點2,最後抵達終點"。

我們使用一個範例來直觀感受三次貝茲曲線的繪製,並對比二次與三次曲線控制點的差異。下方程式將繪製一條三次貝茲曲線,並同樣標示出起點、終點和兩個控制點的位置。

<canvas id="exampleCubicCurve" width="300" height="250"></canvas>
<script>
  const canvas = document.getElementById("exampleCubicCurve");
  const ctx = canvas.getContext("2d");

  // 定義三次貝茲曲線的關鍵點
  const startX = 50,  startY = 200;         // 起點
  const cp1X   = 50,  cp1Y   = 50;          // 控制點1
  const cp2X   = 250, cp2Y   = 50;          // 控制點2
  const endX   = 250, endY   = 200;         // 終點

  // 繪製三次貝茲曲線
  ctx.beginPath();
  ctx.moveTo(startX, startY);
  ctx.bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, endX, endY);
  ctx.strokeStyle = "purple";
  ctx.lineWidth = 3;
  ctx.stroke();

  // 繪製控制點和輔助線以輔助觀察
  ctx.fillStyle = "red";
  ctx.beginPath();
  ctx.arc(cp1X, cp1Y, 5, 0, Math.PI * 2);   // 控制點1(紅色)
  ctx.arc(cp2X, cp2Y, 5, 0, Math.PI * 2);   // 控制點2(紅色)
  ctx.fill();
  ctx.fillStyle = "black";
  ctx.beginPath();
  ctx.arc(startX, startY, 5, 0, Math.PI * 2);  // 起點(黑色)
  ctx.arc(endX, endY, 5, 0, Math.PI * 2);      // 終點(黑色)
  ctx.fill();
  ctx.beginPath();
  ctx.setLineDash([5, 5]);                    // 虛線連線控制點和端點
  ctx.moveTo(startX, startY);
  ctx.lineTo(cp1X, cp1Y);
  ctx.lineTo(cp2X, cp2Y);
  ctx.lineTo(endX, endY);
  ctx.strokeStyle = "gray";
  ctx.stroke();
</script>

這段程式碼在畫布上繪出一條紫色的三次貝茲曲線。可以觀察到,曲線從起點 (50,200) 出發時朝向第一個控制點 (50,50) 上方移動,接著在途中拐彎朝向第二個控制點 (250,50),最後緩緩落向終點 (250,200)。我們以兩個紅點標示了控制點的位置,以黑點標示起點和終點,同時用灰色虛線將四個關鍵點依序相連,以示意整條曲線的幾何結構。通過這些輔助標記可以發現,二次曲線只有一個控制點,曲線形狀呈現單一的弓形;而三次曲線有兩個控制點,曲線可以在中途產生變向,更加靈活多變。

如果您嘗試改變控制點或終點的位置,將會發現曲線形狀會跟著明顯變化。熟練掌握貝茲曲線的控制對於繪製複雜的有機圖形非常關鍵,例如想畫出心形、雲朵、橢圓等,常需要精心調整多段貝茲曲線的控制點來完成。此外,由於在 Canvas 中無法直接"看到"尚未繪製完成的曲線(不像圖形軟體能即時拖曳點線調整),在編寫代碼時需要一些耐心和試驗來選擇控制點座標,以得到理想的曲線形狀。

至此,我們已經介紹了Canvas路徑繪圖中常用的各種曲線繪製方法——從直線、圓弧到二次和三次貝茲曲線。接下來,我們將探討如何讓使用者以更直覺的方式,在 Canvas 上自由繪製曲線。

自由繪製曲線

有時我們希望允許使用者透過滑鼠或觸控,直接在 Canvas 上繪圖,好比一支畫筆讓人自由揮灑。要實現這種自由繪製曲線的效果,關鍵思路是在使用者拖曳滑鼠時,不斷取得滑鼠在畫布上的座標,並繪製連接上一點和當前點的線段,從而形成平滑的手繪軌跡。

在 Canvas 上監聽使用者的滑鼠事件可以做到這點。典型的作法是:

  • 監聽 mousedown 事件,當滑鼠按下時,使用 beginPath() 開始一條新路徑,並記錄起始座標(使用 moveTo 移動畫筆到起點)。
  • 監聽 mousemove 事件,如果滑鼠處於按下狀態,則持續呼叫 lineTo() 將路徑連接到滑鼠的新座標,並即時使用 stroke() 繪製出線段。
  • 監聽 mouseupmouseleave 事件,在滑鼠放開或移出畫布時結束繪圖(可視需要呼叫 closePath(),通常手繪不閉合也沒關係),將狀態重置以準備下一次繪圖。

下面的範例實作了一個簡易的畫筆功能:按下滑鼠在畫布上拖曳時會畫出連續的線條,鬆開滑鼠後停止繪圖。為了簡化實現,我們使用 offsetX, offsetY 直接取得滑鼠相對於 Canvas 元素的座標。

<canvas id="exampleFreeDraw" width="400" height="200" style="border:1px solid #ccc"></canvas>
<script>
  const canvas = document.getElementById("exampleFreeDraw");
  const ctx = canvas.getContext("2d");
  let drawing = false;  // 用於記錄目前是否正在繪圖狀態

  // 畫筆樣式設定
  ctx.strokeStyle = "darkred";
  ctx.lineWidth = 4;
  ctx.lineCap = "round";  // 線條端點圓潤,讓書寫筆跡更自然

  // 滑鼠按下:開始新的繪圖路徑
  canvas.addEventListener("mousedown", (e) => {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX, e.offsetY);  // 將畫筆移動到起始點
  });

  // 滑鼠移動:若處於繪圖狀態,則繪製連續的曲線
  canvas.addEventListener("mousemove", (e) => {
    if (!drawing) return;
    ctx.lineTo(e.offsetX, e.offsetY);  // 畫線到滑鼠所在位置
    ctx.stroke();                     // 繪製當前線段
  });

  // 滑鼠放開或移出畫布:結束繪圖路徑
  canvas.addEventListener("mouseup", () => {
    drawing = false;
  });
  canvas.addEventListener("mouseleave", () => {
    drawing = false;
  });
</script>

在這段程式中,我們首先將 ctx.lineCap 設為 "round" 以使繪製的線段末端呈圓滑狀,模擬更真實的筆跡效果。當使用者按下滑鼠時,我們透過 beginPath() 開始新路徑並用 moveTo 將畫筆定位到滑鼠點擊的位置;隨後每當滑鼠移動時,我們檢查 drawing 狀態是否為真,如果是則不斷使用 lineTo 畫線到滑鼠的新位置並即時 stroke() 繪製,於是滑鼠移動軌跡就被繪製成線條;最後在 mouseup 或 mouseleave 時將 drawing 設為 false,結束這一次的繪圖。如此在使用者每次按下—拖曳—放開的動作循環中,都會對應繪製出一條獨立的筆畫。

值得注意的是,此實作並未對繪製進行平滑算法或壓力感應處理,但已足夠作為基本的手繪演示。您可以試著改變 strokeStyle 或 lineWidth 來得到不同顏色和粗細的線條效果。透過這樣的機制,可以發展出簡易畫圖板、簽名板或註解工具等功能,增強Canvas應用的互動性。

繪製文字與文字描邊

除了各種圖形與路徑,Canvas 也能夠繪製文字。無論是製作圖表標籤、在圖片上添加說明文字,或是創造像海報一樣的圖文並茂效果,Canvas 的文字 API 都相當實用。Canvas 繪製文字主要用到兩個方法:

  • fillText(text, x, y):在指定座標繪製填滿的文字(實心字)。
  • strokeText(text, x, y):在指定座標繪製描邊的文字(字體外框)。

兩者差別在於呈現效果不同:fillText 繪出的文字以 fillStyle 作為填充顏色,文字本體實心;而 strokeText 則使用 strokeStyle 來繪製字的輪廓,產生空心的文字描邊效果。繪製文字前,通常我們會先設定字型和大小,使用 ctx.font 屬性,例如 ctx.font = "20px Arial"。若未設定字型,Canvas 會使用預設字型(一般是 10px sans-serif)。

以下範例展示如何在 Canvas 上繪製文字,以及填充和描邊的效果差異:

<canvas id="exampleText" width="400" height="100"></canvas>
<script>
  const canvas = document.getElementById("exampleText");
  const ctx = canvas.getContext("2d");

  ctx.font = "24px Microsoft JhengHei";   // 設定字型和大小
  ctx.fillStyle = "black";
  ctx.strokeStyle = "red";
  ctx.lineWidth = 2;

  ctx.fillText("Hello Canvas!你好 Canvas!", 20, 40);   // 實心文字
  ctx.strokeText("Hello Canvas!你好 Canvas!", 20, 80); // 空心描邊文字
</script>

程式執行後,我們可以在畫布上看到上方繪製了一行黑色實心文字"Hello Canvas!你好 Canvas!",下方繪製了一行紅色空心文字,文字的字型被設定為微軟正黑體(Microsoft JhengHei)24px大小。由此可以觀察到 fillText 與 strokeText 的效果差別:前者字體本身填滿顏色,後者只有字的外輪廓線條。您可以調整 strokeStyle 來改變文字輪廓顏色,或調整 lineWidth 改變描邊粗細,以獲得不同風格的文字效果。如果需要文字排列換行或更複雜的文字版面,Canvas 需要開發者自行計算座標或切割字串(因 Canvas 文字繪製不會自動換行)。

文字API使我們能將說明、標籤直接繪製在Canvas圖形上,搭配前面介紹的圖形繪製方法,可以創作出內容豐富的教學示意圖或資料視覺化圖表。例如,在遊戲中顯示分數、在圖表上標出數值、在圖像上添加水印等等,都可以使用 Canvas 的文字繪製來達成。

常見問題 (FAQ)

本單元匯總了幾個在使用 Canvas 進行基礎繪圖時,初學者經常遇到的問題與解答,希望能幫助您順利排解疑惑:

Q1:為什麼我執行繪圖程式後,Canvas 上什麼都沒顯示出來?

A1: 可能原因有幾種:

  • 沒有取得 2D 繪圖上下文(context):在繪圖前一定要透過 canvas.getContext("2d") 取得繪圖用的 context 物件,才能呼叫各種繪圖方法。如果這步驟遺漏,ctx 會是 null,繪圖命令自然不會有效果。
  • 忘記調用渲染方法:如果使用了路徑繪圖,如 moveTo、lineTo 等,結束後需要呼叫 ctx.fill() 或 ctx.stroke() 才會真正把圖形畫出來。如果只定義了路徑但沒有填充或描邊,Canvas 不會呈現任何圖形。
  • 繪圖顏色與背景相同:有時圖形其實畫出來了,但可能因為 fillStyle 或 strokeStyle 的顏色剛好和背景相近(甚至透明)而導致肉眼看不見。請確保設定了一個可辨識的繪圖顏色。

Q2:繪製直線/曲線時,為何起點沒有出現在畫布上?

A2: 請檢查是否在繪圖前正確地使用了 moveTo(x, y) 來設定路徑的起點。如果省略 moveTo 就直接 lineTo(x, y),那麼起點會被默認為先前路徑最後繪製的位置,或者 (0,0)(若沒有先前路徑)。這常常導致線條從畫布角落意外地連過來。養成每次繪製新圖形前使用 beginPath() 並搭配 moveTo 設定起始點的習慣,可以避免不必要的連線。

Q3:使用 arc() 繪製弧形時角度總是算不準,如何正確設定角度?

A3: 請確認您使用的是弧度而非度數。Canvas 的 arc 方法所有角度參數都需以 Radians (弧度) 表示。例如,要表達 45 度,應使用約 0.785 (即 π/4) 的弧度值。如果您比較習慣以度數思考,可以在程式中先將度數轉換,如使用 (Math.PI/180) * 度數 的公式做換算。另外,請留意 startAngle 和 endAngle 是相對於圓心右側水平軸的角度,而 anticlockwise 參數會影響弧形繪製的方向,這些都會影響弧線出現的位置和形狀。建議多實驗小角度與大角度的搭配,並善用顏色或輔助圖形來確認弧線範圍是否如預期。

Q4:為什麼呼叫了 fillText/strokeText 卻看不到文字?

A4: 可能原因如下:

  • 沒有設定字型或字體太小:Canvas 預設字型大小僅為 10px,可能較小且不顯眼。您可以透過 ctx.font 設定較大的字型大小以及字體,比如 "16px sans-serif" 或 "20px 微軟正黑體" 等,以確保文字清晰可見。
  • 文字座標在畫布範圍外:請確認傳入 fillText/strokeText 的座標在 Canvas 寬高範圍內。如果 x、y 超出了畫布邊界,文字將無法顯示在畫布上。
  • 填充或描邊顏色問題:若您使用 strokeText 而 ctx.strokeStyle 預設為白色或透明,可能導致文字描邊不可見。請將描邊顏色設為對比背景的顏色。

Q5:Canvas 繪圖看起來失真/模糊,如何改善畫質?

A5: 這通常發生在高 DPI 顯示器或拉伸 Canvas 元素時。幾種改善方法:

  • 使用更高解析度:將 Canvas 的實際畫素尺寸設大一些(透過 HTML 屬性設定 width、height),再用 CSS 縮放顯示,可以增加細節。如 Retina 螢幕下可將 Canvas 實際大小設定為顯示大小的兩倍,繪圖時等比縮放座標,達到高清效果。
  • 避免非整數座標:如果繪製線條時座標不是整數,單像素線可能會因為位於像素格的邊緣而呈現模糊。可以嘗試將座標或線寬調整,使線條對齊像素網格(例如將 0.5 的偏移加入座標,使線條落在整像素上)。
  • 適當使用抗鋸齒:Canvas 瀏覽器預設會抗鋸齒,但在某些情況下可能導致模糊。如果追求像素級銳利,可考慮關閉陰影或使用位圖字型等方式,不過大多數情況下透過提高解析度即可解決問題。

結論

透過本篇教學的逐步講解,我們從 Canvas 基礎繪圖的起點——矩形開始,一路學習了如何使用 JavaScript 操控 Canvas 來繪製各種基本圖形和路徑。我們探討了路徑的繪製原理,學會使用直線段與弧線段來構成圖形,進而深入了解了二次與三次貝茲曲線的強大之處,能夠創造出平滑而多樣的曲線造型。我們也動手實作了自由繪製曲線的互動功能,讓 Canvas 不僅能畫出預定的圖形,還能即時捕捉使用者的筆跡。同時,我們沒有忽略文字繪製,在 Canvas 上輸出填充或描邊文字為圖形增添說明。整體而言,Canvas 2D API 提供了豐富的繪圖工具,只要掌握了這些基礎,本真性地運用創意,就能在瀏覽器中畫出精彩的影像與圖案。

在實際應用中,您可以將這些技術組合起來:例如,使用路徑繪製各種圖形後,再用文字標註說明,或者讓使用者透過自由繪製在既有圖像上做重點標記。隨著熟練度提高,還可以探索 Canvas 更進階的功能,如影像繪製、圖形變形 (transform)、合成效果 (compositing) 等等。不論您是想製作網頁遊戲、資料視覺化、繪圖應用或是簡單的動畫展示,Canvas 都是值得深入研究的強大工具。希望本教程內容能為您的 Canvas 繪圖之旅奠定堅實的基礎,讓您在未來的創作中揮灑自如,畫出屬於自己的精彩作品!

CONTACT US

網站設計報價洽詢

請填寫您的資料,我們將儘快與您聯繫! 為必填