{
    "slug": "js_canvas_api",
    "term": "Canvas API — 2D Drawing",
    "category": "javascript",
    "difficulty": "intermediate",
    "short": "The HTML Canvas API provides a 2D drawing surface via JavaScript — used for charts, image manipulation, games, data visualisations, and any pixel-level rendering that DOM elements cannot efficiently handle.",
    "long": "A <canvas> element provides a bitmap drawing surface. JavaScript obtains a 2D rendering context via canvas.getContext('2d') and draws using methods like fillRect(), arc(), drawImage(), and fillText(). Canvas is immediate mode — you draw commands execute immediately and the result is just pixels; there is no retained object graph like SVG. This makes Canvas fast for many operations but means you must redraw everything on each frame for animations. The CanvasRenderingContext2D API includes path drawing (beginPath, moveTo, lineTo, arc), fill and stroke styles (colours, gradients, patterns), text rendering, image compositing, and transformations (translate, rotate, scale). For 3D, use WebGL or WebGPU via getContext('webgl2') instead.",
    "aliases": [
        "Canvas API",
        "HTML canvas",
        "2D context",
        "CanvasRenderingContext2D"
    ],
    "tags": [
        "javascript",
        "canvas",
        "graphics",
        "animation",
        "web-api"
    ],
    "misconception": "Canvas and SVG are interchangeable. Canvas is pixel-based and immediate — good for many moving objects (games, particle systems). SVG is vector-based and retained — good for interactive diagrams with mouse events per element, accessibility, and scaling at any resolution. Choose based on the use case.",
    "why_it_matters": "Canvas is the foundation of chart libraries (Chart.js, D3 SVG/canvas modes), image editors, game engines (Phaser, PixiJS), and QR code generators in the browser. Understanding Canvas lets you implement custom visualisations that CSS and SVG cannot efficiently handle, and debug or optimise rendering in libraries that wrap it.",
    "common_mistakes": [
        "Not accounting for devicePixelRatio — canvas renders blurry on retina screens; multiply width/height by devicePixelRatio and scale the context.",
        "Forgetting ctx.beginPath() before drawing paths — paths accumulate; without beginPath(), new shapes join the previous path, producing unexpected fills.",
        "Setting canvas size with CSS instead of the width/height attributes — CSS scales the bitmap (blurry); the attributes set the actual resolution.",
        "Doing heavy computation inside the animation loop — move data processing outside requestAnimationFrame and only draw inside it."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "js_requestanimationframe",
        "js_web_workers",
        "js_typed_arrays",
        "web_performance"
    ],
    "prerequisites": [],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API",
        "https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D"
    ],
    "bad_code": "// ❌ Leaking context state, not clearing between frames\nconst canvas = document.getElementById('c');\nconst ctx = canvas.getContext('2d');\n\nctx.fillStyle = 'red'; // Never reset — affects all subsequent draws\nctx.translate(100, 100); // Cumulative! Each frame moves 100px further\n\nfunction draw() {\n    // Missing: ctx.clearRect(0, 0, canvas.width, canvas.height)\n    ctx.fillRect(0, 0, 50, 50); // Draws over previous frame\n    requestAnimationFrame(draw);\n}",
    "good_code": "// ✅ Proper canvas animation loop\nconst canvas = document.getElementById('c');\nconst ctx = canvas.getContext('2d');\n\nlet x = 0;\n\nfunction draw() {\n    // Clear the entire canvas each frame\n    ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n    // Save/restore to isolate state changes\n    ctx.save();\n    ctx.fillStyle = 'royalblue';\n    ctx.translate(x, 100);\n    ctx.fillRect(-25, -25, 50, 50); // Centred rect\n    ctx.restore(); // fillStyle and translate are gone\n\n    x = (x + 2) % canvas.width; // Loop across canvas\n    requestAnimationFrame(draw);\n}\n\n// Set canvas resolution to match device pixel ratio (crisp on retina)\nconst dpr = window.devicePixelRatio || 1;\ncanvas.width  = canvas.offsetWidth  * dpr;\ncanvas.height = canvas.offsetHeight * dpr;\nctx.scale(dpr, dpr);\n\ndraw();",
    "quick_fix": "Always call ctx.save() before and ctx.restore() after applying transformations or style changes you don't want to leak — the canvas context is global state.",
    "effort": "medium",
    "created": "2026-03-23",
    "updated": "2026-04-05",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/js_canvas_api",
        "html_url": "https://codeclaritylab.com/glossary/js_canvas_api",
        "json_url": "https://codeclaritylab.com/glossary/js_canvas_api.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Canvas API — 2D Drawing](https://codeclaritylab.com/glossary/js_canvas_api) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/js_canvas_api"
            }
        }
    }
}