source: Dev/trunk/d3/d3.layout.js @ 185

Last change on this file since 185 was 76, checked in by fpvanagthoven, 14 years ago

d3

File size: 47.6 KB
Line 
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.
6d3.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
16function 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
33function 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
45function 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}
59d3.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    x = 0, i = -1; while (++i < n) {
117      x0 = x, j = -1; while (++j < n) {
118        var di = groupIndex[i],
119            dj = subgroupIndex[i][j],
120            v = matrix[di][dj];
121        subgroups[di + "-" + dj] = {
122          index: di,
123          subindex: dj,
124          startAngle: x,
125          endAngle: x += v * k,
126          value: v
127        };
128      }
129      groups.push({
130        index: di,
131        startAngle: x0,
132        endAngle: x,
133        value: (x - x0) / k
134      });
135      x += padding;
136    }
137
138    // Generate chords for each (non-empty) subgroup-subgroup link.
139    i = -1; while (++i < n) {
140      j = i - 1; while (++j < n) {
141        var source = subgroups[i + "-" + j],
142            target = subgroups[j + "-" + i];
143        if (source.value || target.value) {
144          chords.push(source.value < target.value
145              ? {source: target, target: source}
146              : {source: source, target: target})
147        }
148      }
149    }
150
151    if (sortChords) resort();
152  }
153
154  function resort() {
155    chords.sort(function(a, b) {
156      return sortChords(a.target.value, b.target.value);
157    });
158  }
159
160  chord.matrix = function(x) {
161    if (!arguments.length) return matrix;
162    n = (matrix = x) && matrix.length;
163    chords = groups = null;
164    return chord;
165  };
166
167  chord.padding = function(x) {
168    if (!arguments.length) return padding;
169    padding = x;
170    chords = groups = null;
171    return chord;
172  };
173
174  chord.sortGroups = function(x) {
175    if (!arguments.length) return sortGroups;
176    sortGroups = x;
177    chords = groups = null;
178    return chord;
179  };
180
181  chord.sortSubgroups = function(x) {
182    if (!arguments.length) return sortSubgroups;
183    sortSubgroups = x;
184    chords = null;
185    return chord;
186  };
187
188  chord.sortChords = function(x) {
189    if (!arguments.length) return sortChords;
190    sortChords = x;
191    if (chords) resort();
192    return chord;
193  };
194
195  chord.chords = function() {
196    if (!chords) relayout();
197    return chords;
198  };
199
200  chord.groups = function() {
201    if (!groups) relayout();
202    return groups;
203  };
204
205  return chord;
206};
207// A rudimentary force layout using Gauss-Seidel.
208d3.layout.force = function() {
209  var force = {},
210      event = d3.dispatch("tick"),
211      size = [1, 1],
212      alpha,
213      friction = .9,
214      linkDistance = d3_layout_forceLinkDistance,
215      linkStrength = d3_layout_forceLinkStrength,
216      charge = -30,
217      gravity = .1,
218      theta = .8,
219      interval,
220      nodes = [],
221      links = [],
222      distances,
223      strengths;
224
225  function repulse(node, kc) {
226    return function(quad, x1, y1, x2, y2) {
227      if (quad.point !== node) {
228        var dx = quad.cx - node.x,
229            dy = quad.cy - node.y,
230            dn = 1 / Math.sqrt(dx * dx + dy * dy);
231
232        /* Barnes-Hut criterion. */
233        if ((x2 - x1) * dn < theta) {
234          var k = kc * quad.count * dn * dn;
235          node.x += dx * k;
236          node.y += dy * k;
237          return true;
238        }
239
240        if (quad.point && isFinite(dn)) {
241          var k = kc * dn * dn;
242          node.x += dx * k;
243          node.y += dy * k;
244        }
245      }
246    };
247  }
248
249  function tick() {
250    var n = nodes.length,
251        m = links.length,
252        q = d3.geom.quadtree(nodes),
253        i, // current index
254        o, // current object
255        s, // current source
256        t, // current target
257        l, // current distance
258        x, // x-distance
259        y; // y-distance
260
261    // gauss-seidel relaxation for links
262    for (i = 0; i < m; ++i) {
263      o = links[i];
264      s = o.source;
265      t = o.target;
266      x = t.x - s.x;
267      y = t.y - s.y;
268      if (l = (x * x + y * y)) {
269        l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
270        x *= l;
271        y *= l;
272        t.x -= x;
273        t.y -= y;
274        s.x += x;
275        s.y += y;
276      }
277    }
278
279    // apply gravity forces
280    var kg = alpha * gravity;
281    x = size[0] / 2;
282    y = size[1] / 2;
283    i = -1; while (++i < n) {
284      o = nodes[i];
285      o.x += (x - o.x) * kg;
286      o.y += (y - o.y) * kg;
287    }
288
289    // compute quadtree center of mass
290    d3_layout_forceAccumulate(q);
291
292    // apply charge forces
293    var kc = alpha * charge;
294    i = -1; while (++i < n) {
295      q.visit(repulse(nodes[i], kc));
296    }
297
298    // position verlet integration
299    i = -1; while (++i < n) {
300      o = nodes[i];
301      if (o.fixed) {
302        o.x = o.px;
303        o.y = o.py;
304      } else {
305        o.x -= (o.px - (o.px = o.x)) * friction;
306        o.y -= (o.py - (o.py = o.y)) * friction;
307      }
308    }
309
310    event.tick.dispatch({type: "tick", alpha: alpha});
311
312    // simulated annealing, basically
313    return (alpha *= .99) < .005;
314  }
315
316  force.on = function(type, listener) {
317    event[type].add(listener);
318    return force;
319  };
320
321  force.nodes = function(x) {
322    if (!arguments.length) return nodes;
323    nodes = x;
324    return force;
325  };
326
327  force.links = function(x) {
328    if (!arguments.length) return links;
329    links = x;
330    return force;
331  };
332
333  force.size = function(x) {
334    if (!arguments.length) return size;
335    size = x;
336    return force;
337  };
338
339  force.linkDistance = function(x) {
340    if (!arguments.length) return linkDistance;
341    linkDistance = d3.functor(x);
342    return force;
343  };
344
345  // For backwards-compatibility.
346  force.distance = force.linkDistance;
347
348  force.linkStrength = function(x) {
349    if (!arguments.length) return linkStrength;
350    linkStrength = d3.functor(x);
351    return force;
352  };
353
354  force.friction = function(x) {
355    if (!arguments.length) return friction;
356    friction = x;
357    return force;
358  };
359
360  force.charge = function(x) {
361    if (!arguments.length) return charge;
362    charge = x;
363    return force;
364  };
365
366  force.gravity = function(x) {
367    if (!arguments.length) return gravity;
368    gravity = x;
369    return force;
370  };
371
372  force.theta = function(x) {
373    if (!arguments.length) return theta;
374    theta = x;
375    return force;
376  };
377
378  force.start = function() {
379    var i,
380        j,
381        n = nodes.length,
382        m = links.length,
383        w = size[0],
384        h = size[1],
385        neighbors,
386        o;
387
388    for (i = 0; i < n; ++i) {
389      (o = nodes[i]).index = i;
390    }
391
392    distances = [];
393    strengths = [];
394    for (i = 0; i < m; ++i) {
395      o = links[i];
396      if (typeof o.source == "number") o.source = nodes[o.source];
397      if (typeof o.target == "number") o.target = nodes[o.target];
398      distances[i] = linkDistance.call(this, o, i);
399      strengths[i] = linkStrength.call(this, o, i);
400    }
401
402    for (i = 0; i < n; ++i) {
403      o = nodes[i];
404      if (isNaN(o.x)) o.x = position("x", w);
405      if (isNaN(o.y)) o.y = position("y", h);
406      if (isNaN(o.px)) o.px = o.x;
407      if (isNaN(o.py)) o.py = o.y;
408    }
409
410    // initialize node position based on first neighbor
411    function position(dimension, size) {
412      var neighbors = neighbor(i),
413          j = -1,
414          m = neighbors.length,
415          x;
416      while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
417      return Math.random() * size;
418    }
419
420    // initialize neighbors lazily
421    function neighbor() {
422      if (!neighbors) {
423        neighbors = [];
424        for (j = 0; j < n; ++j) {
425          neighbors[j] = [];
426        }
427        for (j = 0; j < m; ++j) {
428          var o = links[j];
429          neighbors[o.source.index].push(o.target);
430          neighbors[o.target.index].push(o.source);
431        }
432      }
433      return neighbors[i];
434    }
435
436    return force.resume();
437  };
438
439  force.resume = function() {
440    alpha = .1;
441    d3.timer(tick);
442    return force;
443  };
444
445  force.stop = function() {
446    alpha = 0;
447    return force;
448  };
449
450  // use `node.call(force.drag)` to make nodes draggable
451  force.drag = function() {
452
453    this
454      .on("mouseover.force", d3_layout_forceDragOver)
455      .on("mouseout.force", d3_layout_forceDragOut)
456      .on("mousedown.force", dragdown)
457      .on("touchstart.force", dragdown);
458
459    d3.select(window)
460      .on("mousemove.force", d3_layout_forceDragMove)
461      .on("touchmove.force", d3_layout_forceDragMove)
462      .on("mouseup.force", d3_layout_forceDragUp, true)
463      .on("touchend.force", d3_layout_forceDragUp, true)
464      .on("click.force", d3_layout_forceDragClick, true);
465
466    return force;
467  };
468
469  function dragdown(d, i) {
470    var m = d3_layout_forcePoint(this.parentNode);
471    (d3_layout_forceDragNode = d).fixed = true;
472    d3_layout_forceDragMoved = false;
473    d3_layout_forceDragElement = this;
474    d3_layout_forceDragForce = force;
475    d3_layout_forceDragOffset = [m[0] - d.x, m[1] - d.y];
476    d3_layout_forceCancel();
477  }
478
479  return force;
480};
481
482var d3_layout_forceDragForce,
483    d3_layout_forceDragNode,
484    d3_layout_forceDragMoved,
485    d3_layout_forceDragOffset,
486    d3_layout_forceStopClick,
487    d3_layout_forceDragElement;
488
489function d3_layout_forceDragOver(d) {
490  d.fixed = true;
491}
492
493function d3_layout_forceDragOut(d) {
494  if (d !== d3_layout_forceDragNode) {
495    d.fixed = false;
496  }
497}
498
499function d3_layout_forcePoint(container) {
500  return d3.event.touches
501      ? d3.svg.touches(container)[0]
502      : d3.svg.mouse(container);
503}
504
505function d3_layout_forceDragMove() {
506  if (!d3_layout_forceDragNode) return;
507  var parent = d3_layout_forceDragElement.parentNode;
508
509  // O NOES! The drag element was removed from the DOM.
510  if (!parent) {
511    d3_layout_forceDragNode.fixed = false;
512    d3_layout_forceDragOffset = d3_layout_forceDragNode = d3_layout_forceDragElement = null;
513    return;
514  }
515
516  var m = d3_layout_forcePoint(parent);
517  d3_layout_forceDragMoved = true;
518  d3_layout_forceDragNode.px = m[0] - d3_layout_forceDragOffset[0];
519  d3_layout_forceDragNode.py = m[1] - d3_layout_forceDragOffset[1];
520  d3_layout_forceCancel();
521  d3_layout_forceDragForce.resume(); // restart annealing
522}
523
524function d3_layout_forceDragUp() {
525  if (!d3_layout_forceDragNode) return;
526
527  // If the node was moved, prevent the mouseup from propagating.
528  // Also prevent the subsequent click from propagating (e.g., for anchors).
529  if (d3_layout_forceDragMoved) {
530    d3_layout_forceStopClick = true;
531    d3_layout_forceCancel();
532  }
533
534  // Don't trigger this for touchend.
535  if (d3.event.type === "mouseup") {
536    d3_layout_forceDragMove();
537  }
538
539  d3_layout_forceDragNode.fixed = false;
540  d3_layout_forceDragForce =
541  d3_layout_forceDragOffset =
542  d3_layout_forceDragNode =
543  d3_layout_forceDragElement = null;
544}
545
546function d3_layout_forceDragClick() {
547  if (d3_layout_forceStopClick) {
548    d3_layout_forceCancel();
549    d3_layout_forceStopClick = false;
550  }
551}
552
553function d3_layout_forceCancel() {
554  d3.event.stopPropagation();
555  d3.event.preventDefault();
556}
557
558function d3_layout_forceAccumulate(quad) {
559  var cx = 0,
560      cy = 0;
561  quad.count = 0;
562  if (!quad.leaf) {
563    var nodes = quad.nodes,
564        n = nodes.length,
565        i = -1,
566        c;
567    while (++i < n) {
568      c = nodes[i];
569      if (c == null) continue;
570      d3_layout_forceAccumulate(c);
571      quad.count += c.count;
572      cx += c.count * c.cx;
573      cy += c.count * c.cy;
574    }
575  }
576  if (quad.point) {
577    // jitter internal nodes that are coincident
578    if (!quad.leaf) {
579      quad.point.x += Math.random() - .5;
580      quad.point.y += Math.random() - .5;
581    }
582    quad.count++;
583    cx += quad.point.x;
584    cy += quad.point.y;
585  }
586  quad.cx = cx / quad.count;
587  quad.cy = cy / quad.count;
588}
589
590function d3_layout_forceLinkDistance(link) {
591  return 20;
592}
593
594function d3_layout_forceLinkStrength(link) {
595  return 1;
596}
597d3.layout.partition = function() {
598  var hierarchy = d3.layout.hierarchy(),
599      size = [1, 1]; // width, height
600
601  function position(node, x, dx, dy) {
602    var children = node.children;
603    node.x = x;
604    node.y = node.depth * dy;
605    node.dx = dx;
606    node.dy = dy;
607    if (children) {
608      var i = -1,
609          n = children.length,
610          c,
611          d;
612      dx /= node.value;
613      while (++i < n) {
614        position(c = children[i], x, d = c.value * dx, dy);
615        x += d;
616      }
617    }
618  }
619
620  function depth(node) {
621    var children = node.children,
622        d = 0;
623    if (children) {
624      var i = -1,
625          n = children.length;
626      while (++i < n) d = Math.max(d, depth(children[i]));
627    }
628    return 1 + d;
629  }
630
631  function partition(d, i) {
632    var nodes = hierarchy.call(this, d, i);
633    position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
634    return nodes;
635  }
636
637  partition.size = function(x) {
638    if (!arguments.length) return size;
639    size = x;
640    return partition;
641  };
642
643  return d3_layout_hierarchyRebind(partition, hierarchy);
644};
645d3.layout.pie = function() {
646  var value = Number,
647      sort = null,
648      startAngle = 0,
649      endAngle = 2 * Math.PI;
650
651  function pie(data, i) {
652
653    // Compute the start angle.
654    var a = +(typeof startAngle === "function"
655        ? startAngle.apply(this, arguments)
656        : startAngle);
657
658    // Compute the angular range (end - start).
659    var k = (typeof endAngle === "function"
660        ? endAngle.apply(this, arguments)
661        : endAngle) - startAngle;
662
663    // Optionally sort the data.
664    var index = d3.range(data.length);
665    if (sort != null) index.sort(function(i, j) {
666      return sort(data[i], data[j]);
667    });
668
669    // Compute the numeric values for each data element.
670    var values = data.map(value);
671
672    // Convert k into a scale factor from value to angle, using the sum.
673    k /= values.reduce(function(p, d) { return p + d; }, 0);
674
675    // Compute the arcs!
676    var arcs = index.map(function(i) {
677      return {
678        data: data[i],
679        value: d = values[i],
680        startAngle: a,
681        endAngle: a += d * k
682      };
683    });
684
685    // Return the arcs in the original data's order.
686    return data.map(function(d, i) {
687      return arcs[index[i]];
688    });
689  }
690
691  /**
692   * Specifies the value function *x*, which returns a nonnegative numeric value
693   * for each datum. The default value function is `Number`. The value function
694   * is passed two arguments: the current datum and the current index.
695   */
696  pie.value = function(x) {
697    if (!arguments.length) return value;
698    value = x;
699    return pie;
700  };
701
702  /**
703   * Specifies a sort comparison operator *x*. The comparator is passed two data
704   * elements from the data array, a and b; it returns a negative value if a is
705   * less than b, a positive value if a is greater than b, and zero if a equals
706   * b.
707   */
708  pie.sort = function(x) {
709    if (!arguments.length) return sort;
710    sort = x;
711    return pie;
712  };
713
714  /**
715   * Specifies the overall start angle of the pie chart. Defaults to 0. The
716   * start angle can be specified either as a constant or as a function; in the
717   * case of a function, it is evaluated once per array (as opposed to per
718   * element).
719   */
720  pie.startAngle = function(x) {
721    if (!arguments.length) return startAngle;
722    startAngle = x;
723    return pie;
724  };
725
726  /**
727   * Specifies the overall end angle of the pie chart. Defaults to 2π. The
728   * end angle can be specified either as a constant or as a function; in the
729   * case of a function, it is evaluated once per array (as opposed to per
730   * element).
731   */
732  pie.endAngle = function(x) {
733    if (!arguments.length) return endAngle;
734    endAngle = x;
735    return pie;
736  };
737
738  return pie;
739};
740// data is two-dimensional array of x,y; we populate y0
741d3.layout.stack = function() {
742  var values = Object,
743      order = d3_layout_stackOrders["default"],
744      offset = d3_layout_stackOffsets["zero"],
745      out = d3_layout_stackOut,
746      x = d3_layout_stackX,
747      y = d3_layout_stackY;
748
749  function stack(data, index) {
750
751    // Convert series to canonical two-dimensional representation.
752    var series = data.map(function(d, i) {
753      return values.call(stack, d, i);
754    });
755
756    // Convert each series to canonical [[x,y]] representation.
757    var points = series.map(function(d, i) {
758      return d.map(function(v, i) {
759        return [x.call(stack, v, i), y.call(stack, v, i)];
760      });
761    });
762
763    // Compute the order of series, and permute them.
764    var orders = order.call(stack, points, index);
765    series = d3.permute(series, orders);
766    points = d3.permute(points, orders);
767
768    // Compute the baseline

769    var offsets = offset.call(stack, points, index);
770
771    // And propagate it to other series.
772    var n = series.length,
773        m = series[0].length,
774        i,
775        j,
776        o;
777    for (j = 0; j < m; ++j) {
778      out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
779      for (i = 1; i < n; ++i) {
780        out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
781      }
782    }
783
784    return data;
785  }
786
787  stack.values = function(x) {
788    if (!arguments.length) return values;
789    values = x;
790    return stack;
791  };
792
793  stack.order = function(x) {
794    if (!arguments.length) return order;
795    order = typeof x === "function" ? x : d3_layout_stackOrders[x];
796    return stack;
797  };
798
799  stack.offset = function(x) {
800    if (!arguments.length) return offset;
801    offset = typeof x === "function" ? x : d3_layout_stackOffsets[x];
802    return stack;
803  };
804
805  stack.x = function(z) {
806    if (!arguments.length) return x;
807    x = z;
808    return stack;
809  };
810
811  stack.y = function(z) {
812    if (!arguments.length) return y;
813    y = z;
814    return stack;
815  };
816
817  stack.out = function(z) {
818    if (!arguments.length) return out;
819    out = z;
820    return stack;
821  };
822
823  return stack;
824}
825
826function d3_layout_stackX(d) {
827  return d.x;
828}
829
830function d3_layout_stackY(d) {
831  return d.y;
832}
833
834function d3_layout_stackOut(d, y0, y) {
835  d.y0 = y0;
836  d.y = y;
837}
838
839var d3_layout_stackOrders = {
840
841  "inside-out": function(data) {
842    var n = data.length,
843        i,
844        j,
845        max = data.map(d3_layout_stackMaxIndex),
846        sums = data.map(d3_layout_stackReduceSum),
847        index = d3.range(n).sort(function(a, b) { return max[a] - max[b]; }),
848        top = 0,
849        bottom = 0,
850        tops = [],
851        bottoms = [];
852    for (i = 0; i < n; ++i) {
853      j = index[i];
854      if (top < bottom) {
855        top += sums[j];
856        tops.push(j);
857      } else {
858        bottom += sums[j];
859        bottoms.push(j);
860      }
861    }
862    return bottoms.reverse().concat(tops);
863  },
864
865  "reverse": function(data) {
866    return d3.range(data.length).reverse();
867  },
868
869  "default": function(data) {
870    return d3.range(data.length);
871  }
872
873};
874
875var d3_layout_stackOffsets = {
876
877  "silhouette": function(data) {
878    var n = data.length,
879        m = data[0].length,
880        sums = [],
881        max = 0,
882        i,
883        j,
884        o,
885        y0 = [];
886    for (j = 0; j < m; ++j) {
887      for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
888      if (o > max) max = o;
889      sums.push(o);
890    }
891    for (j = 0; j < m; ++j) {
892      y0[j] = (max - sums[j]) / 2;
893    }
894    return y0;
895  },
896
897  "wiggle": function(data) {
898    var n = data.length,
899        x = data[0],
900        m = x.length,
901        max = 0,
902        i,
903        j,
904        k,
905        s1,
906        s2,
907        s3,
908        dx,
909        o,
910        o0,
911        y0 = [];
912    y0[0] = o = o0 = 0;
913    for (j = 1; j < m; ++j) {
914      for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
915      for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
916        for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
917          s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
918        }
919        s2 += s3 * data[i][j][1];
920      }
921      y0[j] = o -= s1 ? s2 / s1 * dx : 0;
922      if (o < o0) o0 = o;
923    }
924    for (j = 0; j < m; ++j) y0[j] -= o0;
925    return y0;
926  },
927
928  "expand": function(data) {
929    var n = data.length,
930        m = data[0].length,
931        k = 1 / n,
932        i,
933        j,
934        o,
935        y0 = [];
936    for (j = 0; j < m; ++j) {
937      for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
938      if (o) for (i = 0; i < n; i++) data[i][j][1] /= o;
939      else for (i = 0; i < n; i++) data[i][j][1] = k;
940    }
941    for (j = 0; j < m; ++j) y0[j] = 0;
942    return y0;
943  },
944
945  "zero": function(data) {
946    var j = -1,
947        m = data[0].length,
948        y0 = [];
949    while (++j < m) y0[j] = 0;
950    return y0;
951  }
952
953};
954
955function d3_layout_stackMaxIndex(array) {
956  var i = 1,
957      j = 0,
958      v = array[0][1],
959      k,
960      n = array.length;
961  for (; i < n; ++i) {
962    if ((k = array[i][1]) > v) {
963      j = i;
964      v = k;
965    }
966  }
967  return j;
968}
969
970function d3_layout_stackReduceSum(d) {
971  return d.reduce(d3_layout_stackSum, 0);
972}
973
974function d3_layout_stackSum(p, d) {
975  return p + d[1];
976}
977d3.layout.histogram = function() {
978  var frequency = true,
979      valuer = Number,
980      ranger = d3_layout_histogramRange,
981      binner = d3_layout_histogramBinSturges;
982
983  function histogram(data, i) {
984    var bins = [],
985        values = data.map(valuer, this),
986        range = ranger.call(this, values, i),
987        thresholds = binner.call(this, range, values, i),
988        bin,
989        i = -1,
990        n = values.length,
991        m = thresholds.length - 1,
992        k = frequency ? 1 : 1 / n,
993        x;
994
995    // Initialize the bins.
996    while (++i < m) {
997      bin = bins[i] = [];
998      bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
999      bin.y = 0;
1000    }
1001
1002    // Fill the bins, ignoring values outside the range.
1003    i = -1; while(++i < n) {
1004      x = values[i];
1005      if ((x >= range[0]) && (x <= range[1])) {
1006        bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
1007        bin.y += k;
1008        bin.push(data[i]);
1009      }
1010    }
1011
1012    return bins;
1013  }
1014
1015  // Specifies how to extract a value from the associated data. The default
1016  // value function is `Number`, which is equivalent to the identity function.
1017  histogram.value = function(x) {
1018    if (!arguments.length) return valuer;
1019    valuer = x;
1020    return histogram;
1021  };
1022
1023  // Specifies the range of the histogram. Values outside the specified range
1024  // will be ignored. The argument `x` may be specified either as a two-element
1025  // array representing the minimum and maximum value of the range, or as a
1026  // function that returns the range given the array of values and the current
1027  // index `i`. The default range is the extent (minimum and maximum) of the
1028  // values.
1029  histogram.range = function(x) {
1030    if (!arguments.length) return ranger;
1031    ranger = d3.functor(x);
1032    return histogram;
1033  };
1034
1035  // Specifies how to bin values in the histogram. The argument `x` may be
1036  // specified as a number, in which case the range of values will be split
1037  // uniformly into the given number of bins. Or, `x` may be an array of
1038  // threshold values, defining the bins; the specified array must contain the
1039  // rightmost (upper) value, thus specifying n + 1 values for n bins. Or, `x`
1040  // may be a function which is evaluated, being passed the range, the array of
1041  // values, and the current index `i`, returning an array of thresholds. The
1042  // default bin function will divide the values into uniform bins using
1043  // Sturges' formula.
1044  histogram.bins = function(x) {
1045    if (!arguments.length) return binner;
1046    binner = typeof x === "number"
1047        ? function(range) { return d3_layout_histogramBinFixed(range, x); }
1048        : d3.functor(x);
1049    return histogram;
1050  };
1051
1052  // Specifies whether the histogram's `y` value is a count (frequency) or a
1053  // probability (density). The default value is true.
1054  histogram.frequency = function(x) {
1055    if (!arguments.length) return frequency;
1056    frequency = !!x;
1057    return histogram;
1058  };
1059
1060  return histogram;
1061};
1062
1063function d3_layout_histogramBinSturges(range, values) {
1064  return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
1065}
1066
1067function d3_layout_histogramBinFixed(range, n) {
1068  var x = -1,
1069      b = +range[0],
1070      m = (range[1] - b) / n,
1071      f = [];
1072  while (++x <= n) f[x] = m * x + b;
1073  return f;
1074}
1075
1076function d3_layout_histogramRange(values) {
1077  return [d3.min(values), d3.max(values)];
1078}
1079d3.layout.hierarchy = function() {
1080  var sort = d3_layout_hierarchySort,
1081      children = d3_layout_hierarchyChildren,
1082      value = d3_layout_hierarchyValue;
1083
1084  // Recursively compute the node depth and value.
1085  // Also converts the data representation into a standard hierarchy structure.
1086  function recurse(data, depth, nodes) {
1087    var childs = children.call(hierarchy, data, depth),
1088        node = d3_layout_hierarchyInline ? data : {data: data};
1089    node.depth = depth;
1090    nodes.push(node);
1091    if (childs) {
1092      var i = -1,
1093          n = childs.length,
1094          c = node.children = [],
1095          v = 0,
1096          j = depth + 1;
1097      while (++i < n) {
1098        d = recurse(childs[i], j, nodes);
1099        d.parent = node;
1100        c.push(d);
1101        v += d.value;
1102      }
1103      if (sort) c.sort(sort);
1104      if (value) node.value = v;
1105    } else if (value) {
1106      node.value = value.call(hierarchy, data, depth);
1107    }
1108    return node;
1109  }
1110
1111  // Recursively re-evaluates the node value.
1112  function revalue(node, depth) {
1113    var children = node.children,
1114        v = 0;
1115    if (children) {
1116      var i = -1,
1117          n = children.length,
1118          j = depth + 1;
1119      while (++i < n) v += revalue(children[i], j);
1120    } else if (value) {
1121      v = value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth);
1122    }
1123    if (value) node.value = v;
1124    return v;
1125  }
1126
1127  function hierarchy(d) {
1128    var nodes = [];
1129    recurse(d, 0, nodes);
1130    return nodes;
1131  }
1132
1133  hierarchy.sort = function(x) {
1134    if (!arguments.length) return sort;
1135    sort = x;
1136    return hierarchy;
1137  };
1138
1139  hierarchy.children = function(x) {
1140    if (!arguments.length) return children;
1141    children = x;
1142    return hierarchy;
1143  };
1144
1145  hierarchy.value = function(x) {
1146    if (!arguments.length) return value;
1147    value = x;
1148    return hierarchy;
1149  };
1150
1151  // Re-evaluates the `value` property for the specified hierarchy.
1152  hierarchy.revalue = function(root) {
1153    revalue(root, 0);
1154    return root;
1155  };
1156
1157  return hierarchy;
1158};
1159
1160// A method assignment helper for hierarchy subclasses.
1161function d3_layout_hierarchyRebind(object, hierarchy) {
1162  object.sort = d3.rebind(object, hierarchy.sort);
1163  object.children = d3.rebind(object, hierarchy.children);
1164  object.links = d3_layout_hierarchyLinks;
1165  object.value = d3.rebind(object, hierarchy.value);
1166
1167  // If the new API is used, enabling inlining.
1168  object.nodes = function(d) {
1169    d3_layout_hierarchyInline = true;
1170    return (object.nodes = object)(d);
1171  };
1172
1173  return object;
1174}
1175
1176function d3_layout_hierarchyChildren(d) {
1177  return d.children;
1178}
1179
1180function d3_layout_hierarchyValue(d) {
1181  return d.value;
1182}
1183
1184function d3_layout_hierarchySort(a, b) {
1185  return b.value - a.value;
1186}
1187
1188// Returns an array source+target objects for the specified nodes.
1189function d3_layout_hierarchyLinks(nodes) {
1190  return d3.merge(nodes.map(function(parent) {
1191    return (parent.children || []).map(function(child) {
1192      return {source: parent, target: child};
1193    });
1194  }));
1195}
1196
1197// For backwards-compatibility, don't enable inlining by default.
1198var d3_layout_hierarchyInline = false;
1199d3.layout.pack = function() {
1200  var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort),
1201      size = [1, 1];
1202
1203  function pack(d, i) {
1204    var nodes = hierarchy.call(this, d, i),
1205        root = nodes[0];
1206
1207    // Recursively compute the layout.
1208    root.x = 0;
1209    root.y = 0;
1210    d3_layout_packTree(root);
1211
1212    // Scale the layout to fit the requested size.
1213    var w = size[0],
1214        h = size[1],
1215        k = 1 / Math.max(2 * root.r / w, 2 * root.r / h);
1216    d3_layout_packTransform(root, w / 2, h / 2, k);
1217
1218    return nodes;
1219  }
1220
1221  pack.size = function(x) {
1222    if (!arguments.length) return size;
1223    size = x;
1224    return pack;
1225  };
1226
1227  return d3_layout_hierarchyRebind(pack, hierarchy);
1228};
1229
1230function d3_layout_packSort(a, b) {
1231  return a.value - b.value;
1232}
1233
1234function d3_layout_packInsert(a, b) {
1235  var c = a._pack_next;
1236  a._pack_next = b;
1237  b._pack_prev = a;
1238  b._pack_next = c;
1239  c._pack_prev = b;
1240}
1241
1242function d3_layout_packSplice(a, b) {
1243  a._pack_next = b;
1244  b._pack_prev = a;
1245}
1246
1247function d3_layout_packIntersects(a, b) {
1248  var dx = b.x - a.x,
1249      dy = b.y - a.y,
1250      dr = a.r + b.r;
1251  return (dr * dr - dx * dx - dy * dy) > .001; // within epsilon
1252}
1253
1254function d3_layout_packCircle(nodes) {
1255  var xMin = Infinity,
1256      xMax = -Infinity,
1257      yMin = Infinity,
1258      yMax = -Infinity,
1259      n = nodes.length,
1260      a, b, c, j, k;
1261
1262  function bound(node) {
1263    xMin = Math.min(node.x - node.r, xMin);
1264    xMax = Math.max(node.x + node.r, xMax);
1265    yMin = Math.min(node.y - node.r, yMin);
1266    yMax = Math.max(node.y + node.r, yMax);
1267  }
1268
1269  // Create node links.
1270  nodes.forEach(d3_layout_packLink);
1271
1272  // Create first node.
1273  a = nodes[0];
1274  a.x = -a.r;
1275  a.y = 0;
1276  bound(a);
1277
1278  // Create second node.
1279  if (n > 1) {
1280    b = nodes[1];
1281    b.x = b.r;
1282    b.y = 0;
1283    bound(b);
1284
1285    // Create third node and build chain.
1286    if (n > 2) {
1287      c = nodes[2];
1288      d3_layout_packPlace(a, b, c);
1289      bound(c);
1290      d3_layout_packInsert(a, c);
1291      a._pack_prev = c;
1292      d3_layout_packInsert(c, b);
1293      b = a._pack_next;
1294
1295      // Now iterate through the rest.
1296      for (var i = 3; i < n; i++) {
1297        d3_layout_packPlace(a, b, c = nodes[i]);
1298
1299        // Search for the closest intersection.
1300        var isect = 0, s1 = 1, s2 = 1;
1301        for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
1302          if (d3_layout_packIntersects(j, c)) {
1303            isect = 1;
1304            break;
1305          }
1306        }
1307        if (isect == 1) {
1308          for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
1309            if (d3_layout_packIntersects(k, c)) {
1310              if (s2 < s1) {
1311                isect = -1;
1312                j = k;
1313              }
1314              break;
1315            }
1316          }
1317        }
1318
1319        // Update node chain.
1320        if (isect == 0) {
1321          d3_layout_packInsert(a, c);
1322          b = c;
1323          bound(c);
1324        } else if (isect > 0) {
1325          d3_layout_packSplice(a, j);
1326          b = j;
1327          i--;
1328        } else { // isect < 0
1329          d3_layout_packSplice(j, b);
1330          a = j;
1331          i--;
1332        }
1333      }
1334    }
1335  }
1336
1337  // Re-center the circles and return the encompassing radius.
1338  var cx = (xMin + xMax) / 2,
1339      cy = (yMin + yMax) / 2,
1340      cr = 0;
1341  for (var i = 0; i < n; i++) {
1342    var node = nodes[i];
1343    node.x -= cx;
1344    node.y -= cy;
1345    cr = Math.max(cr, node.r + Math.sqrt(node.x * node.x + node.y * node.y));
1346  }
1347
1348  // Remove node links.
1349  nodes.forEach(d3_layout_packUnlink);
1350
1351  return cr;
1352}
1353
1354function d3_layout_packLink(node) {
1355  node._pack_next = node._pack_prev = node;
1356}
1357
1358function d3_layout_packUnlink(node) {
1359  delete node._pack_next;
1360  delete node._pack_prev;
1361}
1362
1363function d3_layout_packTree(node) {
1364  var children = node.children;
1365  if (children) {
1366    children.forEach(d3_layout_packTree);
1367    node.r = d3_layout_packCircle(children);
1368  } else {
1369    node.r = Math.sqrt(node.value);
1370  }
1371}
1372
1373function d3_layout_packTransform(node, x, y, k) {
1374  var children = node.children;
1375  node.x = (x += k * node.x);
1376  node.y = (y += k * node.y);
1377  node.r *= k;
1378  if (children) {
1379    var i = -1, n = children.length;
1380    while (++i < n) d3_layout_packTransform(children[i], x, y, k);
1381  }
1382}
1383
1384function d3_layout_packPlace(a, b, c) {
1385  var da = b.r + c.r,
1386      db = a.r + c.r,
1387      dx = b.x - a.x,
1388      dy = b.y - a.y,
1389      dc = Math.sqrt(dx * dx + dy * dy),
1390      cos = (db * db + dc * dc - da * da) / (2 * db * dc),
1391      theta = Math.acos(cos),
1392      x = cos * db,
1393      h = Math.sin(theta) * db;
1394  dx /= dc;
1395  dy /= dc;
1396  c.x = a.x + x * dx + h * dy;
1397  c.y = a.y + x * dy - h * dx;
1398}
1399// Implements a hierarchical layout using the cluster (or dendogram) algorithm.
1400d3.layout.cluster = function() {
1401  var hierarchy = d3.layout.hierarchy().sort(null).value(null),
1402      separation = d3_layout_treeSeparation,
1403      size = [1, 1]; // width, height
1404
1405  function cluster(d, i) {
1406    var nodes = hierarchy.call(this, d, i),
1407        root = nodes[0],
1408        previousNode,
1409        x = 0,
1410        kx,
1411        ky;
1412
1413    // First walk, computing the initial x & y values.
1414    d3_layout_treeVisitAfter(root, function(node) {
1415      if (node.children) {
1416        node.x = d3_layout_clusterX(node.children);
1417        node.y = d3_layout_clusterY(node.children);
1418      } else {
1419        node.x = previousNode ? x += separation(node, previousNode) : 0;
1420        node.y = 0;
1421        previousNode = node;
1422      }
1423    });
1424
1425    // Compute the left-most, right-most, and depth-most nodes for extents.
1426    var left = d3_layout_clusterLeft(root),
1427        right = d3_layout_clusterRight(root),
1428        x0 = left.x - separation(left, right) / 2,
1429        x1 = right.x + separation(right, left) / 2;
1430
1431    // Second walk, normalizing x & y to the desired size.
1432    d3_layout_treeVisitAfter(root, function(node) {
1433      node.x = (node.x - x0) / (x1 - x0) * size[0];
1434      node.y = (1 - node.y / root.y) * size[1];
1435    });
1436
1437    return nodes;
1438  }
1439
1440  cluster.separation = function(x) {
1441    if (!arguments.length) return separation;
1442    separation = x;
1443    return cluster;
1444  };
1445
1446  cluster.size = function(x) {
1447    if (!arguments.length) return size;
1448    size = x;
1449    return cluster;
1450  };
1451
1452  return d3_layout_hierarchyRebind(cluster, hierarchy);
1453};
1454
1455function d3_layout_clusterY(children) {
1456  return 1 + d3.max(children, function(child) {
1457    return child.y;
1458  });
1459}
1460
1461function d3_layout_clusterX(children) {
1462  return children.reduce(function(x, child) {
1463    return x + child.x;
1464  }, 0) / children.length;
1465}
1466
1467function d3_layout_clusterLeft(node) {
1468  var children = node.children;
1469  return children ? d3_layout_clusterLeft(children[0]) : node;
1470}
1471
1472function d3_layout_clusterRight(node) {
1473  var children = node.children;
1474  return children ? d3_layout_clusterRight(children[children.length - 1]) : node;
1475}
1476// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
1477d3.layout.tree = function() {
1478  var hierarchy = d3.layout.hierarchy().sort(null).value(null),
1479      separation = d3_layout_treeSeparation,
1480      size = [1, 1]; // width, height
1481
1482  function tree(d, i) {
1483    var nodes = hierarchy.call(this, d, i),
1484        root = nodes[0];
1485
1486    function firstWalk(node, previousSibling) {
1487      var children = node.children,
1488          layout = node._tree;
1489      if (children) {
1490        var n = children.length,
1491            firstChild = children[0],
1492            previousChild,
1493            ancestor = firstChild,
1494            child,
1495            i = -1;
1496        while (++i < n) {
1497          child = children[i];
1498          firstWalk(child, previousChild);
1499          ancestor = apportion(child, previousChild, ancestor);
1500          previousChild = child;
1501        }
1502        d3_layout_treeShift(node);
1503        var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
1504        if (previousSibling) {
1505          layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
1506          layout.mod = layout.prelim - midpoint;
1507        } else {
1508          layout.prelim = midpoint;
1509        }
1510      } else {
1511        if (previousSibling) {
1512          layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
1513        }
1514      }
1515    }
1516
1517    function secondWalk(node, x) {
1518      node.x = node._tree.prelim + x;
1519      var children = node.children;
1520      if (children) {
1521        var i = -1,
1522            n = children.length;
1523        x += node._tree.mod;
1524        while (++i < n) {
1525          secondWalk(children[i], x);
1526        }
1527      }
1528    }
1529
1530    function apportion(node, previousSibling, ancestor) {
1531      if (previousSibling) {
1532        var vip = node,
1533            vop = node,
1534            vim = previousSibling,
1535            vom = node.parent.children[0],
1536            sip = vip._tree.mod,
1537            sop = vop._tree.mod,
1538            sim = vim._tree.mod,
1539            som = vom._tree.mod,
1540            shift;
1541        while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
1542          vom = d3_layout_treeLeft(vom);
1543          vop = d3_layout_treeRight(vop);
1544          vop._tree.ancestor = node;
1545          shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
1546          if (shift > 0) {
1547            d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
1548            sip += shift;
1549            sop += shift;
1550          }
1551          sim += vim._tree.mod;
1552          sip += vip._tree.mod;
1553          som += vom._tree.mod;
1554          sop += vop._tree.mod;
1555        }
1556        if (vim && !d3_layout_treeRight(vop)) {
1557          vop._tree.thread = vim;
1558          vop._tree.mod += sim - sop;
1559        }
1560        if (vip && !d3_layout_treeLeft(vom)) {
1561          vom._tree.thread = vip;
1562          vom._tree.mod += sip - som;
1563          ancestor = node;
1564        }
1565      }
1566      return ancestor;
1567    }
1568
1569    // Initialize temporary layout variables.
1570    d3_layout_treeVisitAfter(root, function(node, previousSibling) {
1571      node._tree = {
1572        ancestor: node,
1573        prelim: 0,
1574        mod: 0,
1575        change: 0,
1576        shift: 0,
1577        number: previousSibling ? previousSibling._tree.number + 1 : 0
1578      };
1579    });
1580
1581    // Compute the layout using Buchheim et al.'s algorithm.
1582    firstWalk(root);
1583    secondWalk(root, -root._tree.prelim);
1584
1585    // Compute the left-most, right-most, and depth-most nodes for extents.
1586    var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost),
1587        right = d3_layout_treeSearch(root, d3_layout_treeRightmost),
1588        deep = d3_layout_treeSearch(root, d3_layout_treeDeepest),
1589        x0 = left.x - separation(left, right) / 2,
1590        x1 = right.x + separation(right, left) / 2,
1591        y1 = deep.depth || 1;
1592
1593    // Clear temporary layout variables; transform x and y.
1594    d3_layout_treeVisitAfter(root, function(node) {
1595      node.x = (node.x - x0) / (x1 - x0) * size[0];
1596      node.y = node.depth / y1 * size[1];
1597      delete node._tree;
1598    });
1599
1600    return nodes;
1601  }
1602
1603  tree.separation = function(x) {
1604    if (!arguments.length) return separation;
1605    separation = x;
1606    return tree;
1607  };
1608
1609  tree.size = function(x) {
1610    if (!arguments.length) return size;
1611    size = x;
1612    return tree;
1613  };
1614
1615  return d3_layout_hierarchyRebind(tree, hierarchy);
1616};
1617
1618function d3_layout_treeSeparation(a, b) {
1619  return a.parent == b.parent ? 1 : 2;
1620}
1621
1622// function d3_layout_treeSeparationRadial(a, b) {
1623//   return (a.parent == b.parent ? 1 : 2) / a.depth;
1624// }
1625
1626function d3_layout_treeLeft(node) {
1627  return node.children ? node.children[0] : node._tree.thread;
1628}
1629
1630function d3_layout_treeRight(node) {
1631  return node.children ? node.children[node.children.length - 1] : node._tree.thread;
1632}
1633
1634function d3_layout_treeSearch(node, compare) {
1635  var children = node.children;
1636  if (children) {
1637    var child,
1638        n = children.length,
1639        i = -1;
1640    while (++i < n) {
1641      if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
1642        node = child;
1643      }
1644    }
1645  }
1646  return node;
1647}
1648
1649function d3_layout_treeRightmost(a, b) {
1650  return a.x - b.x;
1651}
1652
1653function d3_layout_treeLeftmost(a, b) {
1654  return b.x - a.x;
1655}
1656
1657function d3_layout_treeDeepest(a, b) {
1658  return a.depth - b.depth;
1659}
1660
1661function d3_layout_treeVisitAfter(node, callback) {
1662  function visit(node, previousSibling) {
1663    var children = node.children;
1664    if (children) {
1665      var child,
1666          previousChild = null,
1667          i = -1,
1668          n = children.length;
1669      while (++i < n) {
1670        child = children[i];
1671        visit(child, previousChild);
1672        previousChild = child;
1673      }
1674    }
1675    callback(node, previousSibling);
1676  }
1677  visit(node, null);
1678}
1679
1680function d3_layout_treeShift(node) {
1681  var shift = 0,
1682      change = 0,
1683      children = node.children,
1684      i = children.length,
1685      child;
1686  while (--i >= 0) {
1687    child = children[i]._tree;
1688    child.prelim += shift;
1689    child.mod += shift;
1690    shift += child.shift + (change += child.change);
1691  }
1692}
1693
1694function d3_layout_treeMove(ancestor, node, shift) {
1695  ancestor = ancestor._tree;
1696  node = node._tree;
1697  var change = shift / (node.number - ancestor.number);
1698  ancestor.change += change;
1699  node.change -= change;
1700  node.shift += shift;
1701  node.prelim += shift;
1702  node.mod += shift;
1703}
1704
1705function d3_layout_treeAncestor(vim, node, ancestor) {
1706  return vim._tree.ancestor.parent == node.parent
1707      ? vim._tree.ancestor
1708      : ancestor;
1709}
1710// Squarified Treemaps by Mark Bruls, Kees Huizing, and Jarke J. van Wijk
1711// Modified to support a target aspect ratio by Jeff Heer
1712d3.layout.treemap = function() {
1713  var hierarchy = d3.layout.hierarchy(),
1714      round = Math.round,
1715      size = [1, 1], // width, height
1716      padding = null,
1717      pad = d3_layout_treemapPadNull,
1718      sticky = false,
1719      stickies,
1720      ratio = 0.5 * (1 + Math.sqrt(5)); // golden ratio
1721
1722  // Compute the area for each child based on value & scale.
1723  function scale(children, k) {
1724    var i = -1,
1725        n = children.length,
1726        child,
1727        area;
1728    while (++i < n) {
1729      area = (child = children[i]).value * (k < 0 ? 0 : k);
1730      child.area = isNaN(area) || area <= 0 ? 0 : area;
1731    }
1732  }
1733
1734  // Recursively arranges the specified node's children into squarified rows.
1735  function squarify(node) {
1736    if (!node.children) return;
1737    var rect = pad(node),
1738        row = [],
1739        children = node.children.slice(), // copy-on-write
1740        child,
1741        best = Infinity, // the best row score so far
1742        score, // the current row score
1743        u = Math.min(rect.dx, rect.dy), // initial orientation
1744        n;
1745    scale(children, rect.dx * rect.dy / node.value);
1746    row.area = 0;
1747    while ((n = children.length) > 0) {
1748      row.push(child = children[n - 1]);
1749      row.area += child.area;
1750      if ((score = worst(row, u)) <= best) { // continue with this orientation
1751        children.pop();
1752        best = score;
1753      } else { // abort, and try a different orientation
1754        row.area -= row.pop().area;
1755        position(row, u, rect, false);
1756        u = Math.min(rect.dx, rect.dy);
1757        row.length = row.area = 0;
1758        best = Infinity;
1759      }
1760    }
1761    if (row.length) {
1762      position(row, u, rect, true);
1763      row.length = row.area = 0;
1764    }
1765    node.children.forEach(squarify);
1766  }
1767
1768  // Recursively resizes the specified node's children into existing rows.
1769  // Preserves the existing layout!
1770  function stickify(node) {
1771    if (!node.children) return;
1772    var rect = pad(node),
1773        children = node.children.slice(), // copy-on-write
1774        child,
1775        row = [];
1776    scale(children, rect.dx * rect.dy / node.value);
1777    row.area = 0;
1778    while (child = children.pop()) {
1779      row.push(child);
1780      row.area += child.area;
1781      if (child.z != null) {
1782        position(row, child.z ? rect.dx : rect.dy, rect, !children.length);
1783        row.length = row.area = 0;
1784      }
1785    }
1786    node.children.forEach(stickify);
1787  }
1788
1789  // Computes the score for the specified row, as the worst aspect ratio.
1790  function worst(row, u) {
1791    var s = row.area,
1792        r,
1793        rmax = 0,
1794        rmin = Infinity,
1795        i = -1,
1796        n = row.length;
1797    while (++i < n) {
1798      if (!(r = row[i].area)) continue;
1799      if (r < rmin) rmin = r;
1800      if (r > rmax) rmax = r;
1801    }
1802    s *= s;
1803    u *= u;
1804    return s
1805        ? Math.max((u * rmax * ratio) / s, s / (u * rmin * ratio))
1806        : Infinity;
1807  }
1808
1809  // Positions the specified row of nodes. Modifies `rect`.
1810  function position(row, u, rect, flush) {
1811    var i = -1,
1812        n = row.length,
1813        x = rect.x,
1814        y = rect.y,
1815        v = u ? round(row.area / u) : 0,
1816        o;
1817    if (u == rect.dx) { // horizontal subdivision
1818      if (flush || v > rect.dy) v = rect.dy; // over+underflow
1819      while (++i < n) {
1820        o = row[i];
1821        o.x = x;
1822        o.y = y;
1823        o.dy = v;
1824        x += o.dx = v ? round(o.area / v) : 0;
1825      }
1826      o.z = true;
1827      o.dx += rect.x + rect.dx - x; // rounding error
1828      rect.y += v;
1829      rect.dy -= v;
1830    } else { // vertical subdivision
1831      if (flush || v > rect.dx) v = rect.dx; // over+underflow
1832      while (++i < n) {
1833        o = row[i];
1834        o.x = x;
1835        o.y = y;
1836        o.dx = v;
1837        y += o.dy = v ? round(o.area / v) : 0;
1838      }
1839      o.z = false;
1840      o.dy += rect.y + rect.dy - y; // rounding error
1841      rect.x += v;
1842      rect.dx -= v;
1843    }
1844  }
1845
1846  function treemap(d) {
1847    var nodes = stickies || hierarchy(d),
1848        root = nodes[0];
1849    root.x = 0;
1850    root.y = 0;
1851    root.dx = size[0];
1852    root.dy = size[1];
1853    if (stickies) hierarchy.revalue(root);
1854    scale([root], root.dx * root.dy / root.value);
1855    (stickies ? stickify : squarify)(root);
1856    if (sticky) stickies = nodes;
1857    return nodes;
1858  }
1859
1860  treemap.size = function(x) {
1861    if (!arguments.length) return size;
1862    size = x;
1863    return treemap;
1864  };
1865
1866  treemap.padding = function(x) {
1867    if (!arguments.length) return padding;
1868
1869    function padFunction(node) {
1870      var p = x.call(treemap, node, node.depth);
1871      return p == null
1872          ? d3_layout_treemapPadNull(node)
1873          : d3_layout_treemapPad(node, typeof p === "number" ? [p, p, p, p] : p);
1874    }
1875
1876    function padConstant(node) {
1877      return d3_layout_treemapPad(node, x);
1878    }
1879
1880    var type;
1881    pad = (padding = x) == null ? d3_layout_treemapPadNull
1882        : (type = typeof x) === "function" ? padFunction
1883        : type === "number" ? (x = [x, x, x, x], padConstant)
1884        : padConstant;
1885    return treemap;
1886  };
1887
1888  treemap.round = function(x) {
1889    if (!arguments.length) return round != Number;
1890    round = x ? Math.round : Number;
1891    return treemap;
1892  };
1893
1894  treemap.sticky = function(x) {
1895    if (!arguments.length) return sticky;
1896    sticky = x;
1897    stickies = null;
1898    return treemap;
1899  };
1900
1901  treemap.ratio = function(x) {
1902    if (!arguments.length) return ratio;
1903    ratio = x;
1904    return treemap;
1905  };
1906
1907  return d3_layout_hierarchyRebind(treemap, hierarchy);
1908};
1909
1910function d3_layout_treemapPadNull(node) {
1911  return {x: node.x, y: node.y, dx: node.dx, dy: node.dy};
1912}
1913
1914function d3_layout_treemapPad(node, padding) {
1915  var x = node.x + padding[3],
1916      y = node.y + padding[0],
1917      dx = node.dx - padding[1] - padding[3],
1918      dy = node.dy - padding[0] - padding[2];
1919  if (dx < 0) { x += dx / 2; dx = 0; }
1920  if (dy < 0) { y += dy / 2; dy = 0; }
1921  return {x: x, y: y, dx: dx, dy: dy};
1922}
1923})();
Note: See TracBrowser for help on using the repository browser.