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

タイトル: Canvas API
SEOタイトル: HTML5 Canvas API 入門(描画 / アニメーション / Three.js / PixiJS への発展)

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>Canvas API は <strong><canvas> 要素 + JavaScript</strong> でブラウザにビットマップ描画する API</li><li><code>canvas.getContext("2d")</code> で 2D コンテキスト、<code>"webgl"</code> で 3D(OpenGL ES2 ラッパ)</li><li>基本図形: <code>fillRect</code> / <code>strokeRect</code> / <code>arc</code>(円) / <code>beginPath + moveTo + lineTo + stroke</code>(線)</li><li>画像・テキスト: <code>drawImage(img, x, y)</code> / <code>fillText(text, x, y)</code></li><li>アニメーションは <strong>requestAnimationFrame</strong>。複雑になったら <strong>PixiJS</strong>(2D)・<strong>Three.js</strong>(3D)を使う</li></ul></td></tr></table>
<h2>Canvas API とは</h2>

<p>HTML5 で導入された <code><canvas></code> 要素は、JavaScript からピクセル単位で描画できる<strong>ビットマップキャンバス</strong>です。ゲーム、グラフ、画像処理、データビジュアライゼーションなど幅広く使われます。</p>

<h2>最小サンプル: 四角形を描く</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!DOCTYPE html>
<html>
<body>
<canvas id="c" width="500" height="300" style="border:1px solid #ccc"></canvas>
<script>
const canvas = document.getElementById(&apos;c&apos;);
const ctx = canvas.getContext(&apos;2d&apos;);

// 塗りつぶし四角形
ctx.fillStyle = &apos;#3498db&apos;;
ctx.fillRect(20, 20, 100, 60);

// 枠線のみの四角形
ctx.strokeStyle = &apos;#e74c3c&apos;;
ctx.lineWidth = 3;
ctx.strokeRect(150, 20, 100, 60);

// クリア
// ctx.clearRect(0, 0, canvas.width, canvas.height);
</script>
</body>
</html></code></pre>
<p><strong>width / height は CSS でなく属性で指定</strong>するのが鉄則。CSS で指定すると拡大表示になりピクセルがぼやけます。</p>

<h2>基本図形の描画</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// 直線
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(200, 100);
ctx.lineTo(50, 150);
ctx.closePath();      // パスを閉じる
ctx.stroke();         // 線として描画
// ctx.fill();        // 塗りつぶし

// 円 / 円弧
ctx.beginPath();
ctx.arc(300, 100, 50, 0, Math.PI * 2);  // x, y, r, 開始角, 終了角(ラジアン)
ctx.fillStyle = &apos;#2ecc71&apos;;
ctx.fill();

// 半円
ctx.beginPath();
ctx.arc(400, 100, 50, 0, Math.PI);
ctx.stroke();

// 二次ベジェ曲線
ctx.beginPath();
ctx.moveTo(50, 200);
ctx.quadraticCurveTo(150, 100, 250, 200);  // 制御点, 終点
ctx.stroke();</code></pre>
<h2>テキスト描画</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">ctx.font = &apos;bold 32px sans-serif&apos;;
ctx.fillStyle = &apos;#2c3e50&apos;;
ctx.textAlign = &apos;center&apos;;        // start | end | left | right | center
ctx.textBaseline = &apos;middle&apos;;     // top | hanging | middle | alphabetic | ideographic | bottom
ctx.fillText(&apos;Hello Canvas&apos;, 250, 50);

// 枠線のみ
ctx.strokeStyle = &apos;#e74c3c&apos;;
ctx.lineWidth = 2;
ctx.strokeText(&apos;Outline&apos;, 250, 100);

