Canvas vs SVG: Understanding the Difference
FeatureCanvasSVGTypeRaster (bitmap)VectorDOMSingle elementDOM-basedScalabilityFixed resolutionInfinitely scalableInteractivityManual event handlingBuilt-in DOM eventsPerformanceBetter for complex scenesBetter for simple graphicsSEO/AccessibilityRequires extra workNaturally accessible
HTML5 Canvas Fundamentals
Canvas provides a drawing surface for creating graphics programmatically using JavaScript.
Basic Canvas Setup
html
<canvas id="myCanvas" width="400" height="300">
    Your browser doesn't support Canvas.
</canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// Basic shapes
ctx.fillStyle = '#3498db';
ctx.fillRect(50, 50, 100, 75);
ctx.strokeStyle = '#e74c3c';
ctx.lineWidth = 3;
ctx.strokeRect(200, 50, 100, 75);
</script>
Drawing Shapes and Paths
html
<canvas id="shapesCanvas" width="500" height="300"></canvas>
<script>
const canvas = document.getElementById('shapesCanvas');
const ctx = canvas.getContext('2d');
// Circle
ctx.beginPath();
ctx.arc(100, 100, 50, 0, 2 * Math.PI);
ctx.fillStyle = '#9b59b6';
ctx.fill();
// Triangle
ctx.beginPath();
ctx.moveTo(250, 50);
ctx.lineTo(200, 150);
ctx.lineTo(300, 150);
ctx.closePath();
ctx.fillStyle = '#f39c12';
ctx.fill();
// Complex path
ctx.beginPath();
ctx.moveTo(400, 50);
ctx.quadraticCurveTo(450, 25, 400, 100);
ctx.lineTo(450, 100);
ctx.strokeStyle = '#27ae60';
ctx.lineWidth = 4;
ctx.stroke();
</script>
Working with Images and Text
html
<canvas id="contentCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('contentCanvas');
const ctx = canvas.getContext('2d');
// Text
ctx.font = '30px Arial';
ctx.fillStyle = '#2c3e50';
ctx.fillText('Canvas Text', 50, 50);
ctx.font = 'bold 24px Georgia';
ctx.strokeStyle = '#c0392b';
ctx.lineWidth = 1;
ctx.strokeText('Outlined Text', 50, 100);
// Image (when loaded)
const img = new Image();
img.onload = function() {
    ctx.drawImage(img, 300, 50, 200, 150);
    
    // Apply filter effect
    const imageData = ctx.getImageData(300, 50, 200, 150);
    const data = imageData.data;
    
    // Grayscale filter
    for (let i = 0; i < data.length; i += 4) {
        const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
        data[i] = avg;     // Red
        data[i + 1] = avg; // Green
        data[i + 2] = avg; // Blue
    }
    
    ctx.putImageData(imageData, 300, 220);
};
img.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgZmlsbD0iIzM0OThkYiIvPjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIyMCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGR5PSIuM2VtIj5TYW1wbGUgSW1hZ2U8L3RleHQ+PC9zdmc+';
</script>
Canvas Animation
html
<canvas id="animationCanvas" width="500" height="300"></canvas>
<button onclick="toggleAnimation()">Start/Stop Animation</button>
<script>
const canvas = document.getElementById('animationCanvas');
const ctx = canvas.getContext('2d');
let animationId;
let isAnimating = false;
class Ball {
    constructor(x, y, radius, color, velocityX, velocityY) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
        this.velocityX = velocityX;
        this.velocityY = velocityY;
    }
    
    draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
        ctx.fillStyle = this.color;
        ctx.fill();
    }
    
    update() {
        // Bounce off walls
        if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
            this.velocityX = -this.velocityX;
        }
        if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
            this.velocityY = -this.velocityY;
        }
        
        this.x += this.velocityX;
        this.y += this.velocityY;
    }
}
const balls = [
    new Ball(100, 100, 20, '#e74c3c', 2, 1.5),
    new Ball(200, 150, 15, '#3498db', -1.5, 2.5),
    new Ball(300, 100, 25, '#2ecc71', 1, -2)
];
function animate() {
    // Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // Update and draw balls
    balls.forEach(ball => {
        ball.update();
        ball.draw();
    });
    
    animationId = requestAnimationFrame(animate);
}
function toggleAnimation() {
    if (isAnimating) {
        cancelAnimationFrame(animationId);
        isAnimating = false;
    } else {
        animate();
        isAnimating = true;
    }
}
</script>
SVG Fundamentals
SVG (Scalable Vector Graphics) creates vector-based graphics using XML markup.
Basic SVG Structure
html
<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg">
    <!-- Rectangle -->
    <rect x="50" y="50" width="100" height="75" 
          fill="#3498db" stroke="#2980b9" stroke-width="2"/>
    
    <!-- Circle -->
    <circle cx="250" cy="100" r="40" 
            fill="#e74c3c" opacity="0.8"/>
    
    <!-- Line -->
    <line x1="50" y1="200" x2="350" y2="200" 
          stroke="#34495e" stroke-width="3"/>
    
    <!-- Polyline -->
    <polyline points="100,250 150,220 200,250 250,220 300,250" 
              fill="none" stroke="#9b59b6" stroke-width="2"/>
