h3mm3's blog

Stories from behind the keyboard

  • RSS
  • Twitter

After I stumbled upon this post about how to draw a Koch curve using turtle graphics, I decided to implement some turtle commands in Javascript and test them inside a <canvas/>.

The application

Set the width and the number of recursions of the Koch algorithm, and watch a classic Koch fractal!

Koch curve parameters:


The implementation

The hearth of the application is the fracturtle object. It implements some turtle graphics commands and the algorithm of the Koch curve (may the SRP god forgive me!). The turtle commands implemented here are:

  • right(): turns the turtle (i.e. the drawing brush) clockwise
  • left(): turns the turtle counter-clockwise
  • forward(): moves the turtle ahead

The whole process starts with the init() function, but the real drawing happens after the fracturtle has received all the commands:

  • begin(): sets the starting position of the turtle
  • koch(): tells the turtle how to move in order to obtain a Koch curve
  • end(): terminates the moving phase and draws the geometric path
<script>
var fracturtle = {
 x0: 0,
 y0: 0,
 w2: 150,
 h2: 150,
 x1: 0,
 y1: 0,
 direction360: 0,
 ctx: undefined,
 canvas: undefined,

 init: function(canvasid, width, height) {
  this.canvas = $("#"+canvasid)[0];
  this.canvas.width = width;
  this.canvas.height = height;
  this.ctx = this.canvas.getContext('2d');
  this.ctx.beginPath();
  this.x0 = w2 = width / 2;
  this.y0 = h2 = height / 2;
 },

 begin: function(x,y) {
  this.ctx.beginPath();
  this.ctx.moveTo(this.x0=x, this.y0=y);
 },

 end: function() {
  this.ctx.closePath();
  this.ctx.fill();
  this.ctx.strokeStyle = "red";
  this.ctx.lineWidth="1px";
  this.ctx.stroke();
 },

 from360: function(angle360) {
  return Math.PI * angle360 / 180;
 },

 forward: function(length) {
  this.x1 = this.x0 + length * Math.cos(this.from360(this.direction360));
  this.y1 = this.y0 + length * Math.sin(this.from360(this.direction360));
  this.ctx.lineTo(this.x0=this.x1,this.y0=this.y1);
 },

 right: function(angle360) {
  this.direction360 -= angle360;
 },

 left: function(angle360) {
  this.direction360 += angle360;
 },

 koch: function(length, depth) {
  if (depth === 0) {
   this.forward(length);
  } else {
   this.koch(length / 3, depth - 1);
   this.right(60);
   this.koch(length / 3, depth - 1);
   this.left(120);
   this.koch(length / 3, depth - 1);
   this.right(60);
   this.koch(length / 3, depth - 1);
  }
 }
};

The algorithm is fired when the user interacts with either dropdown, thanks to this vanilla jQuery code:

$("select").change(function(){ 
 var w = $("#fracturtle_w").val();
 var r = $("#fracturtle_r").val();
                
 if (w==0 || r==0) return;

 fracturtle.init("fracturtle_c",w,w/3);
 fracturtle.begin(0,w/3-1);
 fracturtle.koch(w,r);
 fracturtle.end();
});

Happy programming!

No comments: