| この記事の要点 |
|
パス描画の基本フロー
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
// ★ 基本パターン
ctx.beginPath(); // 1. パスを開始
ctx.moveTo(10, 10); // 2. 始点へ
ctx.lineTo(100, 10); // 3. 各種描画
ctx.lineTo(100, 100);
ctx.closePath(); // 4. 始点に戻す (任意)
ctx.strokeStyle = '#000';
ctx.stroke(); // 5. 線を描く
// または
ctx.fillStyle = '#3498db';
ctx.fill(); // 5'. 塗りつぶす
beginPath() を毎回呼ぶのが鉄則。呼ばないと前の stroke() 対象が累積し、線幅変更が過去パスにも適用される事故が起きます。
直線とポリライン
// 一本の直線
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(200, 100);
ctx.stroke();
// 三角形
ctx.beginPath();
ctx.moveTo(100, 50);
ctx.lineTo(200, 200);
ctx.lineTo(50, 200);
ctx.closePath(); // 3 辺目を自動で描いて閉じる
ctx.stroke();
// 折れ線 (ポリライン)
ctx.beginPath();
ctx.moveTo(0, 100);
[50, 80, 120, 200, 250].forEach((y, i) => {
ctx.lineTo(i * 50, y);
});
ctx.stroke();
円弧 (arc / arcTo)
// arc(x, y, radius, startAngle, endAngle, counterclockwise)
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2); // 完全な円
ctx.stroke();
// 半円 (右半分)
ctx.beginPath();
ctx.arc(100, 100, 50, -Math.PI / 2, Math.PI / 2);
ctx.stroke();
// 反時計回り
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI, true);
ctx.stroke();
// arcTo(x1, y1, x2, y2, radius)
// 現在位置から (x1,y1) へ向かい、半径 radius の角丸を描いて (x2,y2) 方向へ
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.arcTo(150, 50, 150, 150, 30); // 30 で角丸の四角
ctx.lineTo(150, 200);
ctx.stroke();
2 次ベジェ (quadraticCurveTo)
// quadraticCurveTo(cpx, cpy, x, y)
// 現在位置から (x, y) へ、(cpx, cpy) を制御点として 2 次ベジェ
ctx.beginPath();
ctx.moveTo(50, 200);
ctx.quadraticCurveTo(150, 50, 250, 200); // 山型
ctx.stroke();
// 制御点を可視化
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(150, 50, 4, 0, Math.PI * 2);
ctx.fill();
3 次ベジェ (bezierCurveTo)
// bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
// 制御点 2 つで S 字なども描ける
ctx.beginPath();
ctx.moveTo(50, 200);
ctx.bezierCurveTo(
100, 50, // 制御点 1
200, 350, // 制御点 2
250, 200, // 終点
);
ctx.stroke();
楕円 (ellipse)
// ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle)
ctx.beginPath();
ctx.ellipse(150, 100, 80, 40, 0, 0, Math.PI * 2);
ctx.stroke();
// 45 度回転した楕円
ctx.beginPath();
ctx.ellipse(150, 100, 80, 40, Math.PI / 4, 0, Math.PI * 2);
ctx.stroke();
Path2D オブジェクト
Path2D はパスを再利用可能なオブジェクトとして持てる API。同じ図形を何度も描く場合に便利:
// パスを 1 度作成
const triangle = new Path2D();
triangle.moveTo(0, 0);
triangle.lineTo(50, 0);
triangle.lineTo(25, 40);
triangle.closePath();
// 何度でも使える
for (let i = 0; i < 5; i++) {
ctx.save();
ctx.translate(i * 60, 0);
ctx.fillStyle = `hsl(${i * 60}, 70%, 50%)`;
ctx.fill(triangle);
ctx.restore();
}
// SVG パス文字列を直接渡せる ★
const star = new Path2D('M 50 0 L 60 35 L 95 35 L 67 55 L 78 90 L 50 70 L 22 90 L 33 55 L 5 35 L 40 35 Z');
ctx.fillStyle = 'gold';
ctx.fill(star);
線スタイル
ctx.lineWidth = 5; // 太さ
ctx.strokeStyle = '#e74c3c'; // 色
ctx.lineCap = 'round'; // butt | round | square (端の形状)
ctx.lineJoin = 'round'; // miter | round | bevel (角の形状)
ctx.miterLimit = 10; // miter のとがり制限
// 破線
ctx.setLineDash([10, 5]); // 10 描画 / 5 空白
ctx.lineDashOffset = 0;
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(250, 50);
ctx.stroke();
// 1 点鎖線
ctx.setLineDash([20, 5, 2, 5]);
// 元に戻す
ctx.setLineDash([]);
塗り潰し規則 (fill rule)
// 自己交差する図形で内側判定が変わる
ctx.fill('nonzero'); // ★ デフォルト
ctx.fill('evenodd'); // SVG と同じ規則 (奇数回交差で内側)
// 例: 五芒星
ctx.beginPath();
for (let i = 0; i < 5; i++) {
const a = -Math.PI / 2 + i * Math.PI * 4 / 5; // 2 つ飛ばし
const x = 100 + Math.cos(a) * 80;
const y = 100 + Math.sin(a) * 80;
i ? ctx.lineTo(x, y) : ctx.moveTo(x, y);
}
ctx.closePath();
ctx.fillStyle = 'gold';
ctx.fill('evenodd'); // 中央のくぼみが抜ける
パス操作系メソッドまとめ
| メソッド | 概要 |
|---|---|
beginPath() | パスをリセット |
closePath() | 始点に戻す直線を引く |
moveTo(x, y) | ペン位置を移動 (描画なし) |
lineTo(x, y) | 直線 |
quadraticCurveTo | 2 次ベジェ |
bezierCurveTo | 3 次ベジェ |
arc | 円弧 (中心 + 半径 + 角度) |
arcTo | 2 接線の間の角丸円弧 |
ellipse | 楕円 |
rect(x, y, w, h) | 矩形パス |
roundRect(x, y, w, h, r) | 角丸矩形 (Chrome 99+) |
stroke() / fill() | 描画実行 |
clip() | クリッピング領域に設定 |
isPointInPath | 当たり判定 |
SVG パスからの変換
SVG の d 属性のパス文字列はそのまま Path2D に渡せます:
// SVG 風のハート
const heart = new Path2D(`
M 100 30
C 100 10, 60 10, 60 50
C 60 80, 100 100, 100 130
C 100 100, 140 80, 140 50
C 140 10, 100 10, 100 30
Z
`);
ctx.fillStyle = '#e91e63';
ctx.fill(heart);
パフォーマンス Tips
- Path2D を再利用: 毎フレーム同じパスを作り直さない
beginPath()を必ず: パスが累積するとパフォーマンス劣化- 整数座標を使う:
0.5オフセットで半画素を回避すると線がシャープに - OffscreenCanvas + Worker: 重い描画は Worker に逃がす
- requestAnimationFrame でループ (setInterval ではなく)
FAQ
Q: 線が滲んで見える
A: 整数座標に +0.5 オフセットすると 1px ラインが滲まなくなります。ctx.translate(0.5, 0.5) も可。
Q: クリックしたパスを判定したい
A: ctx.isPointInPath(path, x, y) / ctx.isPointInStroke(path, x, y)。Path2D 渡しが推奨。
Q: 矢印を描きたい
A: 線端に三角形を描く。角度は Math.atan2(dy, dx) で求めて rotate + 三角形 fill。
子ページ
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Git pushした変更の取消し|revert・履歴変更と保護の注意点 2026-10-15 23:49:01
- Gitでローカルを戻す前に|reset・restoreの違いと退避範囲 2026-10-15 23:49:01
- Git rebaseの使い方|対象範囲・競合解決・pushの判断 2026-10-15 22:50:59
- Git pullの使い方|取込み先・ff-only・競合とstashの注意点 2026-10-15 22:50:59
- Git pushの使い方|送信先・タグ・force-with-leaseの条件 2026-10-15 22:12:47
- Git remoteの設定・確認・削除|SSH URLとfetch/pushの違い 2026-10-15 22:12:47
- Gitリモートリポジトリの作成|初回push・既存履歴・mirrorの注意 2026-10-15 15:48:16
- Gitのuser.name・user.email設定|local/global・確認と過去履歴の注意 2026-10-15 15:30:07
- LinuxにGitをインストール|配布元・初期設定・TLSと認証の確認 2026-10-15 15:30:06
- Git導入と初回push|Linuxサーバー・Windows/macOS・SSH設定 2026-10-15 14:51:54
- Db2のCREATE INDEX|索引定義・INCLUDEと実行計画の確認 2026-10-15 14:10:22
- Db2の自動採番|IDENTITY・ID取得とRESTARTの注意点 2026-10-15 14:10:22
- 【DB2】特定スキーマの全テーブルの全カラム情報を取得する方法 2026-10-15 13:53:15
- Db2のシーケンスとIDENTITYの違い|採番とカタログの確認SQL 2026-10-15 13:53:15
- Db2で複数カラムをUPDATEする方法|SET・WHEREと更新前の値 2026-10-15 13:53:15