</svg>
Complex SVG Shapes and Paths
html
<svg width="500" height="400" xmlns="http://www.w3.org/2000/svg">
    <!-- Path with curves -->
    <path d="M 100 200 Q 150 100 200 200 T 300 200" 
          fill="none" stroke="#f39c12" stroke-width="3"/>
    
    <!-- Star shape -->
    <polygon points="250,50 270,90 310,90 280,120 290,160 250,140 210,160 220,120 190,90 230,90" 
             fill="#e67e22"/>
    
    <!-- Ellipse -->
    <ellipse cx="400" cy="300" rx="60" ry="40" 
             fill="#1abc9c" transform="rotate(45 400 300)"/>
    
    <!-- Text along path -->
    <defs>
        <path id="textPath" d="M 50 350 Q 250 300 450 350"/>
    </defs>
    <text font-family="Arial" font-size="16" fill="#2c3e50">
        <textPath href="#textPath">SVG text along a curved path!</textPath>
    </text>
</svg>
SVG Gradients and Filters
html
<svg width="500" height="300" xmlns="http://www.w3.org/2000/svg">
    <defs>
        <!-- Linear Gradient -->
        <linearGradient id="linearGrad" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" style="stop-color:#3498db;stop-opacity:1"/>
            <stop offset="100%" style="stop-color:#9b59b6;stop-opacity:1"/>
        </linearGradient>
        
        <!-- Radial Gradient -->
        <radialGradient id="radialGrad" cx="50%" cy="50%" r="50%">
            <stop offset="0%" style="stop-color:#f39c12;stop-opacity:1"/>
            <stop offset="100%" style="stop-color:#e74c3c;stop-opacity:1"/>
        </radialGradient>
        
        <!-- Drop Shadow Filter -->
        <filter id="dropshadow" x="-20%" y="-20%" width="140%" height="140%">
            <feDropShadow dx="3" dy="3" stdDeviation="2" flood-color="#000000" flood-opacity="0.3"/>
        </filter>
    </defs>
    
    <!-- Shapes using gradients and filters -->
    <rect x="50" y="50" width="150" height="100" fill="url(#linearGrad)" filter="url(#dropshadow)"/>
    <circle cx="350" cy="100" r="50" fill="url(#radialGrad)" filter="url(#dropshadow)"/>
