source: Dev/branches/jQueryUI/client/d3/d3.layout.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

File size: 47.6 KB
RevLine 
[249]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.