How to Create Fractal Trees Using JavaScript

  Programming

Did you know that trees–I’m talking about the ones you find in a jungle, not those that are in an algorithms book–too behave like fractals? If you step out of your room and take a close look at any old tree in your garden or neighborhood, you’ll notice that most of its branches are quite similar to each other. They might not be exactly like one another, but they definitely share patterns. In this tutorial, I show you how to procedurally generate trees using JavaScript.

Fractal trees, although not as well known as other types of fractals, are definitely interesting. If you are familiar with recursion, creating them is easy and intuitive.

In this tutorial, I’ll assume that you already have access to an HTML5 canvas, and its 2D context. If you don’t know how to create and initialize a canvas, I suggest you read my previous tutorial.

The Algorithm

Here’s the essence of the algorithm we’ll be using to generate our fractal trees:

Step 1: If a branch is long enough, attach two branches to it: one on the left, and one on the right. Both the new branches should be slightly shorter than their parent branch.

Step 2: Repeat Step 1 for both the new branches

We will, of course, start with a long branch, which will serve as the trunk of the tree.

Creating the Recursive Function

Create a new function called draw(). It should take four arguments:

  • The starting X-coordinate of a branch
  • The starting Y-coordinate of the branch
  • The length of the branch
  • The angle of the branch

It should look like this:

function draw(startX, startY, len, angle) {
    // All code goes here
}

To draw the branches, we’ll be using paths. The paths, however, will always be straight, vertical lines. To be able to draw them at the required angle, we’ll be rotating the canvas itself using the rotate() method. Of course, we’ll also have to save and restore the state of the canvas at appropriate times.

Once the branch is drawn, we call the draw() function twice, once for the left branch and once for the right branch.

Here’s the code for doing all that:

function draw(startX, startY, len, angle) {
  ctx.beginPath();
  ctx.save();
  
  ctx.translate(startX, startY);
  ctx.rotate(angle * Math.PI/180);
  ctx.moveTo(0, 0);
  ctx.lineTo(0, -len);
  ctx.stroke();
  
  if(len < 10) {
    ctx.restore();
    return;
  }
  
  draw(0, -len, len*0.8, -15);
  draw(0, -len, len*0.8, 15);
  
  ctx.restore();
}

At this point, you can add a call to the draw() function to actually draw the tree.

draw(350,600,120,0);

Note that the first two arguments are where the tree’s trunk should start. The third argument is the length of the trunk, and the last argument is zero because the trunk should be straight.

If you run the above code, you should see a tree that looks like this:

Fractal tree, simple

It isn’t very impressive, but our function is working the way it should. All it needs now is a few tweaks!

Tweak 1: Branch Thickness

All branches of a real tree don’t have the same thickness. They tend to get thinner as we go higher. Implementing that is simple. Just add an extra parameter to the draw() function called branchWidth. And then, every time you call the draw() function, decrement the branchWidth by a small value, like so:

draw(0, -len, len*0.8, -15, branchWidth*0.8);
draw(0, -len, len*0.8, 15, branchWidth*0.8);

To actually change the thickness, at the beginning of the draw() function, use the lineWidth attribute of the context.

ctx.lineWidth = branchWidth;

With an initial thickness of 10, here’s what the tree looks like:

Fractal tree, thick

Tweak 2: Add Leaves and Color

Adding color is simple. Just add the following lines right after you initialize your 2D drawing context.

ctx.strokeStyle = "darkgreen";
ctx.fillStyle = "green";

Yeah, feel free to use brown for the trunk if you want to. My tree shall have a dark green trunk.

Adding leaves is a little tricky. For now, let’s use the arc() and fill() methods to create slices of a circle that look like leaves. You must, of course, create the leaves only when the branch cannot branch further.

if(len < 10) {
    ctx.beginPath();
    ctx.arc(0, -len, 10, 0, Math.PI/2);
    ctx.fill();
    ctx.restore();
    return;
}

Additionally, let’s increment the angle every time a new branch is drawn. To do so, change the calls to the draw() function to look like this:

draw(0, -len, len*0.8, angle+10, branchWidth*0.8);
draw(0, -len, len*0.8, angle-10, branchWidth*0.8);

And now, the tree should look like this:

Fractal tree, colored

Much better!

Tweak 3: Add Shadows

Let’s make our tree more realistic by adding shadows! Doing so is easy: just use the shadowBlur and shadowColor attributes of the context.

ctx.shadowBlur = 15;
ctx.shadowColor = "rgba(0,0,0,0.8)";

The tree will now look like this:

Fractal tree, thick

Tweak 4: Use Bezier Curves

All our branches are too straight. As a result, our tree looks too stiff and unnatural. Fortunately, the Canvas API allows us to create bezier curves. If you want to, you can replace the call to the lineTo() method in your code, with calls to the bezierCurveTo() method. Here’s how:

if(angle > 0) {
    ctx.bezierCurveTo(10, -len/2, 10, -len/2, 0, -len);
} else {
    ctx.bezierCurveTo(-10, -len/2, -10, -len/2, 0, -len);
}

After changing the minimum length to 5 instead of 10, you will have a rather natural looking “tree” (do you think calling it a plant would be more appropriate?):

Fractal tree, realistic

Conclusion

You now know how to create fractal trees using just JavaScript and the HTML5 Canvas API. We didn’t use any libraries, and our code is quite concise.

If you found anything confusing, please leave a comment.

Beware that the fractal tree generation code can take a few seconds to run. Your browser might complain that it’s taking too long, but let it run to completion.

If you found this article useful, please share it with your friends and colleagues!