Frontend Development 14 min read

Drawing Fractals with HTML5 Canvas: Theory, Vector Mathematics, and Recursive Implementations

This article explains the mathematical foundations of fractals, demonstrates how to use Canvas coordinate transformations and vector operations, and provides complete JavaScript code for drawing classic fractals such as the Koch snowflake, hexagonal snowflake, and a binary tree using recursive algorithms.

ByteFE
ByteFE
ByteFE
Drawing Fractals with HTML5 Canvas: Theory, Vector Mathematics, and Recursive Implementations

Fractals are geometric shapes characterized by self‑similarity, originally studied by B. B. Mandelbrot. The article introduces fractal concepts and shows how to render typical fractal figures on an HTML5 Canvas.

Basic Mathematics – Canvas uses a coordinate system with the origin at the top‑left corner, x increasing to the right and y increasing downward. To draw a regular hexagon of side length 50 on a 300×300 canvas, the article explains the edge‑drawing sequence and the required rotations.

Rotation and Coordinate Mapping – The rotation matrix for clockwise and counter‑clockwise angles is presented, followed by a table of the corresponding matrix forms.

const clockwise = [cosβ, -sinβ, sinβ, cosβ];
const counterClockwise = [cosβ, sinβ, -sinβ, cosβ];

The JavaScript implementation of a hexagon drawing function uses these formulas:

var ctx = canvas.getContext("2d");
ctx.strikeStyle = "#000";
ctx.beginPath();
const y = 50;
ctx.moveTo(0, y);
hexagon(ctx, 0, y, 50, y, 0, 6);

The hexagon function receives parameters (ctx, x1, y1, x2, y2, n, m) and recursively draws the six sides, applying the rotation matrix at each step.

function hexagon(ctx, x1, y1, x2, y2, n, m) {
  ctx.clearRect(0, 0, 300, 300);
  // clockwise 60°
  ctx.moveTo(x2, y2);
  const x3 = x2 + (x2 - x1) * Math.cos(Math.PI / 3) + (y2 - y1) * Math.sin(Math.PI / 3);
  const y3 = y2 - (x2 - x1) * Math.sin(Math.PI / 3) + (y2 - y1) * Math.cos(Math.PI / 3);
  ctx.lineTo(x3, y3);
  // counter‑clockwise 120°
  const x4 = x3 + (x3 - x2) * Math.cos((Math.PI * 2) / 3) - (y3 - y2) * Math.sin((Math.PI * 2) / 3);
  const y4 = y3 + (y3 - y2) * Math.cos((Math.PI * 2) / 3) + (x3 - x2) * Math.sin((Math.PI * 2) / 3);
  ctx.lineTo(x4, y4);
  ctx.stroke();
  n++;
  if (n === m) return false; else hexagon(ctx, x3, y3, x4, y4, n, m);
}

Vector Operations – To simplify coordinate calculations, a Vector class extending Array is defined, providing methods for copying, addition, subtraction, scaling, dot product, cross product, and rotation.

class Vector extends Array {
  constructor(x = 1, y = 0) { super(x, y); }
  copy() { return new Vector(this.x, this.y); }
  add(v) { this.x += v.x; this.y += v.y; return this; }
  sub(v) { this.x -= v.x; this.y -= v.y; return this; }
  cross(v) { return this.x * v.y - v.x * this.y; }
  dot(v) { return this.x * v.x + this.y * v.y; }
  rotate(rad) {
    const c = Math.cos(rad), s = Math.sin(rad);
    const [x, y] = this;
    this.x = x * c - y * s;
    this.y = x * s + y * c;
    return this;
  }
}

Using vectors, the canvas coordinate system is flipped so that the y‑axis points upward:

var ctx = canvas.getContext("2d");
ctx.translate(0, canvas.height);
ctx.scale(1, -1);

Koch Snowflake – The algorithm starts from an equilateral triangle, divides each side into three parts, replaces the middle segment with two segments forming a protruding triangle, and recurses to a specified depth. The core recursive function is:

function koch(ctx, v1, v2, n, m) {
  ctx.clearRect(0, 0, 300, 300);
  const oneThird = v2.copy().sub(v1).scale(1/3);
  const v3 = oneThird.copy().add(v1);
  const v4 = oneThird.copy().scale(2).add(v1);
  const v5 = v4.copy().sub(v3).rotate((-60*Math.PI)/180).add(v3);
  n++;
  if (n === m) {
    ctx.moveTo(...v1);
    ctx.lineTo(...v3);
    ctx.lineTo(...v5);
    ctx.lineTo(...v4);
    ctx.lineTo(...v2);
    ctx.stroke();
    return false;
  }
  koch(ctx, v1, v3, n, m);
  koch(ctx, v3, v5, n, m);
  koch(ctx, v5, v4, n, m);
  koch(ctx, v4, v2, n, m);
}

Hexagonal Snowflake – Starting from a base hexagon, each edge is divided into thirds; a smaller hexagon is drawn on each segment recursively. The main recursive function uses vector rotation of 60° and -120° to compute new vertices.

function hexagon(ctx, v0, v1) {
  const hexagonLen = v1.copy().sub(v0).vlength;
  if (hexagonLen > minLine) {
    // recursion logic here
  }
}

Binary Tree – A simple recursive algorithm draws a binary tree by halving branch length and width at each level and rotating branches by fixed angles until a minimum length is reached. The article links to the full source code.

Conclusion – The tutorial demonstrates how Canvas coordinate transformations, vector mathematics, and recursion combine to simplify fractal drawing, reinforcing fundamental concepts useful for visualisation and graphics programming.

graphicsJavaScriptCanvasrecursionfractalsvector math
ByteFE
Written by

ByteFE

Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.