この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:guest
更新日時:2026-06-11 07:10:02

タイトル: 図形
SEOタイトル: Canvas API 図形描画|四角形 fillRect / 円 arc / 線 lineTo / 多角形 と塗りつぶし・輪郭の使い分け

この記事の要点
  • HTML5 Canvas で図形を描く API は fillRect / strokeRect(四角形)、arc(円・円弧)、moveTo + lineTo(線・多角形)が中心
  • arc(x, y, r, startAngle, endAngle, anticlockwise) の角度はラジアンで指定する
  • 塗りつぶしは fill()、輪郭は stroke()、消去は clearRect
  • Path API(beginPath / closePath)で複雑な形状をパスとしてまとめて描ける

Canvas で図形を描く基本

HTML5 の <canvas> 要素は、JavaScript から命令を出して図形を描画できるビットマップキャンバスです。グラフ・ゲーム・データビジュアライゼーション・画像加工など、幅広い用途で利用されます。

図形を描くには、まず canvas.getContext("2d") で 2D 描画コンテキストを取得し、そのコンテキストに対してメソッドを呼び出します。

// <canvas id="cv" width="400" height="300"></canvas>
const canvas = document.getElementById('cv');
const ctx = canvas.getContext('2d');

四角形

四角形はパスを構築せずに 1 行で描ける最も簡単な図形です。

メソッド役割
ctx.fillRect(x, y, w, h)塗りつぶしの四角形を描画
ctx.strokeRect(x, y, w, h)輪郭の四角形を描画
ctx.clearRect(x, y, w, h)その領域をクリア(透明にする)

x, y は矩形の左上端の座標、w は横幅、h は縦幅です。

ctx.fillStyle = '#3498db';
ctx.fillRect(20, 20, 100, 60);   // 青で塗りつぶし

ctx.strokeStyle = '#e74c3c';
ctx.lineWidth = 3;
ctx.strokeRect(150, 20, 100, 60); // 赤の輪郭線

円・円弧

円や円弧は arc() で描画します。角度はラジアンで指定する点に注意してください(度数法から変換するには 角度 * Math.PI / 180)。

メソッド役割
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise)円弧を作成
ctx.arcTo(x1, y1, x2, y2, radius)直前の座標と接続する円弧を作成(角丸の角に便利)

各引数の意味は次の通りです。

  • x, y: 円の中心座標
  • radius: 円の半径
  • startAngle: 描き始めの角度(ラジアン)。x 軸の正方向 = 右が 0
  • endAngle: 描き終えの角度(ラジアン)
  • anticlockwise: true で反時計回り、省略・false で時計回り

完全な円

ctx.beginPath();
ctx.arc(150, 150, 50, 0, Math.PI * 2);
ctx.fillStyle = '#2ecc71';
ctx.fill();

ctx.beginPath();
ctx.arc(280, 150, 50, 0, Math.PI * 2);
ctx.strokeStyle = '#e67e22';
ctx.lineWidth = 4;
ctx.stroke();

半円・扇形

// 上半円
ctx.beginPath();
ctx.arc(150, 250, 40, Math.PI, Math.PI * 2);
ctx.fillStyle = '#9b59b6';
ctx.fill();

// 扇形(中心まで線を引いて閉じる)
ctx.beginPath();
ctx.moveTo(280, 250);
ctx.arc(280, 250, 40, 0, Math.PI / 2);
ctx.closePath();
ctx.fillStyle = '#f1c40f';
ctx.fill();

線と多角形

直線は moveTo() でペンを移動し、lineTo() で線を引きます。複数の lineTo() をつなぐと多角形になります。

// 三角形
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(100, 130);
ctx.closePath();        // 始点まで自動で線を引いて閉じる
ctx.fillStyle = '#1abc9c';
ctx.fill();
ctx.strokeStyle = '#16a085';
ctx.stroke();

パスをまとめる - beginPath / closePath

Canvas のパスは「ペンの軌跡」を保持し続けるため、適切に beginPath() を呼ばないと、前の図形と一緒に塗られたり線が混ざったりします。図形を描く前は必ず beginPath()、塗りや輪郭を確定したら fill() / stroke() を呼ぶ、というセットで覚えるのが安全です。

クリアとリセット

キャンバス全体を消したい場合は clearRect(0, 0, canvas.width, canvas.height) を使います。アニメーションでは毎フレームの先頭でクリアし、新しい状態を描画する流れが基本パターンです。

function loop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    draw(); // 図形の描画処理
    requestAnimationFrame(loop);
}
loop();

