HTML Canvas

Explore HTML5 Canvas for creating dynamic graphics, animations, data visualizations, and interactive digital art using JavaScript.

Introduction to HTML5 Canvas

The HTML5 <canvas> element provides a powerful drawing surface for creating dynamic graphics, animations, games, and data visualizations directly in the browser. Unlike static images, canvas content is generated programmatically using JavaScript, enabling interactive and responsive graphics.

Canvas operates as a bitmap that can be manipulated pixel by pixel, making it ideal for complex graphics operations, image processing, and real-time visual effects that would be impossible with traditional HTML and CSS alone.

🎨 Key Concept

Canvas is like a digital drawing board that JavaScript can paint on, creating everything from simple shapes to complex interactive graphics and animations.

Canvas Element Basics

Setting up and accessing the canvas drawing context:

<!-- HTML Canvas element -->
<canvas 
    id="myCanvas" 
    width="600" 
    height="400"
    style="border: 1px solid #ccc;">
    Your browser does not support the HTML5 Canvas element.
</canvas>

<script>
    // Get canvas element and 2D rendering context
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Check if Canvas is supported
    if (ctx) {
        // Canvas is supported, start drawing
        ctx.fillStyle = '#007bff';
        ctx.fillRect(50, 50, 200, 100);
    } else {
        // Canvas not supported
        console.log('Canvas is not supported');
    }
</script>
Canvas Setup Considerations:
  • Set width and height attributes in HTML, not CSS
  • CSS sizing stretches the canvas like an image
  • Always provide fallback content for unsupported browsers
  • Use getContext('2d') for 2D graphics
  • Check context availability before drawing

Drawing Shapes and Paths

<canvas id="shapes" width="500" height="400"></canvas>

<script>
    const canvas = document.getElementById('shapes');
    const ctx = canvas.getContext('2d');
    
    // Rectangle methods
    ctx.fillStyle = '#ff6b6b';
    ctx.fillRect(20, 20, 100, 80); // Filled rectangle
    
    ctx.strokeStyle = '#4ecdc4';
    ctx.lineWidth = 3;
    ctx.strokeRect(140, 20, 100, 80); // Rectangle outline
    
    ctx.clearRect(260, 20, 100, 80); // Clear rectangle area
    
    // Drawing paths
    ctx.beginPath();
    ctx.moveTo(50, 150); // Start point
    ctx.lineTo(150, 150); // Line to
    ctx.lineTo(100, 200); // Line to
    ctx.closePath(); // Close path
    ctx.fillStyle = '#45b7d1';
    ctx.fill(); // Fill the triangle
    
    // Circles and arcs
    ctx.beginPath();
    ctx.arc(300, 175, 40, 0, 2 * Math.PI); // Full circle
    ctx.fillStyle = '#f7b731';
    ctx.fill();
    ctx.strokeStyle = '#333';
    ctx.stroke();
    
    // Arc (partial circle)
    ctx.beginPath();
    ctx.arc(400, 175, 30, 0, Math.PI); // Half circle
    ctx.fillStyle = '#5f27cd';
    ctx.fill();
    
    // Bezier curves
    ctx.beginPath();
    ctx.moveTo(50, 270);
    ctx.quadraticCurveTo(100, 220, 150, 270); // Quadratic curve
    ctx.strokeStyle = '#ff9ff3';
    ctx.lineWidth = 4;
    ctx.stroke();
    
    // Cubic Bezier curve
    ctx.beginPath();
    ctx.moveTo(200, 270);
    ctx.bezierCurveTo(220, 220, 280, 220, 300, 270);
    ctx.strokeStyle = '#54a0ff';
    ctx.stroke();
</script>

Text and Styling

<canvas id="text" width="600" height="300"></canvas>

<script>
    const canvas = document.getElementById('text');
    const ctx = canvas.getContext('2d');
    
    // Text styling
    ctx.font = '30px Arial';
    ctx.fillStyle = '#333';
    ctx.textAlign = 'center'; // left, right, center, start, end
    ctx.textBaseline = 'middle'; // top, bottom, middle, alphabetic
    
    // Filled text
    ctx.fillText('HTML5 Canvas', 300, 60);
    
    // Outlined text
    ctx.strokeStyle = '#007bff';
    ctx.lineWidth = 2;
    ctx.strokeText('Outlined Text', 300, 120);
    
    // Combined fill and stroke
    ctx.fillStyle = '#ff6b6b';
    ctx.fillText('Combined Style', 300, 180);
    ctx.strokeText('Combined Style', 300, 180);
    
    // Measure text dimensions
    const textMetrics = ctx.measureText('Measured Text');
    console.log('Text width:', textMetrics.width);
    
    // Gradients and patterns
    const gradient = ctx.createLinearGradient(200, 240, 400, 240);
    gradient.addColorStop(0, '#ff6b6b');
    gradient.addColorStop(0.5, '#4ecdc4');
    gradient.addColorStop(1, '#45b7d1');
    
    ctx.fillStyle = gradient;
    ctx.font = '25px bold Arial';
    ctx.fillText('Gradient Text', 300, 240);
