Skip to content

Canvas and SVG: Deep Comparison and Application of HTML5 Graphics Drawing Technologies ​

Two Paths of Graphics Drawing ​

HTML5 provides Web developers with two powerful graphics drawing technologies: Canvas and SVG. Each has its own characteristics and is suitable for different application scenarios.

Core Differences ​

Canvas:

  • Pixel-based bitmap drawing
  • Draws pixel by pixel using JavaScript
  • Content cannot be directly modified after drawing (requires redrawing)
  • Excellent performance, suitable for dynamic, complex graphics

SVG (Scalable Vector Graphics):

  • XML-based vector graphics
  • Describes graphics using tags
  • Each graphic element is a DOM node that can be manipulated independently
  • Lossless scaling, suitable for graphics requiring interaction

You can think of it this way: Canvas is like a canvas where you paint with a brush; SVG is like building graphics with blocks, where each block can be moved and modified individually.

Canvas Basics ​

Creating a Canvas ​

html
<canvas id="myCanvas" width="800" height="600">
  Your browser does not support Canvas.
</canvas>

Note:

  • Use width and height attributes to set the canvas size (not CSS).
  • Setting dimensions via CSS will cause the graphics to stretch and distort.

Getting the Drawing Context ​

javascript
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d"); // Get 2D drawing context

// Check if browser supports Canvas
if (!ctx) {
  console.error("Browser does not support Canvas");
}

Basic Shape Drawing ​

1. Rectangle ​

javascript
const ctx = canvas.getContext("2d");

// Fill rectangle
ctx.fillStyle = "#3498db"; // Set fill color
ctx.fillRect(50, 50, 200, 100); // fillRect(x, y, width, height)

// Stroke rectangle
ctx.strokeStyle = "#e74c3c"; // Set border color
ctx.lineWidth = 5; // Set line width
ctx.strokeRect(300, 50, 200, 100);

// Clear rectangle area
ctx.clearRect(350, 75, 100, 50);

2. Path Drawing ​

Canvas uses paths to draw complex shapes:

javascript
// Draw triangle
ctx.beginPath(); // Start path
ctx.moveTo(100, 200); // Move to start point
ctx.lineTo(200, 200); // Draw line to second point
ctx.lineTo(150, 120); // Draw line to third point
ctx.closePath(); // Close path (return to start point)

ctx.fillStyle = "#2ecc71";
ctx.fill(); // Fill
ctx.strokeStyle = "#27ae60";
ctx.stroke(); // Stroke

3. Circles and Arcs ​

javascript
// Draw circle
ctx.beginPath();
ctx.arc(400, 300, 80, 0, 2 * Math.PI); // arc(x, y, radius, startAngle, endAngle)
ctx.fillStyle = "#9b59b6";
ctx.fill();

// Draw semi-circle
ctx.beginPath();
ctx.arc(600, 300, 80, 0, Math.PI); // 0 to ΀ is a semi-circle
ctx.strokeStyle = "#8e44ad";
ctx.lineWidth = 3;
ctx.stroke();

// Draw sector
ctx.beginPath();
ctx.moveTo(400, 500); // Center
ctx.arc(400, 500, 60, 0, Math.PI / 2); // 90 degree sector
ctx.lineTo(400, 500); // Return to center
ctx.closePath();
ctx.fillStyle = "#f39c12";
ctx.fill();

4. Bezier Curves ​

javascript
// Quadratic Bezier Curve
ctx.beginPath();
ctx.moveTo(100, 400);
ctx.quadraticCurveTo(200, 300, 300, 400); // Control point and end point
ctx.strokeStyle = "#e67e22";
ctx.lineWidth = 3;
ctx.stroke();

// Cubic Bezier Curve
ctx.beginPath();
ctx.moveTo(100, 500);
ctx.bezierCurveTo(150, 450, 250, 550, 300, 500); // Two control points and end point
ctx.strokeStyle = "#d35400";
ctx.lineWidth = 3;
ctx.stroke();

Text Drawing ​

javascript
// Fill text
ctx.font = "48px Arial"; // Set font
ctx.fillStyle = "#34495e";
ctx.fillText("Hello Canvas!", 100, 100); // fillText(text, x, y)

// Stroke text
ctx.font = "bold 36px Georgia";
ctx.strokeStyle = "#2c3e50";
ctx.lineWidth = 2;
ctx.strokeText("Outlined Text", 100, 200);

// Set text alignment
ctx.textAlign = "center"; // left, right, center, start, end
ctx.textBaseline = "middle"; // top, bottom, middle, alphabetic, hanging
ctx.fillText("Centered Text", canvas.width / 2, canvas.height / 2);

