← thecodex.expert · The Codex Family of Knowledge
The Codex / JavaScript / Canvas API

Canvas API

Drawing 2D graphics in the browser — shapes, text, images, animations, and pixel manipulation with the HTML5 Canvas.

What it is, in plain English: The Canvas API provides a 2D drawing surface in the browser via the element. You get a rendering context with methods to draw shapes, lines, curves, text, and images. Canvas is an immediate-mode API — you draw pixels, not a DOM tree. It's used for: games, data visualisation, image editing, generative art, and anywhere SVG is too slow or too complex.
Where this bites you

A canvas has two sizes: the size CSS displays it at, and its drawing surface, set by the width and height attributes (300 × 150 if you leave them out). Size a canvas only with CSS and your drawing commands still work in the 300 × 150 surface, which is then stretched to fit. Shapes land in the wrong place or disappear past the edge, and everything looks blurry.

// <canvas id="chart" style="width: 600px; height: 300px"></canvas>   <- size set only in CSS
const canvas = document.getElementById("chart");
const ctx    = canvas.getContext("2d");

console.log(canvas.width, canvas.height);                  // the real drawing surface
ctx.fillStyle = "royalblue";
ctx.fillRect(500, 100, 50, 50);                            // meant for the right-hand side
console.log(ctx.getImageData(520, 120, 1, 1).data[3]);     // alpha of a pixel inside that square
// 300 150
// 0          <- nothing there: x = 500 is outside a 300-pixel-wide surface

Drawing on the web

The Canvas API gives you a blank drawing surface in the browser. Unlike HTML elements, canvas has no DOM nodes for each shape — you issue drawing commands and pixels appear. This makes it much faster for things that change constantly, like animations and games.

Setup

<!-- HTML: -->
<canvas id="myCanvas" width="400" height="300"></canvas>

// JavaScript:
const canvas = document.getElementById("myCanvas");
const ctx    = canvas.getContext("2d");   // 2D rendering context

// Canvas coordinate system:
// (0, 0) is top-left
// x increases to the right
// y increases downward

The setup above avoids this by putting width and height on the <canvas> tag itself. When CSS decides the size (a responsive layout, say), copy the displayed size onto the drawing surface in JavaScript, multiplied by devicePixelRatio so it stays sharp on high-density screens. Then scale the context, so you can keep drawing in CSS pixels:

const canvas = document.getElementById("chart");
const ctx    = canvas.getContext("2d");

const dpr  = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();               // the size CSS gave it: 600 x 300
canvas.width  = rect.width  * dpr;                         // match the drawing surface to it
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);                                       // keep drawing in CSS pixels

console.log(canvas.width, canvas.height);
ctx.fillStyle = "royalblue";
ctx.fillRect(500, 100, 50, 50);
console.log(ctx.getImageData(520 * dpr, 120 * dpr, 1, 1).data[3]);   // getImageData uses surface pixels
// 600 300    (1200 600 on a 2x screen)
// 255

Shapes

// Filled rectangle: x, y, width, height
ctx.fillStyle = "royalblue";
ctx.fillRect(10, 10, 100, 50);

// Stroked (outlined) rectangle:
ctx.strokeStyle = "coral";
ctx.lineWidth = 2;
ctx.strokeRect(130, 10, 100, 50);

// Clear a rectangle (erases to transparent):
ctx.clearRect(50, 25, 20, 20);

// Circle using arc():
ctx.fillStyle = "gold";
ctx.beginPath();
ctx.arc(
  250, 35,      // center x, y
  25,           // radius
  0,            // start angle (radians)
  Math.PI * 2   // end angle (full circle = 2π)
);
ctx.fill();   // or ctx.stroke() for outlined

Paths — for complex shapes

// Always beginPath() before drawing, then fill() or stroke():
ctx.fillStyle = "mediumseagreen";
ctx.beginPath();
ctx.moveTo(100, 100);   // starting point
ctx.lineTo(200, 100);   // line to...
ctx.lineTo(150, 180);   // line to...
ctx.closePath();         // line back to start
ctx.fill();              // fill the shape

// Curves:
ctx.strokeStyle = "purple";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(20, 200);
ctx.bezierCurveTo(80, 130, 160, 270, 220, 200);  // cp1x, cp1y, cp2x, cp2y, endX, endY
ctx.stroke();

Text and images

// Text:
ctx.fillStyle = "#333";
ctx.font      = "bold 24px Arial";
ctx.textAlign = "center";        // "left", "center", "right"
ctx.textBaseline = "middle";     // "top", "middle", "bottom"
ctx.fillText("Hello Canvas!", canvas.width / 2, canvas.height / 2);

// Measure text width (for layout):
const metrics = ctx.measureText("Hello Canvas!");
console.log("Text width:", metrics.width);

// Image:
const img = new Image();
img.onload = () => {
  ctx.drawImage(img, 10, 10);            // draw at (10,10)
  ctx.drawImage(img, 10, 10, 100, 80);   // draw and resize to 100x80
};
Try It Yourself

Official Sources

The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.