</svg>
SVG Animations with CSS and SMIL
html
<svg width="500" height="300" xmlns="http://www.w3.org/2000/svg">
    <!-- CSS Animation -->
    <style>
        .rotating-rect {
            animation: rotate 3s linear infinite;
            transform-origin: 125px 100px;
        }
        
        @keyframes rotate {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }
        
        .pulsing-circle {
            animation: pulse 2s ease-in-out infinite alternate;
        }
        
        @keyframes pulse {
            from { r: 30px; }
            to { r: 50px; }
        }
    </style>
    
    <rect class="rotating-rect" x="50" y="50" width="150" height="100" 
          fill="#3498db" stroke="#2980b9" stroke-width="2"/>
    
    <circle class="pulsing-circle" cx="350" cy="100" r="30" fill="#e74c3c"/>
    
    <!-- SMIL Animation -->
    <circle cx="100" cy="200" r="20" fill="#2ecc71">
        <animateMotion dur="4s" repeatCount="indefinite">
            <path d="M 0 0 Q 150 -50 300 0 T 600 0"/>
        </animateMotion>
    </circle>
    
    <!-- Path animation -->
    <path d="M 50 250 Q 250 200 450 250" fill="none" stroke="#9b59b6" 
          stroke-width="3" stroke-dasharray="10,5">
        <animate attributeName="stroke-dashoffset" values="0;15" dur="1s" repeatCount="indefinite"/>
    </path>
</svg>
Interactive SVG with JavaScript
html
<svg id="interactive-svg" width="400" height="300" xmlns="http://www.w3.org/2000/svg">
    <rect class="draggable" x="50" y="50" width="80" height="60" 
          fill="#3498db" cursor="move"/>
    <circle class="clickable" cx="250" cy="100" r="40" 
            fill="#e74c3c" cursor="pointer"/>
    <text x="200" y="200" font-family="Arial" font-size="16" 
          text-anchor="middle" id="status-text">Click circle or drag rectangle</text>
</svg>
<script>
const svg = document.getElementById('interactive-svg');
const statusText = document.getElementById('status-text');
// Click event on circle
svg.querySelector('.clickable').addEventListener('click', function(e) {
    const colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6'];
    const randomColor = colors[Math.floor(Math.random() * colors.length)];
    this.setAttribute('fill', randomColor);
    statusText.textContent = `Circle clicked! New color: ${randomColor}`;
});
// Drag functionality for rectangle
let isDragging = false;
let startX, startY, elementX, elementY;
const draggableRect = svg.querySelector('.draggable');
draggableRect.addEventListener('mousedown', function(e) {
    isDragging = true;
    const rect = this.getBoundingClientRect();
    const svgRect = svg.getBoundingClientRect();
    
    startX = e.clientX - svgRect.left;
    startY = e.clientY - svgRect.top;
    elementX = parseFloat(this.getAttribute('x'));
    elementY = parseFloat(this.getAttribute('y'));
    
    statusText.textContent = 'Dragging rectangle...';
});
svg.addEventListener('mousemove', function(e) {
    if (!isDragging) return;
    
    const rect = this.getBoundingClientRect();
    const currentX = e.clientX - rect.left;
    const currentY = e.clientY - rect.top;
    
    const newX = elementX + (currentX - startX);
    const newY = elementY + (currentY - startY);
    
    draggableRect.setAttribute('x', newX);
    draggableRect.setAttribute('y', newY);
});
document.addEventListener('mouseup', function() {
    if (isDragging) {
        isDragging = false;
        statusText.textContent = 'Rectangle moved!';
    }
});
</script>
Canvas vs SVG: Practical Examples
When to Use Canvas
html
<!-- Particle System with Canvas -->
<canvas id="particles" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('particles');
const ctx = canvas.getContext('2d');
class Particle {
    constructor() {
        this.x = Math.random() * canvas.width;
        this.y = Math.random() * canvas.height;
        this.vx = (Math.random() - 0.5) * 2;
        this.vy = (Math.random() - 0.5) * 2;
        this.size = Math.random() * 3 + 1;
        this.opacity = Math.random();
    }
    