// Measure text width
const text = "Measure Me";
const metrics = ctx.measureText(text);
console.log(`Text width: ${metrics.width}px`);

Image Processing ​

javascript
// Load and draw image
const img = new Image();
img.onload = function () {
  // Draw original image
  ctx.drawImage(img, 0, 0);

  // Draw and scale
  ctx.drawImage(img, 200, 0, 150, 100); // drawImage(img, x, y, width, height)

  // Slice drawing
  ctx.drawImage(
    img,
    50,
    50,
    100,
    100, // Source image slice position and size
    400,
    0,
    200,
    200 // Target canvas position and size
  );
};
img.src = "photo.jpg";

Gradients and Patterns ​

javascript
// Linear Gradient
const linearGradient = ctx.createLinearGradient(0, 0, 200, 0);
linearGradient.addColorStop(0, "#e74c3c");
linearGradient.addColorStop(0.5, "#f39c12");
linearGradient.addColorStop(1, "#f1c40f");

ctx.fillStyle = linearGradient;
ctx.fillRect(50, 50, 200, 100);

// Radial Gradient
const radialGradient = ctx.createRadialGradient(400, 300, 20, 400, 300, 100);
radialGradient.addColorStop(0, "#3498db");
radialGradient.addColorStop(1, "#2c3e50");

ctx.fillStyle = radialGradient;
ctx.beginPath();
ctx.arc(400, 300, 100, 0, 2 * Math.PI);
ctx.fill();

// Pattern Fill
const patternImg = new Image();
patternImg.onload = function () {
  const pattern = ctx.createPattern(patternImg, "repeat"); // repeat, repeat-x, repeat-y, no-repeat
  ctx.fillStyle = pattern;
  ctx.fillRect(0, 400, 300, 150);
};
patternImg.src = "pattern.png";

Canvas Animation ​

javascript
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");

let x = 0;
let y = 100;
let dx = 2; // x velocity
let dy = 1; // y velocity
const radius = 20;

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

  // Draw ball
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, 2 * Math.PI);
  ctx.fillStyle = "#3498db";
  ctx.fill();
  ctx.closePath();

  // Boundary detection
  if (x + dx > canvas.width - radius || x + dx < radius) {
    dx = -dx; // Reverse
  }
  if (y + dy > canvas.height - radius || y + dy < radius) {
    dy = -dy;
  }

  // Update position
  x += dx;
  y += dy;

  // Loop animation
  requestAnimationFrame(draw);
}

draw();

SVG Basics ​

Creating SVG ​

SVG can be embedded directly in HTML:

html
<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg">
  <!-- SVG Content -->
</svg>

Or referenced as an independent file:

html
<img src="graphic.svg" alt="SVG Graphic" />
<object data="graphic.svg" type="image/svg+xml"></object>

Basic Shapes ​

1. Rectangle ​

html
<svg width="400" height="300">
  <!-- Rectangle -->
  <rect
    x="50"
    y="50"
    width="200"
    height="100"
    fill="#3498db"
    stroke="#2980b9"
    stroke-width="3"
  />

  <!-- Rounded Rectangle -->
  <rect
    x="300"
    y="50"
    width="150"
    height="100"
    rx="15"
    ry="15"
    fill="#e74c3c"
  />
</svg>

2. Circle and Ellipse ​

html
<svg width="400" height="300">
  <!-- Circle -->
  <circle cx="100" cy="100" r="50" fill="#2ecc71" />

  <!-- Ellipse -->
  <ellipse cx="300" cy="100" rx="80" ry="50" fill="#9b59b6" />
</svg>

3. Line and Polyline ​

html
<svg width="400" height="300">
  <!-- Line -->
  <line x1="50" y1="50" x2="200" y2="150" stroke="#34495e" stroke-width="3" />

  <!-- Polyline -->
  <polyline
    points="50,200 100,150 150,180 200,120 250,160"
    fill="none"
    stroke="#e67e22"
    stroke-width="2"
  />

  <!-- Polygon -->
  <polygon
    points="300,50 350,100 325,150 275,150 250,100"
    fill="#f39c12"
    stroke="#d35400"
    stroke-width="2"
  />
</svg>

4. Path ​

Path is the most powerful element in SVG:

