canvasで完全二分木を描画したいのですが

canvas の部分は、外側にしろとあれほど・・・

<!DOCTYPE html>
<meta charset="utf-8">
<title>n木分</title>

<body>
<canvas width="1000" height="300"></canvas>

<script>


(function () {
  
  // NTreeは Nodeというオブジェクトを木の枝のように、親と子(配列)お持つ
  function Node (parent) {
    this.parent = parent;
    this.child = new Array ();
  }

  //_________

  // 元というか種を基準
  function NTree (seed) {
    this.seed = seed;
  }


  // 末端を1回(n分岐)成長させる
  function grow (n) {
    var seed = this.seed;
    var buf = find (seed, []);
    var ary = [ ], i, c, j;

    if (0 === buf.length)
      buf = [seed];

    for (i = 0; c = buf[i]; i += 1)
      for (j = 0; j < n; j += 1)
        c.child[j] = new Node (c);
  }

  
  // DOMのように最初の子枝
  function firstNode (n) {
    return n.child[0] ? n.child[0]: null;
  }


  // DOMのように弟の枝
  function nextSibling (n) {
    var p = n.parent, no;
    var c = p.child;

    if (p)
      if (no = c.indexOf (n) + 1)
        if (no < c.length)
          return c[no];

    return null;
  }


  // 要素をすべて集めて配列で返す
  function getAllNodes (node) {
    if (1 > arguments.length)
      node = this.seed;
      
    var rst = [ ];
    var n, b = node;

    B:
      while (n = b)
        if (! (rst.push (n), b = firstNode (n)))
          while (! (b = nextSibling (n)))
            if (node === (n = n.parent))
              break B;

    return rst;
  }


  // 下の関数で呼ばれる
  function maxDepth (mx, n) {
    return Math.max (this.getDepth (n), mx);
  }


  // nodeの要素を基準に最大の深さを返す
  function getMaxDepth (node) {
    if (1 > arguments.length)
      node = this.seed;
    
    return getAllNodes.call (this).reduce (maxDepth.bind (this), 0);
  }


  // nodeの要素の深さを返す
  function getDepth (node) {
    var cnt = 0;
    var p = node;

    while (p = p.parent)
      cnt += 1;

    return cnt;
  }
  
  
  // 要素に番号を振る
  function setNumber (nd, i) {
    nd.number = this + i;
  }


  // 要素を基準に番号を振る(今回の例は再帰ではないので順番が特殊?)
  function setAutoNumber (node, no) {
    switch (arguments.length) {
    case 0 : 
      node = this.seed;
    case 1 :
      no = 0;
    }
    
    var nd = getAllNodes.call (this, node);
    var gd = [ ], d, i, n;
    
    for (i = 0; n = nd[i]; i += 1) {
      d = this.getDepth (n);
      if ('undefined' === typeof gd[d])
        gd[d] = [ ];
      gd[d].push (n); 
    }

    Array.prototype.concat.apply ([], gd)
      .forEach (setNumber, no);//誉めたたえるべきはここか!?
  }


  //子要素を持たない要素を見つける
  function find (node, buf) {
    var child = node.child;

    for (var i = 0, c; c = child[i]; i += 1)
      hasChildNodes (c)
      ? find (c, buf)
      : buf.push (c);

    return buf;
  }


  // 子要素を持っているか?
  function hasChildNodes (node) {
    return !! node.child.length;
  }


  function create (depth, n) {
    if (2 > arguments.length)
      n = 2;

    var seed = new Node (null);
    var tree = new NTree (seed);
    var i;

    for (i = 0; i < depth; i += 1)
      tree.grow (n);

    return tree;
  }


  NTree.prototype.grow = grow;
  NTree.prototype.getAllNodes = getAllNodes;
  NTree.prototype.getMaxDepth = getMaxDepth;
  NTree.prototype.getDepth = getDepth;
  NTree.prototype.setAutoNumber = setAutoNumber;
  
  NTree.create = create;

  this.NTree = NTree;
}) ();


var tree = NTree.create (5);
tree.setAutoNumber (tree.seed, 1);


(function (tree) {
  var canvas = document.querySelector ('canvas');
  var ctx = canvas.getContext('2d');
  var r = 10;
  var mx = canvas.width;
  var my = canvas.height;
  var stepY = tree.getMaxDepth () + 1;
  var nd = tree.getAllNodes ();
  var i, j, cx, cy, d, row, n, s, c;
  var gnd = [ ];
  
  for (i = 0; n = nd[i]; i += 1) {
    d = tree.getDepth (n);
    if ('undefined' === typeof gnd[d])
      gnd[d] = [ ];
    gnd[d].push (n);
  }

  for (i = 0; row = gnd[i]; i += 1) {
    cy = my / stepY * i + r;
    for (j = 0; n = row[j]; j += 1) {
      cx = mx / (row.length) / 2 + (mx / row.length * j);
      n.x = cx;
      n.y = cy;
    }
  }

  ctx.textAlign = "center";
  ctx.textBaseline ="middle";
  ctx.font = Math.floor (r * 1.4) +"px 'Times New Roman'";

  for (i = 0; n = nd[i]; i += 1) {
    cx = n.x;
    cy = n.y;
    for (j = 0; c = n.child[j]; j += 1) {
      ctx.beginPath ();
      ctx.moveTo (cx, cy);
      ctx.lineTo (c.x, c.y)
      ctx.stroke ();
    }
    ctx.beginPath ();
    ctx.strokeStyle = 'rgb(0,0,0)';
    ctx.fillStyle = 'rgb(255, 255, 255)';
    ctx.arc (cx, cy, r, 0, Math.PI*2);
    ctx.fill ();
    ctx.fillStyle = 'rgb(0, 0,0)';
    ctx.fillText(n.number + '', cx, cy + r/ 8);
    ctx.stroke ();
  }

}) (tree);

</script>