How to Code a Christmas Tree in JavaScript

How to Code a Christmas Tree in JavaScript

Today we will be teaching you how to code this Binary Christmas Tree using pure HTML, CSS, and JavaScript.

First, create a new Codepen with HTML, CSS, and JavaScript files.

Insert this simple line of code on the HTML file:

<canvas id=”canvas”></canvas>

Then insert this code on the CSS file:

body {
margin:0;
height:100%;
}

This will ensure that your tree is the correct size.

Finally, add the JavaScript so that there is animation to the tree.

var CANVAS_WIDTH = window.innerWidth;
var CANVAS_HEIGHT = window.innerHeight;
var FPS = 60;
var TREE_HEIGHT = 15;
var TREE_Y_SPACING = 20;
var TREE_X_SPACING = 10;
var TREE_DECORATION_PERC = .25;
var TREE_DECORATION_SCALE = 1.8;
var TREE_STAR_MAX_SCALE = 1.5;
var TREE_STAR_MIN_SCALE = 1;
var TREE_STAR_SCALE_SPEED = .005;
var STAR_COUNT = 200;
var STAR_SCALE_MIN_SPEED = .0005;
var STAR_SCALE_MAX_SPEED = .01;
var STAR_SIZE = 3;

var BG_TOP = ‘#050528’;
var BG_BOTTOM = ‘#257eb4’;
var GREEN = ‘#119911’;
var YELLOW = ‘#ffff00’;
var DECORATION_1 = ‘#dd1111’;
var DECORATION_2 = ‘#1111dd’;
var DECORATION_3 = ‘#cccc00’;

var canvas;
var context;
var tree;
var stars = [];

init();

function init() {
canvas = document.getElementById(‘canvas’);

if (canvas && canvas.getContext) {
context = canvas.getContext(‘2d’);
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;

tree = new Tree(CANVAS_WIDTH / 2, 40);
for (var i = 0; i < STAR_COUNT; i++) {
stars[i] = new Star(Math.random()*CANVAS_WIDTH, Math.random()*CANVAS_HEIGHT);
}

setInterval(loop, 1000 / FPS);
}
}

function Tree(x, y) {
var node;
var starScale = 1;
var isStarGrowing = true;

initTree();

function initTree() {
node = new Node(undefined);
node.setColor(YELLOW);
var left = node;
var right = node;
for (var i = 0; i < TREE_HEIGHT; i++) {
left.setLeft(new Node(left));
right.setRight(new Node(right));
if (i !== 0) {
if (i % 2 === 0) {
var middle = left;
for (var j = 0; j < i; j++) {
if (i + j < TREE_HEIGHT – 1) {
middle.setRight(new Node(middle));
middle = middle.getRight();
middle.setLeft(new Node(middle));
}
}
} else {
var middle = right
for (var j = 0; j < i; j++) {
if (i + j < TREE_HEIGHT – 1) {
middle.setLeft(new Node(middle));
middle = middle.getLeft();
middle.setRight(new Node(middle));
}
}
}
}
left = left.getLeft();
right = right.getRight();
}
}

this.draw = function() {
node.draw(x, y);
drawStar(x, y, 20 * starScale, 5, .5);

if (isStarGrowing) {
starScale += TREE_STAR_SCALE_SPEED;
if (starScale > TREE_STAR_MAX_SCALE) {
starScale = TREE_STAR_MAX_SCALE;
isStarGrowing = false;
}
} else {
starScale -= TREE_STAR_SCALE_SPEED;
if (starScale < TREE_STAR_MIN_SCALE) {
starScale = TREE_STAR_MIN_SCALE;
isStarGrowing = true;
}
}
};
}

function Node(p) {
var parent, left, right;
var color = GREEN;
var scale = 1;

if (Math.random() < TREE_DECORATION_PERC) {
color = getDecorationColor();
scale = TREE_DECORATION_SCALE;
}

this.getParent = function() { return parent; };
this.getLeft = function() { return left; };
this.getRight = function() { return right; };
this.setLeft = function(l) { left = l; };
this.setRight = function(r) { right = r; };
this.setColor = function(c) { color = c; };
this.setScale = function(s) { scale = s; };

this.draw = function(x, y) {
if (left !== undefined) {
drawLine(x, y, x-TREE_X_SPACING, y+TREE_Y_SPACING, GREEN);
left.draw(x-TREE_X_SPACING, y+TREE_Y_SPACING);
}
if (right !== undefined) {
drawLine(x, y, x+TREE_X_SPACING, y+TREE_Y_SPACING, GREEN);
right.draw(x+TREE_X_SPACING, y+TREE_Y_SPACING);
}
context.beginPath();
context.fillStyle = color;
context.moveTo(x, y);
context.arc(x, y, 3*scale, 0, Math.PI*2, true);
context.fill();
};
}

function Star(x, y) {
var minScale = Math.random();
var maxScale = minScale + Math.random();
var scale = minScale + Math.random() * (maxScale – minScale);
var isGrowing = (Math.random() < .5);
var speed = STAR_SCALE_MIN_SPEED + Math.random() * (STAR_SCALE_MAX_SPEED – STAR_SCALE_MIN_SPEED);

this.draw = function() {
if (isGrowing) {
scale += speed;
isGrowing = (scale < maxScale);
} else {
scale -= speed;
isGrowing = (scale < minScale);
}
context.beginPath();
context.arc(x,y,STAR_SIZE*scale,0,Math.PI*2,true);
context.closePath();
gradient = context.createRadialGradient(x,y,0,x,y,STAR_SIZE*scale);
gradient.addColorStop(0.0, ‘rgba(255,255,255,1)’);
gradient.addColorStop(.3, ‘rgba(37,126,180,.6)’);
gradient.addColorStop(1.0, ‘rgba(37,126,180,0)’);
context.fillStyle = gradient;
context.fill();
}
}

function drawLine(x1, y1, x2, y2, color) {
context.beginPath();
context.strokeStyle = color;
context.lineWidth = 5;
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
}

// from http://programmingthomas.wordpress.com/2012/05/16/drawing-stars-with-html5-canvas/
function drawStar(x, y, r, p, m) {
context.save();
context.beginPath();
context.translate(x, y);
context.moveTo(0,0-r);
for (var i = 0; i < p; i++)
{
context.rotate(Math.PI / p);
context.lineTo(0, 0 – (r*m));
context.rotate(Math.PI / p);
context.lineTo(0, 0 – r);
}
context.fill();
context.restore();
}

function getDecorationColor() {
var value = Math.random();
if (value < .33) {
return DECORATION_1;
} else if (value < .66) {
return DECORATION_2;
} else {
return DECORATION_3;
}
}

function loop() {
//context.fillStyle = BG;
var grd = context.createLinearGradient(0,0,0,canvas.height);
grd.addColorStop(0,BG_TOP);
grd.addColorStop(1,BG_BOTTOM);
context.fillStyle=grd;
context.fillRect(0, 0, canvas.width, canvas.height);

for (var i = 0; i < STAR_COUNT; i++) {
stars[i].draw();
}

tree.draw();
}

Done!

If you enjoyed this post, read more on our Blog.