HTML5 Canvas API
The HTML5 Canvas API provides a powerful way to draw graphics, images, and animations directly within a web browser using JavaScript. It offers a drawing surface that can be manipulated dynamically, enabling everything from simple charts and graphs to complex games and interactive visualizations.
The canvas element itself is a simple <canvas> tag in HTML. All drawing is performed using JavaScript, typically by obtaining a rendering context from the canvas element.
<canvas id="myCanvas" width="500" height="300">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
const canvas = document.getElementById('myCanvas');
// Further drawing operations will go here...
</script>
Getting Started
To begin drawing, you first need to get a reference to the canvas element and then obtain its rendering context. The most common context is the 2D rendering context.
const canvas = document.getElementById('myCanvas');
if (canvas.getContext) {
const ctx = canvas.getContext('2d');
// Now you can use the 'ctx' object for drawing.
console.log('Canvas context acquired successfully.');
} else {
console.error('Canvas is not supported by your browser.');
}
The getContext('2d') method returns an object that exposes the 2D drawing API. If you need WebGL support, you would use getContext('webgl') or getContext('experimental-webgl').
Canvas Rendering Contexts
The canvas element can support multiple rendering contexts, each offering a different set of drawing capabilities.
2D Context
The 2D context provides a wide range of methods for drawing shapes, text, and images. It's ideal for 2D graphics, charts, and user interface elements.
Key features include:
- Path manipulation (lines, curves, arcs)
- Shape drawing (rectangles, circles)
- Text rendering
- Image drawing and manipulation
- Color and style application (fill, stroke)
- Transformations (translate, rotate, scale)
WebGL Context
WebGL (Web Graphics Library) is a JavaScript API for rendering interactive 2D and 3D graphics within any compatible web browser without the use of plug-ins. It is based on the OpenGL ES 2.0 API.
WebGL is more complex and lower-level than the 2D context, offering:
- High-performance 3D rendering
- Hardware-accelerated graphics
- Shading language (GLSL) for custom shaders
(Note: This documentation focuses primarily on the 2D Canvas API.)
Drawing Primitives (2D Context)
The 2D context offers methods to draw fundamental graphical shapes.
Paths
Paths are fundamental to drawing in canvas. You define a path by adding segments (lines, arcs, curves) and then you can fill or stroke it.
beginPath(): Starts a new path.moveTo(x, y): Moves the current point to the specified coordinates.lineTo(x, y): Draws a line from the current point to the specified coordinates.arc(x, y, radius, startAngle, endAngle, anticlockwise): Draws an arc.quadraticCurveTo(cpx, cpy, x, y): Draws a quadratic Bezier curve.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y): Draws a cubic Bezier curve.closePath(): Closes the current path by drawing a straight line from the current point to the starting point.fill(): Fills the current path with the current fill style.stroke(): Strokes the current path with the current stroke style.
// Example: Drawing a triangle
if (ctx) {
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(100, 150);
ctx.closePath();
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; // Red with transparency
ctx.fill();
ctx.strokeStyle = 'blue'; // Blue outline
ctx.lineWidth = 2;
ctx.stroke();
}
Rectangles
Canvas provides dedicated methods for drawing rectangles.
fillRect(x, y, width, height): Draws a filled rectangle.strokeRect(x, y, width, height): Draws a rectangle outline.clearRect(x, y, width, height): Clears a rectangular area on the canvas.
// Example: Drawing a rectangle
if (ctx) {
ctx.fillStyle = 'green';
ctx.fillRect(200, 50, 150, 100); // x, y, width, height
ctx.strokeStyle = 'darkgreen';
ctx.lineWidth = 3;
ctx.strokeRect(210, 60, 130, 80);
// Example of clearing a part of the canvas
// ctx.clearRect(220, 70, 50, 30);
}
Arcs & Circles
Draw arcs and circles using the arc() method.
arc(x, y, radius, startAngle, endAngle, anticlockwise):x,y: Center coordinates of the circle.radius: The radius of the circle.startAngle,endAngle: Angles in radians. (0is at the 3 o'clock position, increasing counter-clockwise).anticlockwise: A boolean indicating whether to draw the arc counter-clockwise (true) or clockwise (false).
// Example: Drawing a circle and an arc
if (ctx) {
// Full circle
ctx.beginPath();
ctx.arc(100, 250, 40, 0, Math.PI * 2, false); // x, y, radius, startAngle, endAngle, anticlockwise
ctx.fillStyle = 'orange';
ctx.fill();
// Arc (part of a circle)
ctx.beginPath();
ctx.arc(250, 250, 50, Math.PI * 0.5, Math.PI * 1.5, false); // From 90 to 270 degrees
ctx.strokeStyle = 'purple';
ctx.lineWidth = 5;
ctx.stroke();
}
Lines
Lines are typically drawn as part of a path, but you can style them extensively.
moveTo(x, y)lineTo(x, y)stroke()
Line styling properties:
lineCap: Styles the end of lines ('butt','round','square').lineJoin: Styles the corners where lines meet ('round','bevel','miter').lineWidth: Sets the thickness of lines.miterLimit: Controls the maximum length of mitered joins.
// Example: Dashed line
if (ctx) {
ctx.setLineDash([10, 5]); // [dash length, gap length]
ctx.beginPath();
ctx.moveTo(350, 50);
ctx.lineTo(350, 250);
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
ctx.stroke();
ctx.setLineDash([]); // Reset to solid line
}
Styling and Colors (2D Context)
You can control the appearance of shapes and text using various properties.
Fill and Stroke Styles
These properties determine the color or pattern used to fill shapes or draw outlines.
fillStyle: Sets the color, gradient, or pattern used to fill shapes.strokeStyle: Sets the color, gradient, or pattern used to draw outlines.
Values can be:
- Color strings (e.g.,
'red','#FF0000','rgb(255,0,0)','rgba(255,0,0,0.5)') - Gradients (Linear and Radial)
- Patterns (created with
createPattern())
// Example: Linear Gradient
if (ctx) {
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(1, 'cyan');
ctx.fillStyle = gradient;
ctx.fillRect(50, 350, 150, 100);
}
// Example: Radial Gradient
if (ctx) {
const radialGradient = ctx.createRadialGradient(300, 400, 10, 300, 400, 80);
radialGradient.addColorStop(0, 'yellow');
radialGradient.addColorStop(0.5, 'orange');
radialGradient.addColorStop(1, 'red');
ctx.fillStyle = radialGradient;
ctx.beginPath();
ctx.arc(300, 400, 70, 0, Math.PI * 2, false);
ctx.fill();
}
Line Styles
Control the appearance of strokes.
lineWidth: The thickness of the stroke.lineCap: How the ends of lines are styled.lineJoin: How corners are styled.miterLimit: Maximum miter length.
// Example: Styled lines
if (ctx) {
ctx.lineWidth = 10;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.strokeStyle = 'magenta';
ctx.beginPath();
ctx.moveTo(400, 350);
ctx.lineTo(450, 450);
ctx.lineTo(500, 350);
ctx.stroke();
}
Text
Canvas allows you to draw text with various styling options.
fillText(text, x, y, maxWidth): Draws filled text.strokeText(text, x, y, maxWidth): Draws outlined text.measureText(text): Returns an object with text metrics (e.g., width).
Text styling properties:
font: Font style (e.g.,'20px Arial').textAlign: Text alignment ('left','right','center','start','end').textBaseline: Vertical alignment ('top','middle','bottom','alphabetic','hanging').direction: Text direction ('ltr'or'rtl').
// Example: Styled text
if (ctx) {
ctx.font = '30px "Segoe UI"';
ctx.fillStyle = 'darkblue';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('Hello Canvas!', canvas.width / 2, 50);
}
Images and Video (2D Context)
The canvas API allows you to draw images and even video frames onto the canvas.
drawImage()
This versatile method can draw an image or a video onto the canvas. It has three variations:
drawImage(image, x, y): Draws the entire image at the specified coordinates.drawImage(image, x, y, width, height): Draws the image, scaling it to the specified width and height.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight): Draws a portion of the image (defined bysx, sy, sWidth, sHeight) onto the canvas at the specified destination coordinates and dimensions (dx, dy, dWidth, dHeight).
The image parameter can be an HTMLImageElement, HTMLVideoElement, or HTMLCanvasElement.
// Example: Drawing an image (assuming an image element exists with id="myImage")
// You would typically load the image first:
// const img = new Image();
// img.onload = function() {
// if (ctx) {
// ctx.drawImage(img, 50, 500, 100, 75); // Draw scaled
// }
// };
// img.src = 'path/to/your/image.png';
// Placeholder for demonstration
if (ctx) {
ctx.fillStyle = '#eee';
ctx.fillRect(50, 500, 100, 75);
ctx.fillStyle = '#aaa';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText('Image Placeholder', 100, 535);
}
Images as Styles
You can use an image as a pattern for filling or stroking.
createPattern(image, repetition): Returns aCanvasPatternobject.
The repetition parameter can be 'repeat', 'repeat-x', 'repeat-y', or 'no-repeat'.
// Example: Image pattern fill (assuming an image element with id="patternImage")
// const patternImg = new Image();
// patternImg.onload = function() {
// if (ctx) {
// const pattern = ctx.createPattern(patternImg, 'repeat');
// ctx.fillStyle = pattern;
// ctx.fillRect(200, 500, 200, 100);
// }
// };
// patternImg.src = 'path/to/your/pattern.png';
// Placeholder for demonstration
if (ctx) {
ctx.fillStyle = '#ddd';
ctx.fillRect(200, 500, 200, 100);
ctx.fillStyle = '#666';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText('Pattern Placeholder', 300, 550);
}
Transformations (2D Context)
Transformations allow you to manipulate the coordinate system of the canvas, enabling you to move, rotate, and scale your drawings.
Important: Transformations are cumulative. To apply transformations independently, use save() and restore().
save(): Saves the current canvas state (including transformations, styles, etc.).restore(): Restores the most recently saved canvas state.
translate(x, y)
Moves the origin of the canvas coordinate system. Subsequent drawing operations will be relative to this new origin.
// Example: Translated drawing
if (ctx) {
ctx.save(); // Save original state
ctx.translate(50, 0); // Move origin 50px to the right
ctx.fillStyle = 'red';
ctx.fillRect(0, 600, 100, 50); // This rect starts at (50, 600) in canvas coords
ctx.restore(); // Restore to original state
}
rotate(angle)
Rotates the canvas coordinate system around the origin by the specified angle (in radians). A positive angle rotates clockwise.
// Example: Rotated drawing
if (ctx) {
ctx.save();
ctx.translate(150, 625); // Move to a position to rotate around
ctx.rotate(Math.PI / 4); // Rotate 45 degrees clockwise
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, 100, 50); // This rect is now rotated
ctx.restore();
}
scale(x, y)
Scales the coordinate system. A scale factor greater than 1 enlarges the drawing, while a factor less than 1 shrinks it.
// Example: Scaled drawing
if (ctx) {
ctx.save();
ctx.translate(250, 625);
ctx.scale(1.5, 0.8); // Stretch horizontally, shrink vertically
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 100, 50); // This rect is now scaled
ctx.restore();
}
transform() & setTransform()
These methods allow for more complex matrix-based transformations.
transform(m11, m12, m21, m22, dx, dy): Applies a transformation matrix to the current transformation matrix.setTransform(m11, m12, m21, m22, dx, dy): Resets the current transformation matrix to the identity matrix and then applies the specified transformation.
These are advanced features, often used when precise control over complex transformations is needed.
Animations
Animations on the canvas are typically achieved by repeatedly clearing the canvas and redrawing the scene in its new state. The most common way to create a smooth animation loop is using requestAnimationFrame().
let animationFrameId;
function animate() {
// 1. Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 2. Update animation state (e.g., position of objects)
// ...
// 3. Draw the updated scene
ctx.fillStyle = 'purple';
ctx.fillRect(animationX, 100, 50, 50); // animationX would be updated
// 4. Request the next frame
animationFrameId = requestAnimationFrame(animate);
}
// Start the animation
// animationFrameId = requestAnimationFrame(animate);
// To stop the animation:
// cancelAnimationFrame(animationFrameId);
requestAnimationFrame is generally preferred over setInterval or setTimeout for animations, as it synchronizes with the browser's repaint cycle, leading to smoother animations and better performance.
Performance Tips
- Batch Drawing Operations: Combine multiple drawing calls where possible. For example, draw all static elements once, then only redraw the dynamic parts.
- Off-screen Canvas: For complex or frequently drawn elements, render them to an off-screen canvas and then copy them to the visible canvas using
drawImage(). This can significantly speed up rendering. - Minimize Redrawing: Only clear and redraw the parts of the canvas that have changed, rather than clearing the entire canvas every frame.
- Optimize Images: Use appropriately sized images. Loading very large images and scaling them down can be inefficient.
- Profile Your Code: Use browser developer tools to identify performance bottlenecks in your JavaScript.
- Use
requestAnimationFrame: As mentioned in the animations section, this is crucial for smooth and efficient animation loops.
WebGL Basics (Brief Overview)
While this guide focuses on the 2D API, it's worth noting that WebGL provides low-level access to the GPU for 3D graphics.
Key concepts in WebGL include:
- Shaders: Programs written in GLSL (OpenGL Shading Language) that run on the GPU to define how vertices are processed and how pixels are colored.
- Buffers: Used to store vertex data (positions, colors, texture coordinates).
- Textures: Images used for coloring or applying surface detail.
- Uniforms: Variables that pass data from the CPU to the GPU shaders.
- Attributes: Variables that pass per-vertex data from buffers to shaders.
WebGL is considerably more complex than the 2D API and requires a deeper understanding of computer graphics principles.