html
<svg width="400" height="300">
  <!-- M = moveto, L = lineto, Z = closepath -->
  <path
    d="M 50 50 L 150 50 L 100 120 Z"
    fill="#3498db"
    stroke="#2980b9"
    stroke-width="2"
  />

  <!-- Curve: Q = Quadratic Bezier, C = Cubic Bezier -->
  <path
    d="M 200 50 Q 250 20 300 50"
    fill="none"
    stroke="#e74c3c"
    stroke-width="3"
  />

  <!-- Arc: A rx ry x-axis-rotation large-arc-flag sweep-flag x y -->
  <path
    d="M 50 200 A 50 50 0 0 1 150 200"
    fill="none"
    stroke="#2ecc71"
    stroke-width="3"
  />
</svg>

SVG Text ​

html
<svg width="400" height="200">
  <!-- Basic Text -->
  <text x="50" y="50" font-family="Arial" font-size="24" fill="#34495e">
    Hello SVG!
  </text>

  <!-- Text along Path -->
  <defs>
    <path id="textPath" d="M 50 100 Q 200 50 350 100" />
  </defs>

  <text font-size="18" fill="#e74c3c">
    <textPath href="#textPath">This is text along a path</textPath>
  </text>

  <!-- Multi-line Text -->
  <text x="50" y="150" font-size="16">
    <tspan x="50" dy="0">First Line</tspan>
    <tspan x="50" dy="20">Second Line</tspan>
    <tspan x="50" dy="20">Third Line</tspan>
  </text>
</svg>

SVG Gradients and Filters ​

html
<svg width="400" height="300">
  <defs>
    <!-- Linear Gradient -->
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:#e74c3c;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#f39c12;stop-opacity:1" />
    </linearGradient>

    <!-- Radial Gradient -->
    <radialGradient id="grad2">
      <stop offset="0%" style="stop-color:#3498db;stop-opacity:1" />
      <stop offset="100%" style="stop-color:#2c3e50;stop-opacity:1" />
    </radialGradient>

    <!-- Shadow Filter -->
    <filter id="shadow">
      <feGaussianBlur in="SourceAlpha" stdDeviation="3" />
      <feOffset dx="2" dy="2" result="offsetblur" />
      <feMerge>
        <feMergeNode />
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
  </defs>

  <rect x="50" y="50" width="150" height="100" fill="url(#grad1)" />
  <circle cx="300" cy="100" r="50" fill="url(#grad2)" />
  <text x="50" y="200" font-size="36" fill="#34495e" filter="url(#shadow)">
    Text with Shadow
  </text>
</svg>

SVG Animation ​

html
<svg width="400" height="300">
  <!-- Move Animation -->
  <circle cx="50" cy="100" r="20" fill="#3498db">
    <animate
      attributeName="cx"
      from="50"
      to="350"
      dur="3s"
      repeatCount="indefinite"
    />
  </circle>

  <!-- Color Change -->
  <rect x="50" y="150" width="100" height="60" fill="#e74c3c">
    <animate
      attributeName="fill"
      values="#e74c3c;#f39c12;#e74c3c"
      dur="2s"
      repeatCount="indefinite"
    />
  </rect>

  <!-- Path Animation -->
  <circle r="10" fill="#2ecc71">
    <animateMotion dur="4s" repeatCount="indefinite">
      <mpath href="#motionPath" />
    </animateMotion>
  </circle>

  <path
    id="motionPath"
    d="M 50 250 Q 200 200 350 250"
    fill="none"
    stroke="#ccc"
    stroke-width="2"
  />
</svg>

Manipulating SVG with JavaScript ​

html
<svg id="mySvg" width="400" height="300">
  <circle id="myCircle" cx="100" cy="100" r="50" fill="#3498db" />
</svg>

<button id="changeColor">Change Color</button>
<button id="moveCircle">Move Circle</button>

<script>
  const svg = document.getElementById("mySvg");
  const circle = document.getElementById("myCircle");

  // Change Color
  document.getElementById("changeColor").addEventListener("click", () => {
    const colors = ["#3498db", "#e74c3c", "#2ecc71", "#f39c12"];
    const randomColor = colors[Math.floor(Math.random() * colors.length)];
    circle.setAttribute("fill", randomColor);
  });

  // Move Circle
  document.getElementById("moveCircle").addEventListener("click", () => {
    const newX = Math.random() * (400 - 100) + 50;
    const newY = Math.random() * (300 - 100) + 50;
    circle.setAttribute("cx", newX);
    circle.setAttribute("cy", newY);
  });

  // Dynamically Create SVG Element
  function addRectangle() {
    const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    rect.setAttribute("x", Math.random() * 300);
    rect.setAttribute("y", Math.random() * 200);
    rect.setAttribute("width", 80);
    rect.setAttribute("height", 50);
    rect.setAttribute("fill", "#9b59b6");
    svg.appendChild(rect);
  }

  addRectangle();
</script>

Canvas vs SVG: How to Choose? ​

Performance Comparison ​