// 文字幅を測る
const m = ctx.measureText(&apos;Hello&apos;);
console.log(m.width);  // pixel</code></pre>
<h2>画像の描画</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">const img = new Image();
img.src = &apos;/path/to/photo.jpg&apos;;
img.onload = () => {
    // 原寸
    ctx.drawImage(img, 50, 50);

    // サイズ指定
    ctx.drawImage(img, 50, 50, 200, 150);

    // 切り抜き + 配置(sx, sy, sw, sh, dx, dy, dw, dh)
    ctx.drawImage(img, 0, 0, 100, 100, 300, 50, 200, 200);
};</code></pre>
<h2>変形(回転・拡大・移動)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">ctx.save();                          // 状態を保存
ctx.translate(250, 150);             // 原点を移動
ctx.rotate(Math.PI / 4);             // 45 度回転
ctx.scale(1.5, 1.5);                 // 1.5 倍拡大
ctx.fillStyle = &apos;#9b59b6&apos;;
ctx.fillRect(-50, -25, 100, 50);     // 移動後の原点が中心
ctx.restore();                       // 元の状態に戻す</code></pre>
<h2>アニメーション: requestAnimationFrame</h2>

<p>毎フレーム描き直すには <code>requestAnimationFrame</code> を使います。<code>setInterval</code> ではブラウザの再描画タイミングと同期しないのでカクつきます。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">let x = 0;
let vx = 2;

function tick() {
    // 1. 画面クリア
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // 2. 状態更新
    x += vx;
    if (x > canvas.width - 50 || x < 0) vx = -vx;

    // 3. 描画
    ctx.fillStyle = &apos;#3498db&apos;;
    ctx.fillRect(x, 100, 50, 50);

    // 4. 次フレームを予約
    requestAnimationFrame(tick);
}

tick();</code></pre>
<h2>マウス入力でお絵描き</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">let drawing = false;
canvas.addEventListener(&apos;mousedown&apos;, e => {
    drawing = true;
    ctx.beginPath();
    ctx.moveTo(e.offsetX, e.offsetY);
});
canvas.addEventListener(&apos;mousemove&apos;, e => {
    if (!drawing) return;
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
});
canvas.addEventListener(&apos;mouseup&apos;, () => drawing = false);</code></pre>
<h2>Canvas API でできることの限界</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>用途</th><th>素の Canvas</th><th>推奨ライブラリ</th></tr></thead>
<tbody>
<tr><td>簡単な図形・グラフ</td><td>OK</td><td>Chart.js</td></tr>
<tr><td>2D ゲーム(スプライト多数)</td><td>遅い</td><td><strong>PixiJS</strong>(WebGL 加速)</td></tr>
<tr><td>3D 描画</td><td>不可(getContext("webgl") 必要)</td><td><strong>Three.js</strong> / Babylon.js</td></tr>
<tr><td>SVG 的なベクタ</td><td>パスは描けるが座標管理が大変</td><td>SVG + D3.js</td></tr>
<tr><td>動画フィルタ</td><td>getImageData / putImageData で可能</td><td>WebGL + シェーダ</td></tr>
</tbody>
</table>

<h2>WebGL コンテキストへの拡張</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// 2D → 3D の入り口
const gl = canvas.getContext(&apos;webgl2&apos;);
if (!gl) {
    alert(&apos;WebGL2 がサポートされていません&apos;);
}

// 実際は Three.js を使うのが現実的
// npm install three
import * as THREE from &apos;three&apos;;
const scene  = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, w/h, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ canvas });
const cube = new THREE.Mesh(
    new THREE.BoxGeometry(),
    new THREE.MeshNormalMaterial()
);
scene.add(cube);
camera.position.z = 3;

renderer.setAnimationLoop(() => {
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
});</code></pre>
<h2>FAQ</h2>

<p><strong>Q: Canvas で描いた絵を画像保存したい</strong><br />
A: <code>canvas.toDataURL('image/png')</code> で base64 取得、<code>canvas.toBlob(cb)</code> で Blob 取得が可能です。</p>

<p><strong>Q: 高 DPI(Retina)でぼやける</strong><br />
A: <code>canvas.width = w * devicePixelRatio</code> にして <code>ctx.scale(devicePixelRatio, devicePixelRatio)</code>、CSS 側は <code>w</code> px に。</p>

<p><strong>Q: SVG とどちらが良い?</strong><br />
A: 拡大に強く要素単位でイベント取りたいなら SVG、ピクセル制御や多数オブジェクトのアニメは Canvas が高速です。</p>