HTML Canvas

<canvas> is an HTML element used to draw graphics in the browser. Information on this page is taken from Mozilla's canvas tutorial.

<canvas id="example" width="150" height="150"></canvas>

Use a rendering context to create and manipulate content.

const canvas = document.getElementById('example');
const context = canvas.getContext('2d');

Rectangles

Canvas supports only one primitive shape: rectangles. Three functions exist for drawing rectangles:

  • fillRect(x, y, width, height)
    • Draw a filled rectangle.
  • strokeRect(x, y, width, height)
    • Draw a rectangle outline.
  • clearReact(x, y, width, height)
    • Make the rectangle area transparent.

The x~/~y parameters are relative to a top left origin.

Paths

Paths are the other primitives in canvas. First, call the beginPath() method. Then, execute one or more of the following drawing commands. Lastly, render the path stroke() and/or fill().

  • moveTo(x, y)
    • Lift and move the pen.
  • lineTo(x, y)
    • Draw a line.
  • arc(x, y, radius, startAngle, endAngle, anticlockwise)
    • Draw an arc centered at (x, y). startAngle and endAngle are given in radians.
  • arcTo(x1, y1, x2, y2, radius)
    • Draw an arc on ending at (x2, y2) with the control point (x1, y1), connected to the previous point by a straight line.
  • quadraticCurveTo(cp1x, cp1y, x, y)
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
  • rect(x, y, width, height)
// Line
context.beginPath();
context.moveTo(10, 10);
context.lineTo(100, 100);
context.stroke();

// Triangle
context.beginPath();
context.moveTo(50, 50);
context.lineTo(100, 100);
context.lineTo(50, 100);
context.fill();

// Circle
context.beginPath();
context.arc(100, 100, 50, 0, Math.PI * 2, true);
context.stroke();

Optionally, closePath() may be called to close the shape by drawing a straight line from the current point to the start. If the shape has already been closed or if there's only one point in the list, this function does nothing. Calling fill() will close any open shapes and closePath() is unnecessary. This is not the case with stroke().

Path2D

The Path2D object efficiently records and plays back drawings. All standard path methods are available on Path2D objects. Use stroke() or fill() to draw these objects onto the canvas.

const circle = new Path2D();
circle.moveTo(125, 35);
circle.arc(100, 35, 25, 0, 2 * Path.PI);
context.fill(circle);

The Path2D API also provides an addPath method. This method is useful when you want to build objects from several Path2D components.

Styles

Set the fillStyle and strokeStyle properties to change the fill and stroke colors, respectively. Use any CSS color.

context.fillStyle = 'red';
context.fillRect(100, 100, 100, 100);

Set transparency as part of the color or use the globalAlpha property. This value (between 0 and 1) applies a transparency value to all future shapes.

context.globalAlpha = 0.2;

Lines may be styled with several properties and functions: lineWidth, lineCap, lineJoin, miterLimit, setLineDash(segments)~/~getLineDash(), and lineDashOffset. See this page for more information.

Obtaining crisp lines requires understanding how paths are stroked. Note the situation in the second image below. The area to be filled only extends halfway into the pixels on either side of the path. Be precise to avoid rendering a blurry approximation.

canvas-crisp-lines.png

Shapes may be also filled and stoked with gradients and patterns. Use the createLinearGradient() and createRadialGradient() methods to create gradients. Then, use the addColorStop() on these objects to denote relative color positions. Give the createPattern() method an image to create a pattern. Gradients and patterns should be handed to the fillStyle property.

Control shadows with four properties: shadowOffsetX, shadowOffsetY, shadowBlur, and shadowColor. shadowColor is fully-transparent black by default.

Text

Two methods exist for writing text: fillText(text, x, y) and strokeText(text, x, y). Change the font and size using the font property.

context.font = '100px Helvetica';
context.fillText('Hi there', 100, 100);

Other useful properties include textAlign, textBaseline, and direction.

Images

To add an image to the canvas, first get a reference to HTMLImageElement. This may be done from scratch (see below) or with a call like document.getElementById(). Then, draw the image using the drawImage() function.

const image = new Image();
image.onload = function() {
    // Only be executed when the image has finished loading.
    context.drawImage(image, 0, 0);
}
image.src = 'example.png';

Note that drawImage() takes many optional parameters for scaling and slicing images.

State

Save and restore the state of the canvas with the save() and restore() methods, respectively. States are stored as a stack, each save() pushes, each restore() pops. The state consists of the transformations that have been applied and changes to style attributes.

Transformations

High-Level Transformations

The translate(x, y) method moves the canvas and its origin to a different point in the grid. x indicates the horizontal distance to move and y the vertical distance.

The rotate(angle) method rotates the canvas clockwise around the current origin by the angle number of radians. The center point is always the canvas origin, use the translate() method to move the canvas.

const width = 100;
const height = 100;

const x = 50;
const y = 50;

context.save();

// Translate to the rectangle center, rotate, then translate back.
context.translate(x + 0.5 * width, y + 0.5 * height);
context.rotate((Math.PI / 180) * 25);
context.translate(-(x + 0.5 * width), -(y + 0.5 * height));

context.fillRect(x, y, width, height);

context.restore();

Use the scale(x, y) method to increase or decrease the units in the grid. Both x and y are real numbers. Values smaller than 1.0 reduce the unit size and values above 1.0 increase the unit size.

Low-Level Transformations

The transform(), setTransform(), and resetTransform() methods provide raw manipulation of the transformation matrix. Rotation, translation, scaling, and skewing may all be accomplished using this matrix.

\begin{equation} \begin{bmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{bmatrix} \end{equation}

Transformations map coordinates from a one coordinate system into another.

\begin{equation} \begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = \begin{bmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \end{equation}

Translation, scaling, and rotation are equivalent to the following, respectively.

\begin{equation} \begin{bmatrix} 1 & 0 & tx \\ 0 & 1 & ty \\ 0 & 0 & 1 \end{bmatrix} , \begin{bmatrix} sx & 0 & 0 \\ 0 & sy & 0 \\ 0 & 0 & 1 \end{bmatrix} , \begin{bmatrix} cos(a) & -sin(a) & 0 \\ sin(a) & cos(a) & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{equation}

A skew transformation along the x-axis and y-axis is equivalent to the following, respectively.

\begin{equation} \begin{bmatrix} 1 & tan(a) & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} , \begin{bmatrix} 1 & 0 & 0 \\ tan(a) & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{equation}

The transform(a, b, c, d, e, f) method multiplies the current transformation matrix with the matrix described by its arguments. The setTransform(a, b, c, d, e, f) method resets the current transform to the identity matrix, and then invokes the transform() method with the same arguments. Lastly, the resetTransform() method resets the current transform to the identity matrix.

TODO Compositing and Clipping

TODO Size

Set the component's width and height with JavaScript.

canvas.width = window.innerWidth
canvas.height = window.innerHeight

TODO Do we also need CSS?

canvas {
    width: 100%;
    height: 100%;
}