Improve performance of a HTML5 Canvas with particles bouncing around

To enhance the performance of HTML5 Canvas with particles bouncing around, several optimization techniques can dramatically improve frame rates and reduce CPU usage.

Key Performance Optimization Techniques

  • Separate the calculations from the drawing operations
  • Request a redraw only after updating calculations
  • Optimize collision detection by avoiding O(n²) comparisons
  • Reduce callback usage and function calls
  • Use inline calculations where possible
  • Implement object pooling for particles

Example: Optimized Particle System

<!DOCTYPE html>
<html>
<head>
    <title>Optimized Particles</title>
</head>
<body>
    <canvas id="canvas" width="800" height="600"></canvas>
    
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        
        // Particle pool to avoid garbage collection
        const particles = [];
        const particleCount = 100;
        
        // Initialize particles
        for (let i = 0; i < particleCount; i++) {
            particles.push({
                x: Math.random() * canvas.width,
                y: Math.random() * canvas.height,
                vx: (Math.random() - 0.5) * 4,
                vy: (Math.random() - 0.5) * 4,
                radius: 3
            });
        }
        
        function updateParticles() {
            // Separate calculation phase
            for (let i = 0; i < particles.length; i++) {
                const p = particles[i];
                
                // Update position (inline calculations)
                p.x += p.vx;
                p.y += p.vy;
                
                // Boundary collision (no function calls)
                if (p.x <= p.radius || p.x >= canvas.width - p.radius) {
                    p.vx = -p.vx;
                }
                if (p.y <= p.radius || p.y >= canvas.height - p.radius) {
                    p.vy = -p.vy;
                }
            }
        }
        
        function drawParticles() {
            // Clear canvas once
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // Batch drawing operations
            ctx.fillStyle = '#007acc';
            ctx.beginPath();
            
            for (let i = 0; i < particles.length; i++) {
                const p = particles[i];
                ctx.moveTo(p.x + p.radius, p.y);
                ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
            }
            
            ctx.fill();
        }
        
        function animate() {
            updateParticles();  // Calculate first
            drawParticles();    // Draw after calculations
            requestAnimationFrame(animate);
        }
        
        animate();
    </script>
</body>
</html>

Advanced Optimization: Spatial Partitioning

For collision detection between particles, use spatial partitioning instead of checking every particle against every other particle:

// Grid-based spatial partitioning
const gridSize = 50;
const grid = {};

function getGridKey(x, y) {
    return Math.floor(x / gridSize) + ',' + Math.floor(y / gridSize);
}

function updateCollisions() {
    // Clear grid
    for (let key in grid) {
        grid[key].length = 0;
    }
    
    // Assign particles to grid cells
    for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        const key = getGridKey(p.x, p.y);
        if (!grid[key]) grid[key] = [];
        grid[key].push(p);
    }
    
    // Check collisions only within same grid cell
    for (let key in grid) {
        const cellParticles = grid[key];
        for (let i = 0; i < cellParticles.length; i++) {
            for (let j = i + 1; j < cellParticles.length; j++) {
                // Collision detection logic here
            }
        }
    }
}

Performance Comparison

Technique Performance Gain Best For
Separate calculations/drawing 20-30% FPS increase All particle systems
Spatial partitioning 80-90% for collisions Systems with particle interactions
Object pooling Reduces garbage collection Dynamic particle creation

Additional Tips

  • Use integers: Integer calculations are faster than floating-point
  • Batch canvas operations: Group beginPath() and fill() calls
  • Limit particle count: Monitor frame rates and adjust particle count dynamically
  • Use Web Workers: Offload heavy calculations to background threads

Conclusion

Optimizing Canvas particle systems involves separating calculations from rendering, using spatial partitioning for collision detection, and minimizing function calls. These techniques can improve performance by 200-300% in complex particle systems.

Updated on: 2026-03-15T23:18:59+05:30

230 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements