W3docs

JavaScript Canvas API

Learn how to draw graphics with the HTML canvas element and JavaScript: get a 2D context, draw shapes and lines, and apply transformations.

Introduction to HTML Canvas with JavaScript

The HTML <canvas> element is a drawing surface you control with JavaScript. Unlike images or SVG, canvas is immediate-mode: there are no shape objects to keep track of. You issue drawing commands and pixels are painted right away. Once painted, a shape is just colored pixels — the canvas has no memory of it, which is why redrawing is the core idea behind every animation.

This chapter walks through getting a 2D context, drawing shapes and lines, transforming the coordinate system, and animating with requestAnimationFrame.

This page covers the 2D rendering context (getContext('2d')). Canvas also exposes a webgl context for hardware-accelerated 3D graphics, which is a separate API.

Understanding the 'canvas' Element

The <canvas> element creates a fixed-size drawing surface that renders graphics on the fly. It shines in graphics-intensive work — games, charts, image manipulation, particle effects — where you need pixel-level control and high frame rates. By itself the tag draws nothing; it is an empty container, and JavaScript does all the painting.

One gotcha to learn early: the width and height attributes set the drawing buffer size, while CSS width/height set the displayed size. If they disagree, the canvas is stretched and your drawings look blurry or distorted. Set the size with the attributes (or in JS via canvas.width/canvas.height), not with CSS, unless you intend to scale.

Basic Canvas Setup

To start drawing, place a <canvas> tag in your HTML, then grab its 2D drawing context in JavaScript with getContext('2d'). The context object is where every drawing method lives.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Example</title>
<style>
  canvas {
    border: 1px solid #000;
  }
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('myCanvas');
  const ctx = canvas.getContext('2d');
</script>
</body>
</html>

Here we define a 200×200 canvas, give it a border so you can see its bounds, and obtain the context with getContext('2d'). The border is purely visual; the canvas surface itself starts fully transparent.

Note the coordinate system: the origin (0, 0) is the top-left corner. The x-axis grows to the right and the y-axis grows downward, so (0, 0) is the top edge and larger y values move toward the bottom. This trips up newcomers who expect math-style axes.

Drawing Shapes

The fastest way to put something on screen is fillRect(x, y, width, height), which draws a filled rectangle in a single call. Set fillStyle first to choose the color (any CSS color string works). There is also strokeRect for an outline-only rectangle and clearRect to erase a region back to transparent.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rectangle Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="rectangleCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('rectangleCanvas');
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = '#FF0000'; // Set the fill color to red
  ctx.fillRect(20, 20, 150, 100); // Draw the rectangle
</script>
</body>
</html>

Creating Lines and Paths

Lines, curves, and custom shapes are all built from paths. The pattern is always the same:

  1. beginPath() — start a fresh path (skip this and your new line joins the previous one).
  2. moveTo(x, y) — lift the pen and place it without drawing.
  3. lineTo(x, y) — draw a line segment to a new point (call it repeatedly to chain segments).
  4. stroke() to draw the outline, or fill() to fill the enclosed area.

Control the line appearance with lineWidth, strokeStyle, and lineCap before calling stroke().

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Line Drawing Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="lineCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('lineCanvas');
  const ctx = canvas.getContext('2d');
  ctx.beginPath(); // Start the path
  ctx.moveTo(50, 50); // Move the pen to (50, 50)
  ctx.lineTo(150, 50); // Draw a line to (150, 50)
  ctx.lineTo(150, 150); // Continue to (150, 150)
  ctx.lineWidth = 4; // Thicker line
  ctx.strokeStyle = 'navy'; // Line color
  ctx.stroke(); // Render the path visible
</script>
</body>
</html>

Drawing Circles and Arcs

Circles are drawn with arc(x, y, radius, startAngle, endAngle), where the angles are in radians (a full circle is 2 * Math.PI). Wrap it in a path and then fill() or stroke():

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Circle Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="circleCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('circleCanvas');
  const ctx = canvas.getContext('2d');
  ctx.beginPath();
  // Center (100, 100), radius 60, full circle
  ctx.arc(100, 100, 60, 0, 2 * Math.PI);
  ctx.fillStyle = 'orange';
  ctx.fill();
  ctx.stroke(); // Add an outline on top of the fill
</script>
</body>
</html>

Advanced Canvas Operations

Canvas Transformations

translate, rotate, and scale modify the canvas coordinate system rather than individual shapes. Crucially, they are cumulative — each one builds on the previous, and a rotation pivots around the current origin, not the shape's center. To rotate around a point, translate to that point first, then rotate.

Because transforms stack up, wrap them in ctx.save() / ctx.restore() so you can return to the previous state instead of manually undoing each transform:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Transformation Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="transformCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('transformCanvas');
  const ctx = canvas.getContext('2d');
  ctx.save(); // Remember the untransformed state
  ctx.translate(50, 50); // Move the canvas origin to (50, 50)
  ctx.rotate((Math.PI / 180) * 25); // Rotate 25 degrees (converted to radians)
  ctx.fillStyle = 'blue'; // Set fill color to blue
  ctx.fillRect(0, 0, 100, 50); // Draw at the new, rotated origin
  ctx.restore(); // Back to the original coordinate system
</script>
</body>
</html>

Animations Using Canvas

Canvas has no built-in animation; you create motion by repeatedly clearing and redrawing the whole surface. The browser's requestAnimationFrame schedules your draw function to run before the next repaint — typically 60 times per second — and pauses automatically when the tab is hidden, which is why it is preferred over setInterval.

The loop always follows three steps: clear the canvas (clearRect), update the state (here, the x position), then draw the new frame. Forget the clearRect and you will see a smear of every past frame instead of a moving shape.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Animation Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="animationCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('animationCanvas');
  const ctx = canvas.getContext('2d');
  let x = 0; // Starting position
  function drawFrame() {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas for the new frame
    ctx.fillStyle = 'green'; // Set the fill color to green
    ctx.fillRect(x, 20, 50, 50); // Draw a moving rectangle
    x++; // Increment the horizontal position
    if (x > canvas.width) {
      x = 0;
    }
    requestAnimationFrame(drawFrame); // Continue the animation
  }
  drawFrame();
</script>
</body>
</html>

Common Pitfalls

  • Blurry output: mismatched buffer size and CSS size. Set dimensions with the width/height attributes, not CSS, unless you are intentionally scaling.
  • Shapes joined together: forgetting beginPath() before a new path makes it continue the old one.
  • Lines disappear: you called stroke() or fill() but never built a path, or you drew outside the canvas bounds.
  • Animation leaves trails: missing clearRect at the top of each frame.
  • Nothing rendered: the script ran before the <canvas> existed in the DOM. Place the script after the element, or run it on DOMContentLoaded.

Conclusion

The <canvas> element gives you a low-level, pixel-perfect surface for graphics that HTML and CSS cannot produce: charts, image editing, particle systems, and full games. The API is small — get a context, set a style, issue a draw command — and animations are simply that loop run many times per second.

To go deeper, see the HTML canvas tag and canvas drawing basics for the markup side, and JavaScript animations and the requestAnimationFrame-based animations API for smoother motion. To select your canvas reliably, review getElement and querySelector.

Practice

Practice
What can you do with the Canvas element in JavaScript according to the content found on w3docs.com?
What can you do with the Canvas element in JavaScript according to the content found on w3docs.com?
Was this page helpful?