A Christmas-Themed Experiment - HTML5 Canvas Snowflakes

Inspired by Google's "Let it Snow" holiday surprise, I spent bit of time today writing a simple program in HTML5 to generate random fractal snowflake-like patterns using canvas and JavaScript. The idea behind it is very simple: fractal rotational symmetry. Code is below.

Click the button to generate a new one:

Please ensure your browser supports HTML5 Canvas element.
Download as PNG

And here is the source code.

var DEPTH = 5;
var MAX_FLAKES = 8;
var MIN_FLAKES = 2;

function SnowflakeGenerator(canvasElement) {
    this.element = canvasElement;
    this.width = parseInt(this.element.getAttribute("width"));
    this.height = parseInt(this.element.getAttribute("height"));
    this.randomParameters = [];
    for (i = 0; i <= DEPTH; i++) {
        this.randomParameters[i] = Math.floor(Math.random() * (MAX_FLAKES - MIN_FLAKES)) + MIN_FLAKES;
    }
    this.snowFlakes = [{
        x: 250,
        y: 250,
        r: 120,
        d: DEPTH,
        f: this.randomParameters[0]
    }];
}

SnowflakeGenerator.prototype.DrawFlake = function(context, flake) {
    context.save();
    context.translate(flake.x, flake.y);
    context.fillStyle = "rgba(0,191,255," + (1 - (1 / (flake.d + 4))).toString() + ")";
    context.fillRect(-1, -3, 2, 6);
    context.fillRect(-3, -1, 6, 2);
    var i = 0;
    if (flake.d > 0) {
        for (i = 0; i < flake.f; i++) {
            context.save();
            context.rotate(i * (Math.PI * 2) / flake.f);
            this.DrawFlake(context, {
                x: flake.r - 2,
                y: 0,
                r: flake.r / 2,
                d: flake.d - 1,
                f: this.randomParameters[flake.d]
            });
            context.restore();
        }
    }
    i = 0;
    context.restore();
};

SnowflakeGenerator.prototype.Draw = function(options) {
    startTime = new Date().getTime();
    context = this.element.getContext("2d");
    context.fillStyle = 'rgba(255,255,255, 0)';
    context.clearRect(0, 0, this.width, this.height);

    for (i in this.snowFlakes) {
        this.DrawFlake(context, this.snowFlakes[i]);
    }

    processingTime = new Date().getTime() - startTime;

    context.fillStyle = 'rgba(0,0,0,1)';
    context.font = '10px arial';
    line = 0;
    if (options.display.processingTime) {
        context.fillText("Time: " + processingTime + "ms", 10, line += 10);
    }
    if (options.display.parameters) {
        context.fillText(
            "Parameters: " + JSON.stringify(this.randomParameters), 10,
            line += 10);
    }
};

Comments