    update() {
        this.x += this.vx;
        this.y += this.vy;
        
        if (this.x < 0 || this.x > canvas.width) this.vx *= -1;
        if (this.y < 0 || this.y > canvas.height) this.vy *= -1;
    }
    
    draw() {
        ctx.save();
        ctx.globalAlpha = this.opacity;
        ctx.fillStyle = '#3498db';
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
    }
}
const particles = Array.from({ length: 100 }, () => new Particle());
function animateParticles() {
    ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    particles.forEach(particle => {
        particle.update();
        particle.draw();
    });
    
    requestAnimationFrame(animateParticles);
}
animateParticles();
</script>
When to Use SVG
html
<!-- Interactive Data Visualization with SVG -->
<svg id="chart" width="500" height="300" xmlns="http://www.w3.org/2000/svg">
    <style>
        .bar { cursor: pointer; transition: fill 0.3s ease; }
        .bar:hover { fill: #e74c3c !important; }
        .axis { stroke: #333; stroke-width: 2; }
        .label { font-family: Arial; font-size: 12px; fill: #333; }
    </style>
    
    <!-- Axes -->
    <line class="axis" x1="50" y1="250" x2="450" y2="250"/>
    <line class="axis" x1="50" y1="50" x2="50" y2="250"/>
    
    <!-- Data bars -->
    <rect class="bar" x="70" y="200" width="40" height="50" fill="#3498db" data-value="25"/>
    <rect class="bar" x="130" y="150" width="40" height="100" fill="#2ecc71" data-value="50"/>
    <rect class="bar" x="190" y="100" width="40" height="150" fill="#f39c12" data-value="75"/>
    <rect class="bar" x="250" y="120" width="40" height="130" fill="#9b59b6" data-value="65"/>
    <rect class="bar" x="310" y="180" width="40" height="70" fill="#e67e22" data-value="35"/>
    
    <!-- Labels -->
    <text class="label" x="90" y="270" text-anchor="middle">Q1</text>
    <text class="label" x="150" y="270" text-anchor="middle">Q2</text>
    <text class="label" x="210" y="270" text-anchor="middle">Q3</text>
    <text class="label" x="270" y="270" text-anchor="middle">Q4</text>
    <text class="label" x="330" y="270" text-anchor="middle">Q5</text>
    
    <text id="chart-info" class="label" x="250" y="30" text-anchor="middle" 
          font-size="14" font-weight="bold">Hover over bars for values</text>
</svg>
<script>
const bars = document.querySelectorAll('.bar');
const info = document.getElementById('chart-info');
bars.forEach(bar => {
    bar.addEventListener('mouseenter', function() {
        const value = this.getAttribute('data-value');
        const quarter = this.nextElementSibling.textContent;
        info.textContent = `${quarter}: ${value}%`;
    });
    
    bar.addEventListener('mouseleave', function() {
        info.textContent = 'Hover over bars for values';
    });
});
</script>
Performance Optimization Tips
Canvas Optimization
javascript
// Use requestAnimationFrame for smooth animations
function optimizedAnimation() {
    // Clear only dirty regions instead of entire canvas
    ctx.clearRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
    
    // Use off-screen canvas for complex operations
    const offscreenCanvas = document.createElement('canvas');
    const offCtx = offscreenCanvas.getContext('2d');
    
    // Batch operations
    ctx.save();
    // Multiple drawing operations
    ctx.restore();
    
    requestAnimationFrame(optimizedAnimation);
}
SVG Optimization
html
<!-- Minimize DOM manipulation -->
<svg>
    <defs>
        <!-- Reuse elements with <use> -->
        <g id="reusable-shape">
            <circle r="10" fill="#3498db"/>
        </g>
    </defs>
    
    <use href="#reusable-shape" x="50" y="50"/>
    <use href="#reusable-shape" x="100" y="100"/>
</svg>