Docs

19.7-Canvas-WebGL-Basics

19.7 Canvas and WebGL Basics

Overview

The HTML Canvas API provides a way to draw graphics using JavaScript. The 2D context offers simple drawing operations, while WebGL enables hardware-accelerated 3D graphics.

Learning Objectives

  • Understand Canvas 2D drawing fundamentals
  • Draw shapes, paths, and text
  • Work with images and transformations
  • Introduction to WebGL concepts
  • Basic animation techniques

Canvas Setup

<canvas id="canvas" width="800" height="600"></canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Set canvas size (accounting for device pixel ratio)
function setupCanvas(canvas) {
  const dpr = window.devicePixelRatio || 1;
  const rect = canvas.getBoundingClientRect();

  canvas.width = rect.width * dpr;
  canvas.height = rect.height * dpr;

  ctx.scale(dpr, dpr);

  return ctx;
}

Basic Shapes

Rectangles

// Filled rectangle
ctx.fillStyle = 'blue';
ctx.fillRect(10, 10, 100, 50);

// Stroked rectangle
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.strokeRect(10, 70, 100, 50);

// Clear rectangle
ctx.clearRect(20, 20, 80, 30);

Paths

// Triangle
ctx.beginPath();
ctx.moveTo(75, 50);
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.closePath();
ctx.fill();

// Line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(200, 100);
ctx.stroke();

Circles and Arcs

// Full circle
ctx.beginPath();
ctx.arc(75, 75, 50, 0, Math.PI * 2);
ctx.fill();

// Semi-circle
ctx.beginPath();
ctx.arc(200, 75, 50, 0, Math.PI);
ctx.stroke();

// Arc segment
ctx.beginPath();
ctx.arc(300, 75, 50, 0, Math.PI / 2);
ctx.lineTo(300, 75);
ctx.closePath();
ctx.fill();

Curves

Quadratic Curves

ctx.beginPath();
ctx.moveTo(50, 200);
ctx.quadraticCurveTo(200, 100, 350, 200); // (cpX, cpY, endX, endY)
ctx.stroke();

Bezier Curves

ctx.beginPath();
ctx.moveTo(50, 200);
ctx.bezierCurveTo(100, 100, 300, 100, 350, 200); // (cp1X, cp1Y, cp2X, cp2Y, endX, endY)
ctx.stroke();

Styling

Colors and Gradients

// Solid color
ctx.fillStyle = '#FF5733';
ctx.fillStyle = 'rgba(255, 87, 51, 0.5)';

// Linear gradient
const linearGradient = ctx.createLinearGradient(0, 0, 200, 0);
linearGradient.addColorStop(0, 'red');
linearGradient.addColorStop(0.5, 'yellow');
linearGradient.addColorStop(1, 'blue');
ctx.fillStyle = linearGradient;
ctx.fillRect(0, 0, 200, 100);

// Radial gradient
const radialGradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 75);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(1, 'black');
ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, 150, 150);

Line Styles

ctx.lineWidth = 5;
ctx.lineCap = 'round'; // 'butt', 'round', 'square'
ctx.lineJoin = 'round'; // 'round', 'bevel', 'miter'
ctx.setLineDash([5, 10]); // Dashed line pattern

Text

// Set font
ctx.font = '48px serif';
ctx.textAlign = 'center'; // 'left', 'right', 'center'
ctx.textBaseline = 'middle'; // 'top', 'bottom', 'middle'

// Fill text
ctx.fillStyle = 'black';
ctx.fillText('Hello Canvas', 200, 100);

// Stroke text
ctx.strokeStyle = 'blue';
ctx.strokeText('Hello Canvas', 200, 150);

// Measure text
const metrics = ctx.measureText('Hello');
console.log(metrics.width);

Images

// Draw image
const img = new Image();
img.onload = () => {
  ctx.drawImage(img, 0, 0); // Original size
  ctx.drawImage(img, 0, 0, 200, 100); // Scaled
  ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); // Crop and scale
};
img.src = 'image.png';

// Draw from video
const video = document.querySelector('video');
ctx.drawImage(video, 0, 0);

Transformations

// Save current state
ctx.save();

// Translate (move origin)
ctx.translate(100, 100);

// Rotate (in radians)
ctx.rotate(Math.PI / 4); // 45 degrees

// Scale
ctx.scale(2, 2);

// Reset or restore
ctx.restore();

// Combined transformations
ctx.setTransform(1, 0, 0, 1, 0, 0); // Reset
ctx.transform(a, b, c, d, e, f); // Multiply current matrix

Animation

function animate() {
  // Clear canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // Update positions
  x += velocityX;
  y += velocityY;

  // Draw
  ctx.fillRect(x, y, 50, 50);

  // Request next frame
  requestAnimationFrame(animate);
}

animate();

Compositing and Clipping

// Global alpha
ctx.globalAlpha = 0.5;

// Composite operations
ctx.globalCompositeOperation = 'source-over'; // Default
// Other: 'multiply', 'screen', 'overlay', 'difference', etc.

// Clipping
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.clip();
// All subsequent drawing is clipped to this circle

WebGL Basics

const gl = canvas.getContext('webgl');

// Check support
if (!gl) {
  console.error('WebGL not supported');
}

// Set clear color
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

// Vertex shader source
const vertexShaderSource = `
    attribute vec4 a_position;
    void main() {
        gl_Position = a_position;
    }
`;

// Fragment shader source
const fragmentShaderSource = `
    precision mediump float;
    uniform vec4 u_color;
    void main() {
        gl_FragColor = u_color;
    }
`;

// Create shader
function createShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.error(gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
    return null;
  }

  return shader;
}

// Create program
function createProgram(gl, vertexShader, fragmentShader) {
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
    return null;
  }

  return program;
}

Best Practices

  1. Use requestAnimationFrame - For smooth animations
  2. Minimize state changes - Batch similar operations
  3. Use offscreen canvas - For complex pre-rendering
  4. Handle high DPI - Scale for device pixel ratio
  5. Clean up resources - Remove event listeners, cancel animations

Summary

Feature2D CanvasWebGL
ComplexitySimpleComplex
PerformanceGoodExcellent
Use Case2D graphics, UI3D graphics, games
GPU UsageMinimalHeavy

Resources

.7 Canvas WebGL Basics - JavaScript Tutorial | DeepML