FeatureCanvasSVG
RenderingPixel-based (Bitmap)Object-based (Vector)
DOM ManipulationNo DOM nodes, high performanceEach element is a DOM node
Element CountSuitable for large number of elements (Games)Too many elements affect performance
ScalingDistorts (Pixelated)Lossless scaling
Event HandlingRequires manual coordinate calculationElements support native events
Memory UsageFixed (depends on canvas size)Increases with element count

Applicable Scenarios ​

Choose Canvas:

✅ Game development (requires high frame rate animation)
✅ Real-time data visualization (large number of data points)
✅ Image processing (filters, pixel manipulation)
✅ Video frame processing
✅ Complex particle systems

Choose SVG:

✅ Icons, Logos (require scaling)
✅ Charts (require interaction)
✅ Map applications
✅ Graphics content requiring SEO
✅ High-quality graphics for printing
✅ Few but interaction-rich elements

Practical Example Comparison ​

Canvas Implementation of Bar Chart:

javascript
const canvas = document.getElementById("chart");
const ctx = canvas.getContext("2d");

const data = [30, 80, 45, 60, 95];
const barWidth = 50;
const barGap = 20;

data.forEach((value, index) => {
  const x = index * (barWidth + barGap) + 50;
  const y = canvas.height - value - 50;
  const height = value;

  ctx.fillStyle = "#3498db";
  ctx.fillRect(x, y, barWidth, height);

  // Draw value
  ctx.fillStyle = "#000";
  ctx.font = "14px Arial";
  ctx.textAlign = "center";
  ctx.fillText(value, x + barWidth / 2, y - 5);
});

SVG Implementation of Bar Chart:

html
<svg width="400" height="300">
  <g id="chart"></g>
</svg>

<script>
  const svg = document.getElementById("chart");
  const data = [30, 80, 45, 60, 95];
  const barWidth = 50;
  const barGap = 20;

  data.forEach((value, index) => {
    const x = index * (barWidth + barGap) + 50;
    const y = 250 - value;

    // Create rectangle
    const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    rect.setAttribute("x", x);
    rect.setAttribute("y", y);
    rect.setAttribute("width", barWidth);
    rect.setAttribute("height", value);
    rect.setAttribute("fill", "#3498db");

    // Add interaction
    rect.addEventListener("mouseover", function () {
      this.setAttribute("fill", "#e74c3c");
    });
    rect.addEventListener("mouseout", function () {
      this.setAttribute("fill", "#3498db");
    });

    svg.appendChild(rect);

    // Add text
    const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.setAttribute("x", x + barWidth / 2);
    text.setAttribute("y", y - 5);
    text.setAttribute("text-anchor", "middle");
    text.textContent = value;
    svg.appendChild(text);
  });
</script>

Best Practices ​

Canvas Optimization ​

javascript
// 1. Avoid unnecessary state changes
ctx.fillStyle = "#3498db";
for (let i = 0; i < 1000; i++) {
  ctx.fillRect(x[i], y[i], 10, 10); // Batch draw similar graphics
}

// 2. Use Offscreen Canvas
const offscreenCanvas = document.createElement("canvas");
const offscreenCtx = offscreenCanvas.getContext("2d");
// Draw complex graphics on offscreen canvas
offscreenCtx.drawComplexGraphic();
// Draw to main canvas at once
ctx.drawImage(offscreenCanvas, 0, 0);

// 3. Reduce redraw area
// Only clear the area that needs updating
ctx.clearRect(x, y, width, height);

SVG Optimization ​

html
<!-- 1. Reuse elements -->
<svg>
  <defs>
    <circle id="dot" r="5" fill="#3498db" />
  </defs>

  <use href="#dot" x="50" y="50" />
  <use href="#dot" x="100" y="100" />
  <use href="#dot" x="150" y="150" />
</svg>

<!-- 2. Use CSS Animation instead of SMIL -->
<style>
  .animated-circle {
    animation: move 3s infinite;
  }

  @keyframes move {
    from {
      transform: translateX(0);
    }
    to {
      transform: translateX(300px);
    }
  }
</style>

<svg>
  <circle class="animated-circle" cx="50" cy="100" r="20" fill="#3498db" />
</svg>

Summary ​

Canvas and SVG are two powerful graphics technologies provided by HTML5:

Canvas:

  • High performance, suitable for dynamic, complex graphics.
  • Pixel-level control, suitable for games and image processing.
  • Requires more JavaScript code.

SVG:

  • Vector graphics, lossless scaling.
  • DOM elements, easy to interact with and manipulate.
  • Suitable for graphics that are few in number but require scaling or interaction.