</script>

Images and Transformations

<canvas id="images" width="600" height="400"></canvas>
<img id="sourceImage" src="logo.png" style="display: none;">

<script>
    const canvas = document.getElementById('images');
    const ctx = canvas.getContext('2d');
    const img = document.getElementById('sourceImage');
    
    img.onload = function() {
        // Draw image at original size
        ctx.drawImage(img, 50, 50);
        
        // Draw image with custom size
        ctx.drawImage(img, 200, 50, 100, 80);
        
        // Draw part of image (source clipping)
        ctx.drawImage(
            img, 
            0, 0, 50, 50, // source rectangle
            350, 50, 100, 100 // destination rectangle
        );
        
        // Transformations
        ctx.save(); // Save current state
        
        // Translation
        ctx.translate(150, 200);
        ctx.fillStyle = '#ff6b6b';
        ctx.fillRect(0, 0, 50, 50);
        
        // Rotation (around translated origin)
        ctx.rotate(Math.PI / 4); // 45 degrees
        ctx.fillStyle = '#4ecdc4';
        ctx.fillRect(60, 0, 50, 50);
        
        // Scale
        ctx.scale(1.5, 0.5); // Width 1.5x, height 0.5x
        ctx.fillStyle = '#45b7d1';
        ctx.fillRect(80, 20, 50, 50);
        
        ctx.restore(); // Restore previous state
        
        // Matrix transformation
        ctx.setTransform(1, 0.2, 0.3, 1, 400, 200);
        ctx.fillStyle = '#f7b731';
        ctx.fillRect(0, 0, 80, 60);
        
        // Reset transformation
        ctx.setTransform(1, 0, 0, 1, 0, 0);
    };
</script>

Animation Example

<canvas id="animation" width="600" height="300"></canvas>
<button onclick="startAnimation()">Start Animation</button>
<button onclick="stopAnimation()">Stop Animation</button>

<script>
    const canvas = document.getElementById('animation');
    const ctx = canvas.getContext('2d');
    
    let animationId;
    let balls = [];
    
    // Ball object constructor
    function Ball(x, y, dx, dy, radius, color) {
        this.x = x;
        this.y = y;
        this.dx = dx; // velocity x
        this.dy = dy; // velocity y
        this.radius = radius;
        this.color = color;
        
        this.draw = function() {
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
            ctx.fillStyle = this.color;
            ctx.fill();
        };
        
        this.update = function() {
            // Bounce off walls
            if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
                this.dx = -this.dx;
            }
            if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
                this.dy = -this.dy;
            }
            
            // Update position
            this.x += this.dx;
            this.y += this.dy;
            
            this.draw();
        };
    }
    
    // Create balls
    function initBalls() {
        balls = [];
        const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f7b731', '#5f27cd'];
        
        for (let i = 0; i < 5; i++) {
            const radius = Math.random() * 20 + 10;
            const x = Math.random() * (canvas.width - radius * 2) + radius;
            const y = Math.random() * (canvas.height - radius * 2) + radius;
            const dx = (Math.random() - 0.5) * 4;
            const dy = (Math.random() - 0.5) * 4;
            const color = colors[Math.floor(Math.random() * colors.length)];
            
            balls.push(new Ball(x, y, dx, dy, radius, color));
        }
    }
    
    // Animation loop
    function animate() {
        // Clear canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        
        // Update and draw balls
        balls.forEach(ball => ball.update());
        
        // Continue animation
        animationId = requestAnimationFrame(animate);
    }
    
    function startAnimation() {
        initBalls();
        animate();
    }
    
    function stopAnimation() {
        cancelAnimationFrame(animationId);
    }
</script>

Canvas Applications

Graphics & Art

  • Digital painting applications
  • Interactive drawing tools
  • Image filters and effects
  • Photo editing interfaces
  • Generative art and patterns

Data Visualization

  • Custom charts and graphs
  • Interactive dashboards
  • Real-time data displays
  • Network diagrams
  • Scientific visualizations

Games & Animation

  • 2D games and sprites
  • Particle systems
  • Physics simulations
  • Interactive animations
  • Game UI elements

Utilities & Tools

  • Image processing
  • QR code generators
  • Digital signatures
  • Color pickers
  • Drawing tablets integration

Best Practices

✅ Do

  • Set canvas size in HTML attributes
  • Use requestAnimationFrame for smooth animations
  • Save and restore context state when needed
  • Optimize drawing operations for performance
  • Provide fallback content for accessibility
  • Use off-screen canvas for complex compositions

❌ Avoid

  • Excessive redrawing in animations
  • Drawing outside the canvas bounds
  • Ignoring high-DPI display scaling
  • Complex operations in animation loops
  • Memory leaks from event listeners
  • Blocking the main thread with heavy operations