色と塗りスタイル

図形の見た目は、描画前に ctx.fillStyle(塗り色)と ctx.strokeStyle(輪郭色)を設定して決定します。指定できる値は CSS と同じ書式で、"#ff0000""rgba(255,0,0,0.5)""red" などが使えます。さらに ctx.createLinearGradient()ctx.createRadialGradient() でグラデーションを作って fillStyle に渡せば、ボタンや円グラフのセクションに高級感のある表現を加えられます。輪郭線の太さは ctx.lineWidth、端の形状は ctx.lineCapbutt / round / square)、接続部分の形状は ctx.lineJoinmiter / round / bevel)で細かく制御できます。

状態の保存と復元

Canvas のコンテキストは「現在の塗り色」「現在の変換行列」「現在のクリップ領域」などの状態を持ち続けます。一時的に状態を変えて描いた後に元に戻したい場合は、ctx.save() で現在の状態をスタックにプッシュし、描画後 ctx.restore() でポップします。子要素ごとに変換や色を切り替える複雑な描画では、save/restore のセットを徹底することでバグが激減します。

座標変換

Canvas は translate(dx, dy)(平行移動)、rotate(rad)(回転)、scale(sx, sy)(拡大縮小)でキャンバス自体の座標系を変換できます。回転は中心点を原点として行われるため、特定の図形を中心に回転させたい場合は、まずその図形の中心へ translate し、そこで rotate し、図形を描き、最後に restore で元に戻すという順序が定石です。複雑なグラフィックを作る場合、図形側の座標計算を変換に任せると、ロジックが大幅にシンプルになります。

テキストと画像

図形だけでなく、テキストと画像も描画できます。テキストは ctx.font = "16px sans-serif" でフォント指定し、ctx.fillText(text, x, y) で描画します。画像は new Image() で読み込んだ要素を ctx.drawImage(img, x, y) で配置でき、引数を増やせばトリミングや拡大縮小も可能です。これにより、グラフのラベル、ゲームのスプライト、写真合成といった用途まで Canvas 1 枚で対応できます。

SVG との使い分け

ベクター描画として SVG と比較されることが多いですが、両者には明確な得意分野があります。Canvas はピクセルベースで大量の図形を毎フレーム描き直すゲームや可視化に強く、SVG は DOM 要素として残るため静的な図形・インタラクションが少ない図表に強みがあります。例えばインタラクティブダッシュボードでマウスホバーに反応させたい場合、SVG なら CSS と DOM イベントだけで実装できますが、Canvas では座標計算で当たり判定を自前で書く必要があります。描く対象の規模と動きの量で選び分けましょう。

パフォーマンス最適化

Canvas のパフォーマンスを引き出すコツは「無駄な描画をしない」ことに尽きます。第一に、変化があった部分だけを再描画する「ダーティリージョン」方式。前フレームと変わっていない領域はそのまま残し、変化のあった矩形だけを clearRect + 再描画します。第二に、頻繁に使う図形を別のオフスクリーンキャンバスに一度描き、本キャンバスへは drawImage でビットマップとして貼り付ける手法。複雑なテキストやベクター描画を毎フレーム計算するのに比べて圧倒的に軽くなります。第三に、ループ内で requestAnimationFrame を使うこと。setInterval はブラウザの描画タイミングと同期しないため、無駄な描画やフレーム落ちが起きやすくなります。

HiDPI(Retina)対応

Retina ディスプレイなど高解像度デバイスでは、CSS 上のピクセルと物理ピクセルが 1:2 や 1:3 で対応しています。何も対策せずに Canvas に描くと、ブラウザが拡大表示して輪郭がぼやけます。これを避けるには、window.devicePixelRatio を取得し、canvas.width = cssWidth * dprcanvas.style.width = cssWidth + "px" のように内部解像度を物理ピクセルに合わせ、コンテキストを ctx.scale(dpr, dpr) で拡大します。これにより CSS 上のサイズはそのままで、線や図形がシャープに描画されます。

テキスト描画のベースライン

fillText は与えた座標をテキストのベースラインとして扱います。文字の中心や上端を基準にしたい場合は ctx.textBaseline = "middle" / "top" / "bottom" などを指定します。水平方向の揃えは ctx.textAlign = "center" / "left" / "right" です。テキストの幅は ctx.measureText(text).width で測れるため、複数行の中央揃え配置や、長すぎる文字列の自動折り返しを実装する際に欠かせません。

関連記事