toolkit/javascript/d3/d3.layout.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 (function(){d3.layout = {};
       
     2 // Implements hierarchical edge bundling using Holten's algorithm. For each
       
     3 // input link, a path is computed that travels through the tree, up the parent
       
     4 // hierarchy to the least common ancestor, and then back down to the destination
       
     5 // node. Each path is simply an array of nodes.
       
     6 d3.layout.bundle = function() {
       
     7   return function(links) {
       
     8     var paths = [],
       
     9         i = -1,
       
    10         n = links.length;
       
    11     while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
       
    12     return paths;
       
    13   };
       
    14 };
       
    15 
       
    16 function d3_layout_bundlePath(link) {
       
    17   var start = link.source,
       
    18       end = link.target,
       
    19       lca = d3_layout_bundleLeastCommonAncestor(start, end),
       
    20       points = [start];
       
    21   while (start !== lca) {
       
    22     start = start.parent;
       
    23     points.push(start);
       
    24   }
       
    25   var k = points.length;
       
    26   while (end !== lca) {
       
    27     points.splice(k, 0, end);
       
    28     end = end.parent;
       
    29   }
       
    30   return points;
       
    31 }
       
    32 
       
    33 function d3_layout_bundleAncestors(node) {
       
    34   var ancestors = [],
       
    35       parent = node.parent;
       
    36   while (parent != null) {
       
    37     ancestors.push(node);
       
    38     node = parent;
       
    39     parent = parent.parent;
       
    40   }
       
    41   ancestors.push(node);
       
    42   return ancestors;
       
    43 }
       
    44 
       
    45 function d3_layout_bundleLeastCommonAncestor(a, b) {
       
    46   if (a === b) return a;
       
    47   var aNodes = d3_layout_bundleAncestors(a),
       
    48       bNodes = d3_layout_bundleAncestors(b),
       
    49       aNode = aNodes.pop(),
       
    50       bNode = bNodes.pop(),
       
    51       sharedNode = null;
       
    52   while (aNode === bNode) {
       
    53     sharedNode = aNode;
       
    54     aNode = aNodes.pop();
       
    55     bNode = bNodes.pop();
       
    56   }
       
    57   return sharedNode;
       
    58 }
       
    59 d3.layout.chord = function() {
       
    60   var chord = {},
       
    61       chords,
       
    62       groups,
       
    63       matrix,
       
    64       n,
       
    65       padding = 0,
       
    66       sortGroups,
       
    67       sortSubgroups,
       
    68       sortChords;
       
    69 
       
    70   function relayout() {
       
    71     var subgroups = {},
       
    72         groupSums = [],
       
    73         groupIndex = d3.range(n),
       
    74         subgroupIndex = [],
       
    75         k,
       
    76         x,
       
    77         x0,
       
    78         i,
       
    79         j;
       
    80 
       
    81     chords = [];
       
    82     groups = [];
       
    83 
       
    84     // Compute the sum.
       
    85     k = 0, i = -1; while (++i < n) {
       
    86       x = 0, j = -1; while (++j < n) {
       
    87         x += matrix[i][j];
       
    88       }
       
    89       groupSums.push(x);
       
    90       subgroupIndex.push(d3.range(n));
       
    91       k += x;
       
    92     }
       
    93 
       
    94     // Sort groups…
       
    95     if (sortGroups) {
       
    96       groupIndex.sort(function(a, b) {
       
    97         return sortGroups(groupSums[a], groupSums[b]);
       
    98       });
       
    99     }
       
   100 
       
   101     // Sort subgroups…
       
   102     if (sortSubgroups) {
       
   103       subgroupIndex.forEach(function(d, i) {
       
   104         d.sort(function(a, b) {
       
   105           return sortSubgroups(matrix[i][a], matrix[i][b]);
       
   106         });
       
   107       });
       
   108     }
       
   109 
       
   110     // Convert the sum to scaling factor for [0, 2pi].
       
   111     // TODO Allow start and end angle to be specified.
       
   112     // TODO Allow padding to be specified as percentage?
       
   113     k = (2 * Math.PI - padding * n) / k;
       
   114 
       
   115     // Compute the start and end angle for each group and subgroup.
       
   116     // Note: Opera has a bug reordering object literal properties!
       
   117     x = 0, i = -1; while (++i < n) {
       
   118       x0 = x, j = -1; while (++j < n) {
       
   119         var di = groupIndex[i],
       
   120             dj = subgroupIndex[di][j],
       
   121             v = matrix[di][dj],
       
   122             a0 = x,
       
   123             a1 = x += v * k;
       
   124         subgroups[di + "-" + dj] = {
       
   125           index: di,
       
   126           subindex: dj,
       
   127           startAngle: a0,
       
   128           endAngle: a1,
       
   129           value: v
       
   130         };
       
   131       }
       
   132       groups.push({
       
   133         index: di,
       
   134         startAngle: x0,
       
   135         endAngle: x,
       
   136         value: (x - x0) / k
       
   137       });
       
   138       x += padding;
       
   139     }
       
   140 
       
   141     // Generate chords for each (non-empty) subgroup-subgroup link.
       
   142     i = -1; while (++i < n) {
       
   143       j = i - 1; while (++j < n) {
       
   144         var source = subgroups[i + "-" + j],
       
   145             target = subgroups[j + "-" + i];
       
   146         if (source.value || target.value) {
       
   147           chords.push(source.value < target.value
       
   148               ? {source: target, target: source}
       
   149               : {source: source, target: target});
       
   150         }
       
   151       }
       
   152     }
       
   153 
       
   154     if (sortChords) resort();
       
   155   }
       
   156 
       
   157   function resort() {
       
   158     chords.sort(function(a, b) {
       
   159       return sortChords(
       
   160           (a.source.value + a.target.value) / 2,
       
   161           (b.source.value + b.target.value) / 2);
       
   162     });
       
   163   }
       
   164 
       
   165   chord.matrix = function(x) {
       
   166     if (!arguments.length) return matrix;
       
   167     n = (matrix = x) && matrix.length;
       
   168     chords = groups = null;
       
   169     return chord;
       
   170   };
       
   171 
       
   172   chord.padding = function(x) {
       
   173     if (!arguments.length) return padding;
       
   174     padding = x;
       
   175     chords = groups = null;
       
   176     return chord;
       
   177   };
       
   178 
       
   179   chord.sortGroups = function(x) {
       
   180     if (!arguments.length) return sortGroups;
       
   181     sortGroups = x;
       
   182     chords = groups = null;
       
   183     return chord;
       
   184   };
       
   185 
       
   186   chord.sortSubgroups = function(x) {
       
   187     if (!arguments.length) return sortSubgroups;
       
   188     sortSubgroups = x;
       
   189     chords = null;
       
   190     return chord;
       
   191   };
       
   192 
       
   193   chord.sortChords = function(x) {
       
   194     if (!arguments.length) return sortChords;
       
   195     sortChords = x;
       
   196     if (chords) resort();
       
   197     return chord;
       
   198   };
       
   199 
       
   200   chord.chords = function() {
       
   201     if (!chords) relayout();
       
   202     return chords;
       
   203   };
       
   204 
       
   205   chord.groups = function() {
       
   206     if (!groups) relayout();
       
   207     return groups;
       
   208   };
       
   209 
       
   210   return chord;
       
   211 };
       
   212 // A rudimentary force layout using Gauss-Seidel.
       
   213 d3.layout.force = function() {
       
   214   var force = {},
       
   215       event = d3.dispatch("tick"),
       
   216       size = [1, 1],
       
   217       drag,
       
   218       alpha,
       
   219       friction = .9,
       
   220       linkDistance = d3_layout_forceLinkDistance,
       
   221       linkStrength = d3_layout_forceLinkStrength,
       
   222       charge = -30,
       
   223       gravity = .1,
       
   224       theta = .8,
       
   225       interval,
       
   226       nodes = [],
       
   227       links = [],
       
   228       distances,
       
   229       strengths,
       
   230       charges;
       
   231 
       
   232   function repulse(node) {
       
   233     return function(quad, x1, y1, x2, y2) {
       
   234       if (quad.point !== node) {
       
   235         var dx = quad.cx - node.x,
       
   236             dy = quad.cy - node.y,
       
   237             dn = 1 / Math.sqrt(dx * dx + dy * dy);
       
   238 
       
   239         /* Barnes-Hut criterion. */
       
   240         if ((x2 - x1) * dn < theta) {
       
   241           var k = quad.charge * dn * dn;
       
   242           node.px -= dx * k;
       
   243           node.py -= dy * k;
       
   244           return true;
       
   245         }
       
   246 
       
   247         if (quad.point && isFinite(dn)) {
       
   248           var k = quad.pointCharge * dn * dn;
       
   249           node.px -= dx * k;
       
   250           node.py -= dy * k;
       
   251         }
       
   252       }
       
   253       return !quad.charge;
       
   254     };
       
   255   }
       
   256 
       
   257   function tick() {
       
   258     var n = nodes.length,
       
   259         m = links.length,
       
   260         q,
       
   261         i, // current index
       
   262         o, // current object
       
   263         s, // current source
       
   264         t, // current target
       
   265         l, // current distance
       
   266         k, // current force
       
   267         x, // x-distance
       
   268         y; // y-distance
       
   269 
       
   270     // gauss-seidel relaxation for links
       
   271     for (i = 0; i < m; ++i) {
       
   272       o = links[i];
       
   273       s = o.source;
       
   274       t = o.target;
       
   275       x = t.x - s.x;
       
   276       y = t.y - s.y;
       
   277       if (l = (x * x + y * y)) {
       
   278         l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
       
   279         x *= l;
       
   280         y *= l;
       
   281         t.x -= x * (k = s.weight / (t.weight + s.weight));
       
   282         t.y -= y * k;
       
   283         s.x += x * (k = 1 - k);
       
   284         s.y += y * k;
       
   285       }
       
   286     }
       
   287 
       
   288     // apply gravity forces
       
   289     if (k = alpha * gravity) {
       
   290       x = size[0] / 2;
       
   291       y = size[1] / 2;
       
   292       i = -1; if (k) while (++i < n) {
       
   293         o = nodes[i];
       
   294         o.x += (x - o.x) * k;
       
   295         o.y += (y - o.y) * k;
       
   296       }
       
   297     }
       
   298 
       
   299     // compute quadtree center of mass and apply charge forces
       
   300     if (charge) {
       
   301       d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
       
   302       i = -1; while (++i < n) {
       
   303         if (!(o = nodes[i]).fixed) {
       
   304           q.visit(repulse(o));
       
   305         }
       
   306       }
       
   307     }
       
   308 
       
   309     // position verlet integration
       
   310     i = -1; while (++i < n) {
       
   311       o = nodes[i];
       
   312       if (o.fixed) {
       
   313         o.x = o.px;
       
   314         o.y = o.py;
       
   315       } else {
       
   316         o.x -= (o.px - (o.px = o.x)) * friction;
       
   317         o.y -= (o.py - (o.py = o.y)) * friction;
       
   318       }
       
   319     }
       
   320 
       
   321     event.tick({type: "tick", alpha: alpha});
       
   322 
       
   323     // simulated annealing, basically
       
   324     return (alpha *= .99) < .005;
       
   325   }
       
   326 
       
   327   force.on = function(type, listener) {
       
   328     event.on(type, listener);
       
   329     return force;
       
   330   };
       
   331 
       
   332   force.nodes = function(x) {
       
   333     if (!arguments.length) return nodes;
       
   334     nodes = x;
       
   335     return force;
       
   336   };
       
   337 
       
   338   force.links = function(x) {
       
   339     if (!arguments.length) return links;
       
   340     links = x;
       
   341     return force;
       
   342   };
       
   343 
       
   344   force.size = function(x) {
       
   345     if (!arguments.length) return size;
       
   346     size = x;
       
   347     return force;
       
   348   };
       
   349 
       
   350   force.linkDistance = function(x) {
       
   351     if (!arguments.length) return linkDistance;
       
   352     linkDistance = d3.functor(x);
       
   353     return force;
       
   354   };
       
   355 
       
   356   // For backwards-compatibility.
       
   357   force.distance = force.linkDistance;
       
   358 
       
   359   force.linkStrength = function(x) {
       
   360     if (!arguments.length) return linkStrength;
       
   361     linkStrength = d3.functor(x);
       
   362     return force;
       
   363   };
       
   364 
       
   365   force.friction = function(x) {
       
   366     if (!arguments.length) return friction;
       
   367     friction = x;
       
   368     return force;
       
   369   };
       
   370 
       
   371   force.charge = function(x) {
       
   372     if (!arguments.length) return charge;
       
   373     charge = typeof x === "function" ? x : +x;
       
   374     return force;
       
   375   };
       
   376 
       
   377   force.gravity = function(x) {
       
   378     if (!arguments.length) return gravity;
       
   379     gravity = x;
       
   380     return force;
       
   381   };
       
   382 
       
   383   force.theta = function(x) {
       
   384     if (!arguments.length) return theta;
       
   385     theta = x;
       
   386     return force;
       
   387   };
       
   388 
       
   389   force.start = function() {
       
   390     var i,
       
   391         j,
       
   392         n = nodes.length,
       
   393         m = links.length,
       
   394         w = size[0],
       
   395         h = size[1],
       
   396         neighbors,
       
   397         o;
       
   398 
       
   399     for (i = 0; i < n; ++i) {
       
   400       (o = nodes[i]).index = i;
       
   401       o.weight = 0;
       
   402     }
       
   403 
       
   404     distances = [];
       
   405     strengths = [];
       
   406     for (i = 0; i < m; ++i) {
       
   407       o = links[i];
       
   408       if (typeof o.source == "number") o.source = nodes[o.source];
       
   409       if (typeof o.target == "number") o.target = nodes[o.target];
       
   410       distances[i] = linkDistance.call(this, o, i);
       
   411       strengths[i] = linkStrength.call(this, o, i);
       
   412       ++o.source.weight;
       
   413       ++o.target.weight;
       
   414     }
       
   415 
       
   416     for (i = 0; i < n; ++i) {
       
   417       o = nodes[i];
       
   418       if (isNaN(o.x)) o.x = position("x", w);
       
   419       if (isNaN(o.y)) o.y = position("y", h);
       
   420       if (isNaN(o.px)) o.px = o.x;
       
   421       if (isNaN(o.py)) o.py = o.y;
       
   422     }
       
   423 
       
   424     charges = [];
       
   425     if (typeof charge === "function") {
       
   426       for (i = 0; i < n; ++i) {
       
   427         charges[i] = +charge.call(this, nodes[i], i);
       
   428       }
       
   429     } else {
       
   430       for (i = 0; i < n; ++i) {
       
   431         charges[i] = charge;
       
   432       }
       
   433     }
       
   434 
       
   435     // initialize node position based on first neighbor
       
   436     function position(dimension, size) {
       
   437       var neighbors = neighbor(i),
       
   438           j = -1,
       
   439           m = neighbors.length,
       
   440           x;
       
   441       while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
       
   442       return Math.random() * size;
       
   443     }
       
   444 
       
   445     // initialize neighbors lazily
       
   446     function neighbor() {
       
   447       if (!neighbors) {
       
   448         neighbors = [];
       
   449         for (j = 0; j < n; ++j) {
       
   450           neighbors[j] = [];
       
   451         }
       
   452         for (j = 0; j < m; ++j) {
       
   453           var o = links[j];
       
   454           neighbors[o.source.index].push(o.target);
       
   455           neighbors[o.target.index].push(o.source);
       
   456         }
       
   457       }
       
   458       return neighbors[i];
       
   459     }
       
   460 
       
   461     return force.resume();
       
   462   };
       
   463 
       
   464   force.resume = function() {
       
   465     alpha = .1;
       
   466     d3.timer(tick);
       
   467     return force;
       
   468   };
       
   469 
       
   470   force.stop = function() {
       
   471     alpha = 0;
       
   472     return force;
       
   473   };
       
   474 
       
   475   // use `node.call(force.drag)` to make nodes draggable
       
   476   force.drag = function() {
       
   477     if (!drag) drag = d3.behavior.drag()
       
   478         .on("dragstart", dragstart)
       
   479         .on("drag", d3_layout_forceDrag)
       
   480         .on("dragend", d3_layout_forceDragEnd);
       
   481 
       
   482     this.on("mouseover.force", d3_layout_forceDragOver)
       
   483         .on("mouseout.force", d3_layout_forceDragOut)
       
   484         .call(drag);
       
   485   };
       
   486 
       
   487   function dragstart(d) {
       
   488     d3_layout_forceDragOver(d3_layout_forceDragNode = d);
       
   489     d3_layout_forceDragForce = force;
       
   490   }
       
   491 
       
   492   return force;
       
   493 };
       
   494 
       
   495 var d3_layout_forceDragForce,
       
   496     d3_layout_forceDragNode;
       
   497 
       
   498 function d3_layout_forceDragOver(d) {
       
   499   d.fixed |= 2;
       
   500 }
       
   501 
       
   502 function d3_layout_forceDragOut(d) {
       
   503   if (d !== d3_layout_forceDragNode) d.fixed &= 1;
       
   504 }
       
   505 
       
   506 function d3_layout_forceDragEnd() {
       
   507   d3_layout_forceDrag();
       
   508   d3_layout_forceDragNode.fixed &= 1;
       
   509   d3_layout_forceDragForce = d3_layout_forceDragNode = null;
       
   510 }
       
   511 
       
   512 function d3_layout_forceDrag() {
       
   513   d3_layout_forceDragNode.px += d3.event.dx;
       
   514   d3_layout_forceDragNode.py += d3.event.dy;
       
   515   d3_layout_forceDragForce.resume(); // restart annealing
       
   516 }
       
   517 
       
   518 function d3_layout_forceAccumulate(quad, alpha, charges) {
       
   519   var cx = 0,
       
   520       cy = 0;
       
   521   quad.charge = 0;
       
   522   if (!quad.leaf) {
       
   523     var nodes = quad.nodes,
       
   524         n = nodes.length,
       
   525         i = -1,
       
   526         c;
       
   527     while (++i < n) {
       
   528       c = nodes[i];
       
   529       if (c == null) continue;
       
   530       d3_layout_forceAccumulate(c, alpha, charges);
       
   531       quad.charge += c.charge;
       
   532       cx += c.charge * c.cx;
       
   533       cy += c.charge * c.cy;
       
   534     }
       
   535   }
       
   536   if (quad.point) {
       
   537     // jitter internal nodes that are coincident
       
   538     if (!quad.leaf) {
       
   539       quad.point.x += Math.random() - .5;
       
   540       quad.point.y += Math.random() - .5;
       
   541     }
       
   542     var k = alpha * charges[quad.point.index];
       
   543     quad.charge += quad.pointCharge = k;
       
   544     cx += k * quad.point.x;
       
   545     cy += k * quad.point.y;
       
   546   }
       
   547   quad.cx = cx / quad.charge;
       
   548   quad.cy = cy / quad.charge;
       
   549 }
       
   550 
       
   551 function d3_layout_forceLinkDistance(link) {
       
   552   return 20;
       
   553 }
       
   554 
       
   555 function d3_layout_forceLinkStrength(link) {
       
   556   return 1;
       
   557 }
       
   558 d3.layout.partition = function() {
       
   559   var hierarchy = d3.layout.hierarchy(),
       
   560       size = [1, 1]; // width, height
       
   561 
       
   562   function position(node, x, dx, dy) {
       
   563     var children = node.children;
       
   564     node.x = x;
       
   565     node.y = node.depth * dy;
       
   566     node.dx = dx;
       
   567     node.dy = dy;
       
   568     if (children && (n = children.length)) {
       
   569       var i = -1,
       
   570           n,
       
   571           c,
       
   572           d;
       
   573       dx = node.value ? dx / node.value : 0;
       
   574       while (++i < n) {
       
   575         position(c = children[i], x, d = c.value * dx, dy);
       
   576         x += d;
       
   577       }
       
   578     }
       
   579   }
       
   580 
       
   581   function depth(node) {
       
   582     var children = node.children,
       
   583         d = 0;
       
   584     if (children && (n = children.length)) {
       
   585       var i = -1,
       
   586           n;
       
   587       while (++i < n) d = Math.max(d, depth(children[i]));
       
   588     }
       
   589     return 1 + d;
       
   590   }
       
   591 
       
   592   function partition(d, i) {
       
   593     var nodes = hierarchy.call(this, d, i);
       
   594     position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
       
   595     return nodes;
       
   596   }
       
   597 
       
   598   partition.size = function(x) {
       
   599     if (!arguments.length) return size;
       
   600     size = x;
       
   601     return partition;
       
   602   };
       
   603 
       
   604   return d3_layout_hierarchyRebind(partition, hierarchy);
       
   605 };
       
   606 d3.layout.pie = function() {
       
   607   var value = Number,
       
   608       sort = d3_layout_pieSortByValue,
       
   609       startAngle = 0,
       
   610       endAngle = 2 * Math.PI;
       
   611 
       
   612   function pie(data, i) {
       
   613 
       
   614     // Compute the numeric values for each data element.
       
   615     var values = data.map(function(d, i) { return +value.call(pie, d, i); });
       
   616 
       
   617     // Compute the start angle.
       
   618     var a = +(typeof startAngle === "function"
       
   619         ? startAngle.apply(this, arguments)
       
   620         : startAngle);
       
   621 
       
   622     // Compute the angular scale factor: from value to radians.
       
   623     var k = ((typeof endAngle === "function"
       
   624         ? endAngle.apply(this, arguments)
       
   625         : endAngle) - startAngle)
       
   626         / d3.sum(values);
       
   627 
       
   628     // Optionally sort the data.
       
   629     var index = d3.range(data.length);
       
   630     if (sort != null) index.sort(sort === d3_layout_pieSortByValue
       
   631         ? function(i, j) { return values[j] - values[i]; }
       
   632         : function(i, j) { return sort(data[i], data[j]); });
       
   633 
       
   634     // Compute the arcs!
       
   635     var arcs = index.map(function(i) {
       
   636       return {
       
   637         data: data[i],
       
   638         value: d = values[i],
       
   639         startAngle: a,
       
   640         endAngle: a += d * k
       
   641       };
       
   642     });
       
   643 
       
   644     // Return the arcs in the original data's order.
       
   645     return data.map(function(d, i) {
       
   646       return arcs[index[i]];
       
   647     });
       
   648   }
       
   649 
       
   650   /**
       
   651    * Specifies the value function *x*, which returns a nonnegative numeric value
       
   652    * for each datum. The default value function is `Number`. The value function
       
   653    * is passed two arguments: the current datum and the current index.
       
   654    */
       
   655   pie.value = function(x) {
       
   656     if (!arguments.length) return value;
       
   657     value = x;
       
   658     return pie;
       
   659   };
       
   660 
       
   661   /**
       
   662    * Specifies a sort comparison operator *x*. The comparator is passed two data
       
   663    * elements from the data array, a and b; it returns a negative value if a is
       
   664    * less than b, a positive value if a is greater than b, and zero if a equals
       
   665    * b.
       
   666    */
       
   667   pie.sort = function(x) {
       
   668     if (!arguments.length) return sort;
       
   669     sort = x;
       
   670     return pie;
       
   671   };
       
   672 
       
   673   /**
       
   674    * Specifies the overall start angle of the pie chart. Defaults to 0. The
       
   675    * start angle can be specified either as a constant or as a function; in the
       
   676    * case of a function, it is evaluated once per array (as opposed to per
       
   677    * element).
       
   678    */
       
   679   pie.startAngle = function(x) {
       
   680     if (!arguments.length) return startAngle;
       
   681     startAngle = x;
       
   682     return pie;
       
   683   };
       
   684 
       
   685   /**
       
   686    * Specifies the overall end angle of the pie chart. Defaults to 2Ď€. The
       
   687    * end angle can be specified either as a constant or as a function; in the
       
   688    * case of a function, it is evaluated once per array (as opposed to per
       
   689    * element).
       
   690    */
       
   691   pie.endAngle = function(x) {
       
   692     if (!arguments.length) return endAngle;
       
   693     endAngle = x;
       
   694     return pie;
       
   695   };
       
   696 
       
   697   return pie;
       
   698 };
       
   699 
       
   700 var d3_layout_pieSortByValue = {};
       
   701 // data is two-dimensional array of x,y; we populate y0
       
   702 d3.layout.stack = function() {
       
   703   var values = Object,
       
   704       order = d3_layout_stackOrders["default"],
       
   705       offset = d3_layout_stackOffsets["zero"],
       
   706       out = d3_layout_stackOut,
       
   707       x = d3_layout_stackX,
       
   708       y = d3_layout_stackY;
       
   709 
       
   710   function stack(data, index) {
       
   711 
       
   712     // Convert series to canonical two-dimensional representation.
       
   713     var series = data.map(function(d, i) {
       
   714       return values.call(stack, d, i);
       
   715     });
       
   716 
       
   717     // Convert each series to canonical [[x,y]] representation.
       
   718     var points = series.map(function(d, i) {
       
   719       return d.map(function(v, i) {
       
   720         return [x.call(stack, v, i), y.call(stack, v, i)];
       
   721       });
       
   722     });
       
   723 
       
   724     // Compute the order of series, and permute them.
       
   725     var orders = order.call(stack, points, index);
       
   726     series = d3.permute(series, orders);
       
   727     points = d3.permute(points, orders);
       
   728 
       
   729     // Compute the baseline…
       
   730     var offsets = offset.call(stack, points, index);
       
   731 
       
   732     // And propagate it to other series.
       
   733     var n = series.length,
       
   734         m = series[0].length,
       
   735         i,
       
   736         j,
       
   737         o;
       
   738     for (j = 0; j < m; ++j) {
       
   739       out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
       
   740       for (i = 1; i < n; ++i) {
       
   741         out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
       
   742       }
       
   743     }
       
   744 
       
   745     return data;
       
   746   }
       
   747 
       
   748   stack.values = function(x) {
       
   749     if (!arguments.length) return values;
       
   750     values = x;
       
   751     return stack;
       
   752   };
       
   753 
       
   754   stack.order = function(x) {
       
   755     if (!arguments.length) return order;
       
   756     order = typeof x === "function" ? x : d3_layout_stackOrders[x];
       
   757     return stack;
       
   758   };
       
   759 
       
   760   stack.offset = function(x) {
       
   761     if (!arguments.length) return offset;
       
   762     offset = typeof x === "function" ? x : d3_layout_stackOffsets[x];
       
   763     return stack;
       
   764   };
       
   765 
       
   766   stack.x = function(z) {
       
   767     if (!arguments.length) return x;
       
   768     x = z;
       
   769     return stack;
       
   770   };
       
   771 
       
   772   stack.y = function(z) {
       
   773     if (!arguments.length) return y;
       
   774     y = z;
       
   775     return stack;
       
   776   };
       
   777 
       
   778   stack.out = function(z) {
       
   779     if (!arguments.length) return out;
       
   780     out = z;
       
   781     return stack;
       
   782   };
       
   783 
       
   784   return stack;
       
   785 }
       
   786 
       
   787 function d3_layout_stackX(d) {
       
   788   return d.x;
       
   789 }
       
   790 
       
   791 function d3_layout_stackY(d) {
       
   792   return d.y;
       
   793 }
       
   794 
       
   795 function d3_layout_stackOut(d, y0, y) {
       
   796   d.y0 = y0;
       
   797   d.y = y;
       
   798 }
       
   799 
       
   800 var d3_layout_stackOrders = {
       
   801 
       
   802   "inside-out": function(data) {
       
   803     var n = data.length,
       
   804         i,
       
   805         j,
       
   806         max = data.map(d3_layout_stackMaxIndex),
       
   807         sums = data.map(d3_layout_stackReduceSum),
       
   808         index = d3.range(n).sort(function(a, b) { return max[a] - max[b]; }),
       
   809         top = 0,
       
   810         bottom = 0,
       
   811         tops = [],
       
   812         bottoms = [];
       
   813     for (i = 0; i < n; ++i) {
       
   814       j = index[i];
       
   815       if (top < bottom) {
       
   816         top += sums[j];
       
   817         tops.push(j);
       
   818       } else {
       
   819         bottom += sums[j];
       
   820         bottoms.push(j);
       
   821       }
       
   822     }
       
   823     return bottoms.reverse().concat(tops);
       
   824   },
       
   825 
       
   826   "reverse": function(data) {
       
   827     return d3.range(data.length).reverse();
       
   828   },
       
   829 
       
   830   "default": function(data) {
       
   831     return d3.range(data.length);
       
   832   }
       
   833 
       
   834 };
       
   835 
       
   836 var d3_layout_stackOffsets = {
       
   837 
       
   838   "silhouette": function(data) {
       
   839     var n = data.length,
       
   840         m = data[0].length,
       
   841         sums = [],
       
   842         max = 0,
       
   843         i,
       
   844         j,
       
   845         o,
       
   846         y0 = [];
       
   847     for (j = 0; j < m; ++j) {
       
   848       for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
       
   849       if (o > max) max = o;
       
   850       sums.push(o);
       
   851     }
       
   852     for (j = 0; j < m; ++j) {
       
   853       y0[j] = (max - sums[j]) / 2;
       
   854     }
       
   855     return y0;
       
   856   },
       
   857 
       
   858   "wiggle": function(data) {
       
   859     var n = data.length,
       
   860         x = data[0],
       
   861         m = x.length,
       
   862         max = 0,
       
   863         i,
       
   864         j,
       
   865         k,
       
   866         s1,
       
   867         s2,
       
   868         s3,
       
   869         dx,
       
   870         o,
       
   871         o0,
       
   872         y0 = [];
       
   873     y0[0] = o = o0 = 0;
       
   874     for (j = 1; j < m; ++j) {
       
   875       for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
       
   876       for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
       
   877         for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
       
   878           s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
       
   879         }
       
   880         s2 += s3 * data[i][j][1];
       
   881       }
       
   882       y0[j] = o -= s1 ? s2 / s1 * dx : 0;
       
   883       if (o < o0) o0 = o;
       
   884     }
       
   885     for (j = 0; j < m; ++j) y0[j] -= o0;
       
   886     return y0;
       
   887   },
       
   888 
       
   889   "expand": function(data) {
       
   890     var n = data.length,
       
   891         m = data[0].length,
       
   892         k = 1 / n,
       
   893         i,
       
   894         j,
       
   895         o,
       
   896         y0 = [];
       
   897     for (j = 0; j < m; ++j) {
       
   898       for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
       
   899       if (o) for (i = 0; i < n; i++) data[i][j][1] /= o;
       
   900       else for (i = 0; i < n; i++) data[i][j][1] = k;
       
   901     }
       
   902     for (j = 0; j < m; ++j) y0[j] = 0;
       
   903     return y0;
       
   904   },
       
   905 
       
   906   "zero": function(data) {
       
   907     var j = -1,
       
   908         m = data[0].length,
       
   909         y0 = [];
       
   910     while (++j < m) y0[j] = 0;
       
   911     return y0;
       
   912   }
       
   913 
       
   914 };
       
   915 
       
   916 function d3_layout_stackMaxIndex(array) {
       
   917   var i = 1,
       
   918       j = 0,
       
   919       v = array[0][1],
       
   920       k,
       
   921       n = array.length;
       
   922   for (; i < n; ++i) {
       
   923     if ((k = array[i][1]) > v) {
       
   924       j = i;
       
   925       v = k;
       
   926     }
       
   927   }
       
   928   return j;
       
   929 }
       
   930 
       
   931 function d3_layout_stackReduceSum(d) {
       
   932   return d.reduce(d3_layout_stackSum, 0);
       
   933 }
       
   934 
       
   935 function d3_layout_stackSum(p, d) {
       
   936   return p + d[1];
       
   937 }
       
   938 d3.layout.histogram = function() {
       
   939   var frequency = true,
       
   940       valuer = Number,
       
   941       ranger = d3_layout_histogramRange,
       
   942       binner = d3_layout_histogramBinSturges;
       
   943 
       
   944   function histogram(data, i) {
       
   945     var bins = [],
       
   946         values = data.map(valuer, this),
       
   947         range = ranger.call(this, values, i),
       
   948         thresholds = binner.call(this, range, values, i),
       
   949         bin,
       
   950         i = -1,
       
   951         n = values.length,
       
   952         m = thresholds.length - 1,
       
   953         k = frequency ? 1 : 1 / n,
       
   954         x;
       
   955 
       
   956     // Initialize the bins.
       
   957     while (++i < m) {
       
   958       bin = bins[i] = [];
       
   959       bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
       
   960       bin.y = 0;
       
   961     }
       
   962 
       
   963     // Fill the bins, ignoring values outside the range.
       
   964     i = -1; while(++i < n) {
       
   965       x = values[i];
       
   966       if ((x >= range[0]) && (x <= range[1])) {
       
   967         bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
       
   968         bin.y += k;
       
   969         bin.push(data[i]);
       
   970       }
       
   971     }
       
   972 
       
   973     return bins;
       
   974   }
       
   975 
       
   976   // Specifies how to extract a value from the associated data. The default
       
   977   // value function is `Number`, which is equivalent to the identity function.
       
   978   histogram.value = function(x) {
       
   979     if (!arguments.length) return valuer;
       
   980     valuer = x;
       
   981     return histogram;
       
   982   };
       
   983 
       
   984   // Specifies the range of the histogram. Values outside the specified range
       
   985   // will be ignored. The argument `x` may be specified either as a two-element
       
   986   // array representing the minimum and maximum value of the range, or as a
       
   987   // function that returns the range given the array of values and the current
       
   988   // index `i`. The default range is the extent (minimum and maximum) of the
       
   989   // values.
       
   990   histogram.range = function(x) {
       
   991     if (!arguments.length) return ranger;
       
   992     ranger = d3.functor(x);
       
   993     return histogram;
       
   994   };
       
   995 
       
   996   // Specifies how to bin values in the histogram. The argument `x` may be
       
   997   // specified as a number, in which case the range of values will be split
       
   998   // uniformly into the given number of bins. Or, `x` may be an array of
       
   999   // threshold values, defining the bins; the specified array must contain the
       
  1000   // rightmost (upper) value, thus specifying n + 1 values for n bins. Or, `x`
       
  1001   // may be a function which is evaluated, being passed the range, the array of
       
  1002   // values, and the current index `i`, returning an array of thresholds. The
       
  1003   // default bin function will divide the values into uniform bins using
       
  1004   // Sturges' formula.
       
  1005   histogram.bins = function(x) {
       
  1006     if (!arguments.length) return binner;
       
  1007     binner = typeof x === "number"
       
  1008         ? function(range) { return d3_layout_histogramBinFixed(range, x); }
       
  1009         : d3.functor(x);
       
  1010     return histogram;
       
  1011   };
       
  1012 
       
  1013   // Specifies whether the histogram's `y` value is a count (frequency) or a
       
  1014   // probability (density). The default value is true.
       
  1015   histogram.frequency = function(x) {
       
  1016     if (!arguments.length) return frequency;
       
  1017     frequency = !!x;
       
  1018     return histogram;
       
  1019   };
       
  1020 
       
  1021   return histogram;
       
  1022 };
       
  1023 
       
  1024 function d3_layout_histogramBinSturges(range, values) {
       
  1025   return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
       
  1026 }
       
  1027 
       
  1028 function d3_layout_histogramBinFixed(range, n) {
       
  1029   var x = -1,
       
  1030       b = +range[0],
       
  1031       m = (range[1] - b) / n,
       
  1032       f = [];
       
  1033   while (++x <= n) f[x] = m * x + b;
       
  1034   return f;
       
  1035 }
       
  1036 
       
  1037 function d3_layout_histogramRange(values) {
       
  1038   return [d3.min(values), d3.max(values)];
       
  1039 }
       
  1040 d3.layout.hierarchy = function() {
       
  1041   var sort = d3_layout_hierarchySort,
       
  1042       children = d3_layout_hierarchyChildren,
       
  1043       value = d3_layout_hierarchyValue;
       
  1044 
       
  1045   // Recursively compute the node depth and value.
       
  1046   // Also converts the data representation into a standard hierarchy structure.
       
  1047   function recurse(data, depth, nodes) {
       
  1048     var childs = children.call(hierarchy, data, depth),
       
  1049         node = d3_layout_hierarchyInline ? data : {data: data};
       
  1050     node.depth = depth;
       
  1051     nodes.push(node);
       
  1052     if (childs && (n = childs.length)) {
       
  1053       var i = -1,
       
  1054           n,
       
  1055           c = node.children = [],
       
  1056           v = 0,
       
  1057           j = depth + 1;
       
  1058       while (++i < n) {
       
  1059         d = recurse(childs[i], j, nodes);
       
  1060         d.parent = node;
       
  1061         c.push(d);
       
  1062         v += d.value;
       
  1063       }
       
  1064       if (sort) c.sort(sort);
       
  1065       if (value) node.value = v;
       
  1066     } else if (value) {
       
  1067       node.value = +value.call(hierarchy, data, depth) || 0;
       
  1068     }
       
  1069     return node;
       
  1070   }
       
  1071 
       
  1072   // Recursively re-evaluates the node value.
       
  1073   function revalue(node, depth) {
       
  1074     var children = node.children,
       
  1075         v = 0;
       
  1076     if (children && (n = children.length)) {
       
  1077       var i = -1,
       
  1078           n,
       
  1079           j = depth + 1;
       
  1080       while (++i < n) v += revalue(children[i], j);
       
  1081     } else if (value) {
       
  1082       v = +value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth) || 0;
       
  1083     }
       
  1084     if (value) node.value = v;
       
  1085     return v;
       
  1086   }
       
  1087 
       
  1088   function hierarchy(d) {
       
  1089     var nodes = [];
       
  1090     recurse(d, 0, nodes);
       
  1091     return nodes;
       
  1092   }
       
  1093 
       
  1094   hierarchy.sort = function(x) {
       
  1095     if (!arguments.length) return sort;
       
  1096     sort = x;
       
  1097     return hierarchy;
       
  1098   };
       
  1099 
       
  1100   hierarchy.children = function(x) {
       
  1101     if (!arguments.length) return children;
       
  1102     children = x;
       
  1103     return hierarchy;
       
  1104   };
       
  1105 
       
  1106   hierarchy.value = function(x) {
       
  1107     if (!arguments.length) return value;
       
  1108     value = x;
       
  1109     return hierarchy;
       
  1110   };
       
  1111 
       
  1112   // Re-evaluates the `value` property for the specified hierarchy.
       
  1113   hierarchy.revalue = function(root) {
       
  1114     revalue(root, 0);
       
  1115     return root;
       
  1116   };
       
  1117 
       
  1118   return hierarchy;
       
  1119 };
       
  1120 
       
  1121 // A method assignment helper for hierarchy subclasses.
       
  1122 function d3_layout_hierarchyRebind(object, hierarchy) {
       
  1123   object.sort = d3.rebind(object, hierarchy.sort);
       
  1124   object.children = d3.rebind(object, hierarchy.children);
       
  1125   object.links = d3_layout_hierarchyLinks;
       
  1126   object.value = d3.rebind(object, hierarchy.value);
       
  1127 
       
  1128   // If the new API is used, enabling inlining.
       
  1129   object.nodes = function(d) {
       
  1130     d3_layout_hierarchyInline = true;
       
  1131     return (object.nodes = object)(d);
       
  1132   };
       
  1133 
       
  1134   return object;
       
  1135 }
       
  1136 
       
  1137 function d3_layout_hierarchyChildren(d) {
       
  1138   return d.children;
       
  1139 }
       
  1140 
       
  1141 function d3_layout_hierarchyValue(d) {
       
  1142   return d.value;
       
  1143 }
       
  1144 
       
  1145 function d3_layout_hierarchySort(a, b) {
       
  1146   return b.value - a.value;
       
  1147 }
       
  1148 
       
  1149 // Returns an array source+target objects for the specified nodes.
       
  1150 function d3_layout_hierarchyLinks(nodes) {
       
  1151   return d3.merge(nodes.map(function(parent) {
       
  1152     return (parent.children || []).map(function(child) {
       
  1153       return {source: parent, target: child};
       
  1154     });
       
  1155   }));
       
  1156 }
       
  1157 
       
  1158 // For backwards-compatibility, don't enable inlining by default.
       
  1159 var d3_layout_hierarchyInline = false;
       
  1160 d3.layout.pack = function() {
       
  1161   var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort),
       
  1162       size = [1, 1];
       
  1163 
       
  1164   function pack(d, i) {
       
  1165     var nodes = hierarchy.call(this, d, i),
       
  1166         root = nodes[0];
       
  1167 
       
  1168     // Recursively compute the layout.
       
  1169     root.x = 0;
       
  1170     root.y = 0;
       
  1171     d3_layout_packTree(root);
       
  1172 
       
  1173     // Scale the layout to fit the requested size.
       
  1174     var w = size[0],
       
  1175         h = size[1],
       
  1176         k = 1 / Math.max(2 * root.r / w, 2 * root.r / h);
       
  1177     d3_layout_packTransform(root, w / 2, h / 2, k);
       
  1178 
       
  1179     return nodes;
       
  1180   }
       
  1181 
       
  1182   pack.size = function(x) {
       
  1183     if (!arguments.length) return size;
       
  1184     size = x;
       
  1185     return pack;
       
  1186   };
       
  1187 
       
  1188   return d3_layout_hierarchyRebind(pack, hierarchy);
       
  1189 };
       
  1190 
       
  1191 function d3_layout_packSort(a, b) {
       
  1192   return a.value - b.value;
       
  1193 }
       
  1194 
       
  1195 function d3_layout_packInsert(a, b) {
       
  1196   var c = a._pack_next;
       
  1197   a._pack_next = b;
       
  1198   b._pack_prev = a;
       
  1199   b._pack_next = c;
       
  1200   c._pack_prev = b;
       
  1201 }
       
  1202 
       
  1203 function d3_layout_packSplice(a, b) {
       
  1204   a._pack_next = b;
       
  1205   b._pack_prev = a;
       
  1206 }
       
  1207 
       
  1208 function d3_layout_packIntersects(a, b) {
       
  1209   var dx = b.x - a.x,
       
  1210       dy = b.y - a.y,
       
  1211       dr = a.r + b.r;
       
  1212   return (dr * dr - dx * dx - dy * dy) > .001; // within epsilon
       
  1213 }
       
  1214 
       
  1215 function d3_layout_packCircle(nodes) {
       
  1216   var xMin = Infinity,
       
  1217       xMax = -Infinity,
       
  1218       yMin = Infinity,
       
  1219       yMax = -Infinity,
       
  1220       n = nodes.length,
       
  1221       a, b, c, j, k;
       
  1222 
       
  1223   function bound(node) {
       
  1224     xMin = Math.min(node.x - node.r, xMin);
       
  1225     xMax = Math.max(node.x + node.r, xMax);
       
  1226     yMin = Math.min(node.y - node.r, yMin);
       
  1227     yMax = Math.max(node.y + node.r, yMax);
       
  1228   }
       
  1229 
       
  1230   // Create node links.
       
  1231   nodes.forEach(d3_layout_packLink);
       
  1232 
       
  1233   // Create first node.
       
  1234   a = nodes[0];
       
  1235   a.x = -a.r;
       
  1236   a.y = 0;
       
  1237   bound(a);
       
  1238 
       
  1239   // Create second node.
       
  1240   if (n > 1) {
       
  1241     b = nodes[1];
       
  1242     b.x = b.r;
       
  1243     b.y = 0;
       
  1244     bound(b);
       
  1245 
       
  1246     // Create third node and build chain.
       
  1247     if (n > 2) {
       
  1248       c = nodes[2];
       
  1249       d3_layout_packPlace(a, b, c);
       
  1250       bound(c);
       
  1251       d3_layout_packInsert(a, c);
       
  1252       a._pack_prev = c;
       
  1253       d3_layout_packInsert(c, b);
       
  1254       b = a._pack_next;
       
  1255 
       
  1256       // Now iterate through the rest.
       
  1257       for (var i = 3; i < n; i++) {
       
  1258         d3_layout_packPlace(a, b, c = nodes[i]);
       
  1259 
       
  1260         // Search for the closest intersection.
       
  1261         var isect = 0, s1 = 1, s2 = 1;
       
  1262         for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
       
  1263           if (d3_layout_packIntersects(j, c)) {
       
  1264             isect = 1;
       
  1265             break;
       
  1266           }
       
  1267         }
       
  1268         if (isect == 1) {
       
  1269           for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
       
  1270             if (d3_layout_packIntersects(k, c)) {
       
  1271               if (s2 < s1) {
       
  1272                 isect = -1;
       
  1273                 j = k;
       
  1274               }
       
  1275               break;
       
  1276             }
       
  1277           }
       
  1278         }
       
  1279 
       
  1280         // Update node chain.
       
  1281         if (isect == 0) {
       
  1282           d3_layout_packInsert(a, c);
       
  1283           b = c;
       
  1284           bound(c);
       
  1285         } else if (isect > 0) {
       
  1286           d3_layout_packSplice(a, j);
       
  1287           b = j;
       
  1288           i--;
       
  1289         } else { // isect < 0
       
  1290           d3_layout_packSplice(j, b);
       
  1291           a = j;
       
  1292           i--;
       
  1293         }
       
  1294       }
       
  1295     }
       
  1296   }
       
  1297 
       
  1298   // Re-center the circles and return the encompassing radius.
       
  1299   var cx = (xMin + xMax) / 2,
       
  1300       cy = (yMin + yMax) / 2,
       
  1301       cr = 0;
       
  1302   for (var i = 0; i < n; i++) {
       
  1303     var node = nodes[i];
       
  1304     node.x -= cx;
       
  1305     node.y -= cy;
       
  1306     cr = Math.max(cr, node.r + Math.sqrt(node.x * node.x + node.y * node.y));
       
  1307   }
       
  1308 
       
  1309   // Remove node links.
       
  1310   nodes.forEach(d3_layout_packUnlink);
       
  1311 
       
  1312   return cr;
       
  1313 }
       
  1314 
       
  1315 function d3_layout_packLink(node) {
       
  1316   node._pack_next = node._pack_prev = node;
       
  1317 }
       
  1318 
       
  1319 function d3_layout_packUnlink(node) {
       
  1320   delete node._pack_next;
       
  1321   delete node._pack_prev;
       
  1322 }
       
  1323 
       
  1324 function d3_layout_packTree(node) {
       
  1325   var children = node.children;
       
  1326   if (children && children.length) {
       
  1327     children.forEach(d3_layout_packTree);
       
  1328     node.r = d3_layout_packCircle(children);
       
  1329   } else {
       
  1330     node.r = Math.sqrt(node.value);
       
  1331   }
       
  1332 }
       
  1333 
       
  1334 function d3_layout_packTransform(node, x, y, k) {
       
  1335   var children = node.children;
       
  1336   node.x = (x += k * node.x);
       
  1337   node.y = (y += k * node.y);
       
  1338   node.r *= k;
       
  1339   if (children) {
       
  1340     var i = -1, n = children.length;
       
  1341     while (++i < n) d3_layout_packTransform(children[i], x, y, k);
       
  1342   }
       
  1343 }
       
  1344 
       
  1345 function d3_layout_packPlace(a, b, c) {
       
  1346   var db = a.r + c.r,
       
  1347       dx = b.x - a.x,
       
  1348       dy = b.y - a.y;
       
  1349   if (db && (dx || dy)) {
       
  1350     var da = b.r + c.r,
       
  1351         dc = Math.sqrt(dx * dx + dy * dy),
       
  1352         cos = Math.max(-1, Math.min(1, (db * db + dc * dc - da * da) / (2 * db * dc))),
       
  1353         theta = Math.acos(cos),
       
  1354         x = cos * (db /= dc),
       
  1355         y = Math.sin(theta) * db;
       
  1356     c.x = a.x + x * dx + y * dy;
       
  1357     c.y = a.y + x * dy - y * dx;
       
  1358   } else {
       
  1359     c.x = a.x + db;
       
  1360     c.y = a.y;
       
  1361   }
       
  1362 }
       
  1363 // Implements a hierarchical layout using the cluster (or dendogram) algorithm.
       
  1364 d3.layout.cluster = function() {
       
  1365   var hierarchy = d3.layout.hierarchy().sort(null).value(null),
       
  1366       separation = d3_layout_treeSeparation,
       
  1367       size = [1, 1]; // width, height
       
  1368 
       
  1369   function cluster(d, i) {
       
  1370     var nodes = hierarchy.call(this, d, i),
       
  1371         root = nodes[0],
       
  1372         previousNode,
       
  1373         x = 0,
       
  1374         kx,
       
  1375         ky;
       
  1376 
       
  1377     // First walk, computing the initial x & y values.
       
  1378     d3_layout_treeVisitAfter(root, function(node) {
       
  1379       var children = node.children;
       
  1380       if (children && children.length) {
       
  1381         node.x = d3_layout_clusterX(children);
       
  1382         node.y = d3_layout_clusterY(children);
       
  1383       } else {
       
  1384         node.x = previousNode ? x += separation(node, previousNode) : 0;
       
  1385         node.y = 0;
       
  1386         previousNode = node;
       
  1387       }
       
  1388     });
       
  1389 
       
  1390     // Compute the left-most, right-most, and depth-most nodes for extents.
       
  1391     var left = d3_layout_clusterLeft(root),
       
  1392         right = d3_layout_clusterRight(root),
       
  1393         x0 = left.x - separation(left, right) / 2,
       
  1394         x1 = right.x + separation(right, left) / 2;
       
  1395 
       
  1396     // Second walk, normalizing x & y to the desired size.
       
  1397     d3_layout_treeVisitAfter(root, function(node) {
       
  1398       node.x = (node.x - x0) / (x1 - x0) * size[0];
       
  1399       node.y = (1 - node.y / root.y) * size[1];
       
  1400     });
       
  1401 
       
  1402     return nodes;
       
  1403   }
       
  1404 
       
  1405   cluster.separation = function(x) {
       
  1406     if (!arguments.length) return separation;
       
  1407     separation = x;
       
  1408     return cluster;
       
  1409   };
       
  1410 
       
  1411   cluster.size = function(x) {
       
  1412     if (!arguments.length) return size;
       
  1413     size = x;
       
  1414     return cluster;
       
  1415   };
       
  1416 
       
  1417   return d3_layout_hierarchyRebind(cluster, hierarchy);
       
  1418 };
       
  1419 
       
  1420 function d3_layout_clusterY(children) {
       
  1421   return 1 + d3.max(children, function(child) {
       
  1422     return child.y;
       
  1423   });
       
  1424 }
       
  1425 
       
  1426 function d3_layout_clusterX(children) {
       
  1427   return children.reduce(function(x, child) {
       
  1428     return x + child.x;
       
  1429   }, 0) / children.length;
       
  1430 }
       
  1431 
       
  1432 function d3_layout_clusterLeft(node) {
       
  1433   var children = node.children;
       
  1434   return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
       
  1435 }
       
  1436 
       
  1437 function d3_layout_clusterRight(node) {
       
  1438   var children = node.children, n;
       
  1439   return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
       
  1440 }
       
  1441 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
       
  1442 d3.layout.tree = function() {
       
  1443   var hierarchy = d3.layout.hierarchy().sort(null).value(null),
       
  1444       separation = d3_layout_treeSeparation,
       
  1445       size = [1, 1]; // width, height
       
  1446 
       
  1447   function tree(d, i) {
       
  1448     var nodes = hierarchy.call(this, d, i),
       
  1449         root = nodes[0];
       
  1450 
       
  1451     function firstWalk(node, previousSibling) {
       
  1452       var children = node.children,
       
  1453           layout = node._tree;
       
  1454       if (children && (n = children.length)) {
       
  1455         var n,
       
  1456             firstChild = children[0],
       
  1457             previousChild,
       
  1458             ancestor = firstChild,
       
  1459             child,
       
  1460             i = -1;
       
  1461         while (++i < n) {
       
  1462           child = children[i];
       
  1463           firstWalk(child, previousChild);
       
  1464           ancestor = apportion(child, previousChild, ancestor);
       
  1465           previousChild = child;
       
  1466         }
       
  1467         d3_layout_treeShift(node);
       
  1468         var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
       
  1469         if (previousSibling) {
       
  1470           layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
       
  1471           layout.mod = layout.prelim - midpoint;
       
  1472         } else {
       
  1473           layout.prelim = midpoint;
       
  1474         }
       
  1475       } else {
       
  1476         if (previousSibling) {
       
  1477           layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
       
  1478         }
       
  1479       }
       
  1480     }
       
  1481 
       
  1482     function secondWalk(node, x) {
       
  1483       node.x = node._tree.prelim + x;
       
  1484       var children = node.children;
       
  1485       if (children && (n = children.length)) {
       
  1486         var i = -1,
       
  1487             n;
       
  1488         x += node._tree.mod;
       
  1489         while (++i < n) {
       
  1490           secondWalk(children[i], x);
       
  1491         }
       
  1492       }
       
  1493     }
       
  1494 
       
  1495     function apportion(node, previousSibling, ancestor) {
       
  1496       if (previousSibling) {
       
  1497         var vip = node,
       
  1498             vop = node,
       
  1499             vim = previousSibling,
       
  1500             vom = node.parent.children[0],
       
  1501             sip = vip._tree.mod,
       
  1502             sop = vop._tree.mod,
       
  1503             sim = vim._tree.mod,
       
  1504             som = vom._tree.mod,
       
  1505             shift;
       
  1506         while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
       
  1507           vom = d3_layout_treeLeft(vom);
       
  1508           vop = d3_layout_treeRight(vop);
       
  1509           vop._tree.ancestor = node;
       
  1510           shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
       
  1511           if (shift > 0) {
       
  1512             d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
       
  1513             sip += shift;
       
  1514             sop += shift;
       
  1515           }
       
  1516           sim += vim._tree.mod;
       
  1517           sip += vip._tree.mod;
       
  1518           som += vom._tree.mod;
       
  1519           sop += vop._tree.mod;
       
  1520         }
       
  1521         if (vim && !d3_layout_treeRight(vop)) {
       
  1522           vop._tree.thread = vim;
       
  1523           vop._tree.mod += sim - sop;
       
  1524         }
       
  1525         if (vip && !d3_layout_treeLeft(vom)) {
       
  1526           vom._tree.thread = vip;
       
  1527           vom._tree.mod += sip - som;
       
  1528           ancestor = node;
       
  1529         }
       
  1530       }
       
  1531       return ancestor;
       
  1532     }
       
  1533 
       
  1534     // Initialize temporary layout variables.
       
  1535     d3_layout_treeVisitAfter(root, function(node, previousSibling) {
       
  1536       node._tree = {
       
  1537         ancestor: node,
       
  1538         prelim: 0,
       
  1539         mod: 0,
       
  1540         change: 0,
       
  1541         shift: 0,
       
  1542         number: previousSibling ? previousSibling._tree.number + 1 : 0
       
  1543       };
       
  1544     });
       
  1545 
       
  1546     // Compute the layout using Buchheim et al.'s algorithm.
       
  1547     firstWalk(root);
       
  1548     secondWalk(root, -root._tree.prelim);
       
  1549 
       
  1550     // Compute the left-most, right-most, and depth-most nodes for extents.
       
  1551     var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost),
       
  1552         right = d3_layout_treeSearch(root, d3_layout_treeRightmost),
       
  1553         deep = d3_layout_treeSearch(root, d3_layout_treeDeepest),
       
  1554         x0 = left.x - separation(left, right) / 2,
       
  1555         x1 = right.x + separation(right, left) / 2,
       
  1556         y1 = deep.depth || 1;
       
  1557 
       
  1558     // Clear temporary layout variables; transform x and y.
       
  1559     d3_layout_treeVisitAfter(root, function(node) {
       
  1560       node.x = (node.x - x0) / (x1 - x0) * size[0];
       
  1561       node.y = node.depth / y1 * size[1];
       
  1562       delete node._tree;
       
  1563     });
       
  1564 
       
  1565     return nodes;
       
  1566   }
       
  1567 
       
  1568   tree.separation = function(x) {
       
  1569     if (!arguments.length) return separation;
       
  1570     separation = x;
       
  1571     return tree;
       
  1572   };
       
  1573 
       
  1574   tree.size = function(x) {
       
  1575     if (!arguments.length) return size;
       
  1576     size = x;
       
  1577     return tree;
       
  1578   };
       
  1579 
       
  1580   return d3_layout_hierarchyRebind(tree, hierarchy);
       
  1581 };
       
  1582 
       
  1583 function d3_layout_treeSeparation(a, b) {
       
  1584   return a.parent == b.parent ? 1 : 2;
       
  1585 }
       
  1586 
       
  1587 // function d3_layout_treeSeparationRadial(a, b) {
       
  1588 //   return (a.parent == b.parent ? 1 : 2) / a.depth;
       
  1589 // }
       
  1590 
       
  1591 function d3_layout_treeLeft(node) {
       
  1592   var children = node.children;
       
  1593   return children && children.length ? children[0] : node._tree.thread;
       
  1594 }
       
  1595 
       
  1596 function d3_layout_treeRight(node) {
       
  1597   var children = node.children,
       
  1598       n;
       
  1599   return children && (n = children.length) ? children[n - 1] : node._tree.thread;
       
  1600 }
       
  1601 
       
  1602 function d3_layout_treeSearch(node, compare) {
       
  1603   var children = node.children;
       
  1604   if (children && (n = children.length)) {
       
  1605     var child,
       
  1606         n,
       
  1607         i = -1;
       
  1608     while (++i < n) {
       
  1609       if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
       
  1610         node = child;
       
  1611       }
       
  1612     }
       
  1613   }
       
  1614   return node;
       
  1615 }
       
  1616 
       
  1617 function d3_layout_treeRightmost(a, b) {
       
  1618   return a.x - b.x;
       
  1619 }
       
  1620 
       
  1621 function d3_layout_treeLeftmost(a, b) {
       
  1622   return b.x - a.x;
       
  1623 }
       
  1624 
       
  1625 function d3_layout_treeDeepest(a, b) {
       
  1626   return a.depth - b.depth;
       
  1627 }
       
  1628 
       
  1629 function d3_layout_treeVisitAfter(node, callback) {
       
  1630   function visit(node, previousSibling) {
       
  1631     var children = node.children;
       
  1632     if (children && (n = children.length)) {
       
  1633       var child,
       
  1634           previousChild = null,
       
  1635           i = -1,
       
  1636           n;
       
  1637       while (++i < n) {
       
  1638         child = children[i];
       
  1639         visit(child, previousChild);
       
  1640         previousChild = child;
       
  1641       }
       
  1642     }
       
  1643     callback(node, previousSibling);
       
  1644   }
       
  1645   visit(node, null);
       
  1646 }
       
  1647 
       
  1648 function d3_layout_treeShift(node) {
       
  1649   var shift = 0,
       
  1650       change = 0,
       
  1651       children = node.children,
       
  1652       i = children.length,
       
  1653       child;
       
  1654   while (--i >= 0) {
       
  1655     child = children[i]._tree;
       
  1656     child.prelim += shift;
       
  1657     child.mod += shift;
       
  1658     shift += child.shift + (change += child.change);
       
  1659   }
       
  1660 }
       
  1661 
       
  1662 function d3_layout_treeMove(ancestor, node, shift) {
       
  1663   ancestor = ancestor._tree;
       
  1664   node = node._tree;
       
  1665   var change = shift / (node.number - ancestor.number);
       
  1666   ancestor.change += change;
       
  1667   node.change -= change;
       
  1668   node.shift += shift;
       
  1669   node.prelim += shift;
       
  1670   node.mod += shift;
       
  1671 }
       
  1672 
       
  1673 function d3_layout_treeAncestor(vim, node, ancestor) {
       
  1674   return vim._tree.ancestor.parent == node.parent
       
  1675       ? vim._tree.ancestor
       
  1676       : ancestor;
       
  1677 }
       
  1678 // Squarified Treemaps by Mark Bruls, Kees Huizing, and Jarke J. van Wijk
       
  1679 // Modified to support a target aspect ratio by Jeff Heer
       
  1680 d3.layout.treemap = function() {
       
  1681   var hierarchy = d3.layout.hierarchy(),
       
  1682       round = Math.round,
       
  1683       size = [1, 1], // width, height
       
  1684       padding = null,
       
  1685       pad = d3_layout_treemapPadNull,
       
  1686       sticky = false,
       
  1687       stickies,
       
  1688       ratio = 0.5 * (1 + Math.sqrt(5)); // golden ratio
       
  1689 
       
  1690   // Compute the area for each child based on value & scale.
       
  1691   function scale(children, k) {
       
  1692     var i = -1,
       
  1693         n = children.length,
       
  1694         child,
       
  1695         area;
       
  1696     while (++i < n) {
       
  1697       area = (child = children[i]).value * (k < 0 ? 0 : k);
       
  1698       child.area = isNaN(area) || area <= 0 ? 0 : area;
       
  1699     }
       
  1700   }
       
  1701 
       
  1702   // Recursively arranges the specified node's children into squarified rows.
       
  1703   function squarify(node) {
       
  1704     var children = node.children;
       
  1705     if (children && children.length) {
       
  1706       var rect = pad(node),
       
  1707           row = [],
       
  1708           remaining = children.slice(), // copy-on-write
       
  1709           child,
       
  1710           best = Infinity, // the best row score so far
       
  1711           score, // the current row score
       
  1712           u = Math.min(rect.dx, rect.dy), // initial orientation
       
  1713           n;
       
  1714       scale(remaining, rect.dx * rect.dy / node.value);
       
  1715       row.area = 0;
       
  1716       while ((n = remaining.length) > 0) {
       
  1717         row.push(child = remaining[n - 1]);
       
  1718         row.area += child.area;
       
  1719         if ((score = worst(row, u)) <= best) { // continue with this orientation
       
  1720           remaining.pop();
       
  1721           best = score;
       
  1722         } else { // abort, and try a different orientation
       
  1723           row.area -= row.pop().area;
       
  1724           position(row, u, rect, false);
       
  1725           u = Math.min(rect.dx, rect.dy);
       
  1726           row.length = row.area = 0;
       
  1727           best = Infinity;
       
  1728         }
       
  1729       }
       
  1730       if (row.length) {
       
  1731         position(row, u, rect, true);
       
  1732         row.length = row.area = 0;
       
  1733       }
       
  1734       children.forEach(squarify);
       
  1735     }
       
  1736   }
       
  1737 
       
  1738   // Recursively resizes the specified node's children into existing rows.
       
  1739   // Preserves the existing layout!
       
  1740   function stickify(node) {
       
  1741     var children = node.children;
       
  1742     if (children && children.length) {
       
  1743       var rect = pad(node),
       
  1744           remaining = children.slice(), // copy-on-write
       
  1745           child,
       
  1746           row = [];
       
  1747       scale(remaining, rect.dx * rect.dy / node.value);
       
  1748       row.area = 0;
       
  1749       while (child = remaining.pop()) {
       
  1750         row.push(child);
       
  1751         row.area += child.area;
       
  1752         if (child.z != null) {
       
  1753           position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
       
  1754           row.length = row.area = 0;
       
  1755         }
       
  1756       }
       
  1757       children.forEach(stickify);
       
  1758     }
       
  1759   }
       
  1760 
       
  1761   // Computes the score for the specified row, as the worst aspect ratio.
       
  1762   function worst(row, u) {
       
  1763     var s = row.area,
       
  1764         r,
       
  1765         rmax = 0,
       
  1766         rmin = Infinity,
       
  1767         i = -1,
       
  1768         n = row.length;
       
  1769     while (++i < n) {
       
  1770       if (!(r = row[i].area)) continue;
       
  1771       if (r < rmin) rmin = r;
       
  1772       if (r > rmax) rmax = r;
       
  1773     }
       
  1774     s *= s;
       
  1775     u *= u;
       
  1776     return s
       
  1777         ? Math.max((u * rmax * ratio) / s, s / (u * rmin * ratio))
       
  1778         : Infinity;
       
  1779   }
       
  1780 
       
  1781   // Positions the specified row of nodes. Modifies `rect`.
       
  1782   function position(row, u, rect, flush) {
       
  1783     var i = -1,
       
  1784         n = row.length,
       
  1785         x = rect.x,
       
  1786         y = rect.y,
       
  1787         v = u ? round(row.area / u) : 0,
       
  1788         o;
       
  1789     if (u == rect.dx) { // horizontal subdivision
       
  1790       if (flush || v > rect.dy) v = v ? rect.dy : 0; // over+underflow
       
  1791       while (++i < n) {
       
  1792         o = row[i];
       
  1793         o.x = x;
       
  1794         o.y = y;
       
  1795         o.dy = v;
       
  1796         x += o.dx = v ? round(o.area / v) : 0;
       
  1797       }
       
  1798       o.z = true;
       
  1799       o.dx += rect.x + rect.dx - x; // rounding error
       
  1800       rect.y += v;
       
  1801       rect.dy -= v;
       
  1802     } else { // vertical subdivision
       
  1803       if (flush || v > rect.dx) v = v ? rect.dx : 0; // over+underflow
       
  1804       while (++i < n) {
       
  1805         o = row[i];
       
  1806         o.x = x;
       
  1807         o.y = y;
       
  1808         o.dx = v;
       
  1809         y += o.dy = v ? round(o.area / v) : 0;
       
  1810       }
       
  1811       o.z = false;
       
  1812       o.dy += rect.y + rect.dy - y; // rounding error
       
  1813       rect.x += v;
       
  1814       rect.dx -= v;
       
  1815     }
       
  1816   }
       
  1817 
       
  1818   function treemap(d) {
       
  1819     var nodes = stickies || hierarchy(d),
       
  1820         root = nodes[0];
       
  1821     root.x = 0;
       
  1822     root.y = 0;
       
  1823     root.dx = size[0];
       
  1824     root.dy = size[1];
       
  1825     if (stickies) hierarchy.revalue(root);
       
  1826     scale([root], root.dx * root.dy / root.value);
       
  1827     (stickies ? stickify : squarify)(root);
       
  1828     if (sticky) stickies = nodes;
       
  1829     return nodes;
       
  1830   }
       
  1831 
       
  1832   treemap.size = function(x) {
       
  1833     if (!arguments.length) return size;
       
  1834     size = x;
       
  1835     return treemap;
       
  1836   };
       
  1837 
       
  1838   treemap.padding = function(x) {
       
  1839     if (!arguments.length) return padding;
       
  1840 
       
  1841     function padFunction(node) {
       
  1842       var p = x.call(treemap, node, node.depth);
       
  1843       return p == null
       
  1844           ? d3_layout_treemapPadNull(node)
       
  1845           : d3_layout_treemapPad(node, typeof p === "number" ? [p, p, p, p] : p);
       
  1846     }
       
  1847 
       
  1848     function padConstant(node) {
       
  1849       return d3_layout_treemapPad(node, x);
       
  1850     }
       
  1851 
       
  1852     var type;
       
  1853     pad = (padding = x) == null ? d3_layout_treemapPadNull
       
  1854         : (type = typeof x) === "function" ? padFunction
       
  1855         : type === "number" ? (x = [x, x, x, x], padConstant)
       
  1856         : padConstant;
       
  1857     return treemap;
       
  1858   };
       
  1859 
       
  1860   treemap.round = function(x) {
       
  1861     if (!arguments.length) return round != Number;
       
  1862     round = x ? Math.round : Number;
       
  1863     return treemap;
       
  1864   };
       
  1865 
       
  1866   treemap.sticky = function(x) {
       
  1867     if (!arguments.length) return sticky;
       
  1868     sticky = x;
       
  1869     stickies = null;
       
  1870     return treemap;
       
  1871   };
       
  1872 
       
  1873   treemap.ratio = function(x) {
       
  1874     if (!arguments.length) return ratio;
       
  1875     ratio = x;
       
  1876     return treemap;
       
  1877   };
       
  1878 
       
  1879   return d3_layout_hierarchyRebind(treemap, hierarchy);
       
  1880 };
       
  1881 
       
  1882 function d3_layout_treemapPadNull(node) {
       
  1883   return {x: node.x, y: node.y, dx: node.dx, dy: node.dy};
       
  1884 }
       
  1885 
       
  1886 function d3_layout_treemapPad(node, padding) {
       
  1887   var x = node.x + padding[3],
       
  1888       y = node.y + padding[0],
       
  1889       dx = node.dx - padding[1] - padding[3],
       
  1890       dy = node.dy - padding[0] - padding[2];
       
  1891   if (dx < 0) { x += dx / 2; dx = 0; }
       
  1892   if (dy < 0) { y += dy / 2; dy = 0; }
       
  1893   return {x: x, y: y, dx: dx, dy: dy};
       
  1894 }
       
  1895 })();