Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add various new examples. Update to 1.11.

  • Loading branch information...
commit 6e6b694d679a7036118677c31a62aab87a6b11b5 1 parent 6de3a28
Mike Bostock mbostock authored

Showing 49 changed files with 1,333 additions and 119 deletions. Show diff stats Hide diff stats

  1. +38 0 _includes/Makefile
  2. +68 0 _includes/box.js
  3. +3 3 _includes/bullet.js
  4. +41 0 _includes/cluster.js
  5. +33 0 _includes/pack.js
  6. +12 27 _includes/tree.js
  7. +1 1  _layouts/api.html
  8. +1 1  _layouts/default.html
  9. +1 1  _layouts/ex.html
  10. +1 1  _layouts/tutorial.html
  11. BIN  api/group.png
  12. +27 0 api/index.markdown
  13. BIN  api/janwillemtulp.png
  14. BIN  box.png
  15. BIN  cluster.png
  16. +296 0 d3.chart.js
  17. +1 1  d3.chart.min.js
  18. +91 37 d3.js
  19. +296 0 d3.layout.js
  20. +1 1  d3.layout.min.js
  21. +2 2 d3.min.js
  22. +4 0 ex/box.css
  23. +68 0 ex/box.js
  24. +28 0 ex/box.markdown
  25. +3 3 ex/bullet.js
  26. +1 1  ex/bullet.markdown
  27. +2 2 ex/calendar.markdown
  28. +2 2 ex/cartogram.markdown
  29. +1 1  ex/chord.markdown
  30. +1 1  ex/choropleth.markdown
  31. +15 0 ex/cluster.css
  32. +41 0 ex/cluster.js
  33. +20 0 ex/cluster.markdown
  34. +1 1  ex/force.markdown
  35. +45 0 ex/index.markdown
  36. +101 0 ex/morley.csv
  37. +14 0 ex/pack.css
  38. +33 0 ex/pack.js
  39. +21 0 ex/pack.markdown
  40. +1 1  ex/stack.markdown
  41. +1 1  ex/stream.markdown
  42. +1 1  ex/sunburst.markdown
  43. +1 0  ex/tree.css
  44. +12 27 ex/tree.js
  45. +1 1  ex/tree.markdown
  46. +1 1  ex/treemap.markdown
  47. +1 1  ex/voronoi.markdown
  48. BIN  pack.png
  49. BIN  whatdoyouworkfor.png
38 _includes/Makefile
@@ -15,6 +15,11 @@ SRC_FILES = \
15 15 ../d3.time.min.js
16 16
17 17 EX_FILES = \
  18 + ../ex/box.js \
  19 + ../ex/box.css \
  20 + ../ex/morley.csv \
  21 + ../ex/cluster.js \
  22 + ../ex/cluster.css \
18 23 ../ex/calendar.js \
19 24 ../ex/calendar.css \
20 25 ../ex/chord.css \
@@ -33,6 +38,8 @@ EX_FILES = \
33 38 ../ex/treemap.css \
34 39 ../ex/treemap.js \
35 40 ../ex/miserables.json \
  41 + ../ex/pack.js \
  42 + ../ex/pack.css \
36 43 ../ex/splom.css \
37 44 ../ex/splom.js \
38 45 ../ex/flowers.json \
@@ -55,6 +62,8 @@ EX_FILES = \
55 62 ../ex/tree.css
56 63
57 64 INCLUDE_FILES = \
  65 + box.js \
  66 + cluster.js \
58 67 cartogram.js \
59 68 chord.js \
60 69 choropleth.js \
@@ -70,6 +79,7 @@ INCLUDE_FILES = \
70 79 sunburst.js \
71 80 bullet.js \
72 81 bullets.json \
  82 + pack.js \
73 83 tree.js
74 84
75 85 .PHONY all: $(SRC_FILES) $(EX_FILES) $(INCLUDE_FILES)
@@ -86,6 +96,34 @@ $(SRC_FILES):
86 96 @rm -rf $@
87 97 git cat-file blob master:examples/calendar/calendar.css > $@
88 98
  99 +../ex/box.js box.js:
  100 + @rm -rf $@
  101 + git cat-file blob master:examples/box/box.js > $@
  102 +
  103 +../ex/morley.csv:
  104 + @rm -rf $@
  105 + git cat-file blob master:examples/box/morley.csv > $@
  106 +
  107 +../ex/box.css:
  108 + @rm -rf $@
  109 + git cat-file blob master:examples/box/box.css > $@
  110 +
  111 +../ex/pack.js pack.js:
  112 + @rm -rf $@
  113 + git cat-file blob master:examples/pack/pack.js > $@
  114 +
  115 +../ex/pack.css:
  116 + @rm -rf $@
  117 + git cat-file blob master:examples/pack/pack.css > $@
  118 +
  119 +../ex/cluster.js cluster.js:
  120 + @rm -rf $@
  121 + git cat-file blob master:examples/cluster/cluster.js > $@
  122 +
  123 +../ex/cluster.css:
  124 + @rm -rf $@
  125 + git cat-file blob master:examples/cluster/cluster.css > $@
  126 +
89 127 ../ex/bullet.js bullet.js:
90 128 @rm -rf $@
91 129 git cat-file blob master:examples/bullet/bullet.js > $@
68 _includes/box.js
... ... @@ -0,0 +1,68 @@
  1 +var w = 120,
  2 + h = 500,
  3 + m = [10, 50, 20, 50], // top right bottom left
  4 + min = Infinity,
  5 + max = -Infinity;
  6 +
  7 +var chart = d3.chart.box()
  8 + .whiskers(iqr(1.5))
  9 + .width(w - m[1] - m[3])
  10 + .height(h - m[0] - m[2]);
  11 +
  12 +d3.csv("morley.csv", function(csv) {
  13 + var data = [];
  14 +
  15 + csv.forEach(function(x) {
  16 + var e = ~~x.Expt - 1,
  17 + r = ~~x.Run - 1,
  18 + s = ~~x.Speed,
  19 + d = data[e];
  20 + if (!d) d = data[e] = [s];
  21 + else d.push(s);
  22 + if (s > max) max = s;
  23 + if (s < min) min = s;
  24 + });
  25 +
  26 + chart.domain([min, max]);
  27 +
  28 + var vis = d3.select("#chart").selectAll("svg")
  29 + .data(data)
  30 + .enter().append("svg:svg")
  31 + .attr("class", "box")
  32 + .attr("width", w)
  33 + .attr("height", h)
  34 + .append("svg:g")
  35 + .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
  36 + .call(chart);
  37 +
  38 + chart.duration(1000);
  39 + window.transition = function() {
  40 + vis.map(randomize).call(chart);
  41 + };
  42 +});
  43 +
  44 +function randomize(d) {
  45 + if (!d.randomizer) d.randomizer = randomizer(d);
  46 + return d.map(d.randomizer);
  47 +}
  48 +
  49 +function randomizer(d) {
  50 + var k = d3.max(d) * .02;
  51 + return function(d) {
  52 + return Math.max(min, Math.min(max, d + k * (Math.random() - .5)));
  53 + };
  54 +}
  55 +
  56 +// Returns a function to compute the interquartile range.
  57 +function iqr(k) {
  58 + return function(d, i) {
  59 + var q1 = d.quartiles[0],
  60 + q3 = d.quartiles[2],
  61 + iqr = (q3 - q1) * k,
  62 + i = -1,
  63 + j = d.length;
  64 + while (d[++i] < q1 - iqr);
  65 + while (d[--j] > q3 + iqr);
  66 + return [i, j];
  67 + };
  68 +}
6 _includes/bullet.js
@@ -17,15 +17,15 @@ d3.json("bullets.json", function(data) {
17 17 .append("svg:g")
18 18 .attr("transform", "translate(" + m[3] + "," + m[0] + ")")
19 19 .call(chart);
20   -
  20 +
21 21 var title = vis.append("svg:g")
22 22 .attr("text-anchor", "end")
23 23 .attr("transform", "translate(-6," + (h - m[0] - m[2]) / 2 + ")");
24   -
  24 +
25 25 title.append("svg:text")
26 26 .attr("class", "title")
27 27 .text(function(d) { return d.title; });
28   -
  28 +
29 29 title.append("svg:text")
30 30 .attr("class", "subtitle")
31 31 .attr("dy", "1em")
41 _includes/cluster.js
... ... @@ -0,0 +1,41 @@
  1 +var w = 960,
  2 + h = 2200;
  3 +
  4 +var cluster = d3.layout.cluster()
  5 + .size([h, w - 160])
  6 + .sort(null)
  7 + .children(function(d) { return isNaN(d.value) ? d3.entries(d.value) : null; });
  8 +
  9 +var diagonal = d3.svg.diagonal()
  10 + .projection(function(d) { return [d.y, d.x]; });
  11 +
  12 +var vis = d3.select("#chart").append("svg:svg")
  13 + .attr("width", w)
  14 + .attr("height", h)
  15 + .append("svg:g")
  16 + .attr("transform", "translate(40, 0)");
  17 +
  18 +d3.json("flare.json", function(json) {
  19 + var nodes = cluster(d3.entries(json)[0]);
  20 +
  21 + var link = vis.selectAll("path.link")
  22 + .data(cluster.links(nodes))
  23 + .enter().append("svg:path")
  24 + .attr("class", "link")
  25 + .attr("d", diagonal);
  26 +
  27 + var node = vis.selectAll("g.node")
  28 + .data(nodes)
  29 + .enter().append("svg:g")
  30 + .attr("class", "node")
  31 + .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
  32 +
  33 + node.append("svg:circle")
  34 + .attr("r", 4.5);
  35 +
  36 + node.append("svg:text")
  37 + .attr("dx", function(d) { return d.children ? -8 : 8; })
  38 + .attr("dy", 3)
  39 + .attr("text-anchor", function(d) { return d.children ? "end" : "start"; })
  40 + .text(function(d) { return d.data.key; });
  41 +});
33 _includes/pack.js
... ... @@ -0,0 +1,33 @@
  1 +var w = 960,
  2 + h = 960,
  3 + format = d3.format(",d");
  4 +
  5 +var pack = d3.layout.pack()
  6 + .size([w - 4, h - 4])
  7 + .children(function(d) { return isNaN(d.value) ? d3.entries(d.value) : null; });
  8 +
  9 +var vis = d3.select("#chart").append("svg:svg")
  10 + .attr("width", w)
  11 + .attr("height", h)
  12 + .attr("class", "pack")
  13 + .append("svg:g")
  14 + .attr("transform", "translate(2, 2)");
  15 +
  16 +d3.json("flare.json", function(json) {
  17 + var node = vis.data(d3.entries(json)).selectAll("g.node")
  18 + .data(pack)
  19 + .enter().append("svg:g")
  20 + .attr("class", function(d) { return d.children ? "node" : "leaf node"; })
  21 + .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
  22 +
  23 + node.append("svg:title")
  24 + .text(function(d) { return d.data.key + (d.children ? "" : ": " + format(d.value)); });
  25 +
  26 + node.append("svg:circle")
  27 + .attr("r", function(d) { return d.r; });
  28 +
  29 + node.filter(function(d) { return !d.children; }).append("svg:text")
  30 + .attr("text-anchor", "middle")
  31 + .attr("dy", ".3em")
  32 + .text(function(d) { return d.data.key.substring(0, d.r / 3); });
  33 +});
39 _includes/tree.js
@@ -6,6 +6,12 @@ var tree = d3.layout.tree()
6 6 .children(function(d) { return isNaN(d.value) ? d3.entries(d.value) : null; })
7 7 .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
8 8
  9 +var diagonal = d3.svg.diagonal()
  10 + .projection(function(d) {
  11 + var r = d.y, a = (d.x - 90) / 180 * Math.PI;
  12 + return [r * Math.cos(a), r * Math.sin(a)];
  13 + });
  14 +
9 15 var vis = d3.select("#chart").append("svg:svg")
10 16 .attr("width", r * 2)
11 17 .attr("height", r * 2 - 150)
@@ -15,18 +21,11 @@ var vis = d3.select("#chart").append("svg:svg")
15 21 d3.json("flare.json", function(json) {
16 22 var nodes = tree(d3.entries(json)[0]);
17 23
18   - var link = vis.selectAll("g.link")
19   - .data(nodes)
20   - .enter().append("svg:g")
21   - .attr("class", "link");
22   -
23   - link.selectAll("line")
24   - .data(children)
25   - .enter().append("svg:line")
26   - .attr("x1", function(d) { return x(d.parent); })
27   - .attr("y1", function(d) { return y(d.parent); })
28   - .attr("x2", function(d) { return x(d.child); })
29   - .attr("y2", function(d) { return y(d.child); });
  24 + var link = vis.selectAll("path.link")
  25 + .data(tree.links(nodes))
  26 + .enter().append("svg:path")
  27 + .attr("class", "link")
  28 + .attr("d", diagonal);
30 29
31 30 var node = vis.selectAll("g.node")
32 31 .data(nodes)
@@ -35,7 +34,7 @@ d3.json("flare.json", function(json) {
35 34 .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
36 35
37 36 node.append("svg:circle")
38   - .attr("r", 5);
  37 + .attr("r", 4.5);
39 38
40 39 node.append("svg:text")
41 40 .attr("dx", function(d) { return d.x < 180 ? 8 : -8; })
@@ -43,18 +42,4 @@ d3.json("flare.json", function(json) {
43 42 .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
44 43 .attr("transform", function(d) { return d.x < 180 ? null : "rotate(180)"; })
45 44 .text(function(d) { return d.data.key; });
46   -
47   - // Returns parent+child objects for any children of `d`.
48   - function children(d) {
49   - return (d.children || []).map(function(v) {
50   - return {
51   - parent: d,
52   - child: v
53   - };
54   - });
55   - }
56   -
57   - // Radial scales for x and y.
58   - function x(d) { return d.y * Math.cos((d.x - 90) / 180 * Math.PI); }
59   - function y(d) { return d.y * Math.sin((d.x - 90) / 180 * Math.PI); }
60 45 });
2  _layouts/api.html
@@ -3,7 +3,7 @@
3 3 <head>
4 4 <meta http-equiv="content-type" content="text/html;charset=utf-8">
5 5 <title>d3.js{% if page.title %} ~ {{ page.title }}{% endif %}</title>
6   - <script type="text/javascript" src="../d3.js?1.10.0"></script>
  6 + <script type="text/javascript" src="../d3.js?1.11.0"></script>
7 7 <style type="text/css">
8 8
9 9 @import url("../style.css?1.10.0");
2  _layouts/default.html
@@ -3,7 +3,7 @@
3 3 <head>
4 4 <meta http-equiv="content-type" content="text/html;charset=utf-8">
5 5 <title>d3.js{% if page.title %} ~ {{ page.title }}{% endif %}</title>
6   - <script type="text/javascript" src="d3.js?1.10.0"></script>
  6 + <script type="text/javascript" src="d3.js?1.11.0"></script>
7 7 <style type="text/css">
8 8
9 9 @import url("style.css?1.10.0");
2  _layouts/ex.html
@@ -3,7 +3,7 @@
3 3 <head>
4 4 <meta http-equiv="content-type" content="text/html;charset=utf-8">
5 5 <title>d3.js{% if page.title %} ~ {{ page.title }}{% endif %}</title>
6   - <script type="text/javascript" src="../d3.js?1.10.0"></script>
  6 + <script type="text/javascript" src="../d3.js?1.11.0"></script>
7 7 <style type="text/css">
8 8
9 9 @import url("../style.css?1.10.0");
2  _layouts/tutorial.html
@@ -3,7 +3,7 @@
3 3 <head>
4 4 <meta http-equiv="content-type" content="text/html;charset=utf-8">
5 5 <title>d3.js{% if page.title %} ~ {{ page.title }}{% endif %}</title>
6   - <script type="text/javascript" src="../d3.js?1.10.0"></script>
  6 + <script type="text/javascript" src="../d3.js?1.11.0"></script>
7 7 <style type="text/css">
8 8
9 9 @import url("../style.css?1.10.0");
BIN  api/group.png
27 api/index.markdown
Source Rendered
@@ -47,6 +47,33 @@ title: Documentation
47 47
48 48 <br clear="left"/>
49 49
  50 +## User Guides
  51 +
  52 +<div class="gallery">
  53 +
  54 +<div class="list">
  55 + <a href="http://www.janwillemtulp.com/category/d3/">
  56 + <img src="janwillemtulp.png"/>
  57 + </a>
  58 + <h4><a href="http://www.janwillemtulp.com/category/d3/">Jan Willem Tulp's Blog</a></h4>
  59 +
  60 + <p>Jan Willem Tulp has posted a number of introductory tutorials on D3 to his
  61 + blog.</p>
  62 +</div>
  63 +
  64 +<div class="list">
  65 + <a href="http://groups.google.com/group/d3-js">
  66 + <img src="group.png"/>
  67 + </a>
  68 + <h4><a href="http://groups.google.com/group/d3-js">Google Group d3-js</a></h4>
  69 +
  70 + <p>Questions about D3? Post them to our Google Group.</p>
  71 +</div>
  72 +
  73 +</div>
  74 +
  75 +<br clear="left"/>
  76 +
50 77 ## Reference
51 78
52 79 ### d3
BIN  api/janwillemtulp.png
BIN  box.png
BIN  cluster.png
296 d3.chart.js
... ... @@ -1,4 +1,300 @@
1 1 (function(){d3.chart = {};
  2 +// Inspired by http://informationandvisualization.de/blog/box-plot
  3 +d3.chart.box = function() {
  4 + var width = 1,
  5 + height = 1,
  6 + duration = 0,
  7 + domain = null,
  8 + value = Number,
  9 + whiskers = d3_chart_boxWhiskers,
  10 + quartiles = d3_chart_boxQuartiles,
  11 + tickFormat = null;
  12 +
  13 + // For each small multiple…
  14 + function box(g) {
  15 + g.each(function(d, i) {
  16 + d = d.map(value).sort(d3.ascending);
  17 + var g = d3.select(this),
  18 + n = d.length,
  19 + min = d[0],
  20 + max = d[n - 1];
  21 +
  22 + // Compute quartiles. Must return exactly 3 elements.
  23 + var quartileData = d.quartiles = quartiles(d);
  24 +
  25 + // Compute whiskers. Must return exactly 2 elements, or null.
  26 + var whiskerIndices = whiskers && whiskers.call(this, d, i),
  27 + whiskerData = whiskerIndices && whiskerIndices.map(function(i) { return d[i]; });
  28 +
  29 + // Compute outliers. If no whiskers are specified, all data are "outliers".
  30 + // We compute the outliers as indices, so that we can join across transitions!
  31 + var outlierIndices = whiskerIndices
  32 + ? d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n))
  33 + : d3.range(n);
  34 +
  35 + // Compute the new x-scale.
  36 + var x1 = d3.scale.linear()
  37 + .domain(domain && domain.call(this, d, i) || [min, max])
  38 + .range([height, 0]);
  39 +
  40 + // Retrieve the old x-scale, if this is an update.
  41 + var x0 = this.__chart__ || d3.scale.linear()
  42 + .domain([0, Infinity])
  43 + .range(x1.range());
  44 +
  45 + // Stash the new scale.
  46 + this.__chart__ = x1;
  47 +
  48 + // Note: the box, median, and box tick elements are fixed in number,
  49 + // so we only have to handle enter and update. In contrast, the outliers
  50 + // and other elements are variable, so we need to exit them! Variable
  51 + // elements also fade in and out.
  52 +
  53 + // Update center line: the vertical line spanning the whiskers.
  54 + var center = g.selectAll("line.center")
  55 + .data(whiskerData ? [whiskerData] : []);
  56 +
  57 + center.enter().insert("svg:line", "rect")
  58 + .attr("class", "center")
  59 + .attr("x1", width / 2)
  60 + .attr("y1", function(d) { return x0(d[0]); })
  61 + .attr("x2", width / 2)
  62 + .attr("y2", function(d) { return x0(d[1]); })
  63 + .style("opacity", 1e-6)
  64 + .transition()
  65 + .duration(duration)
  66 + .style("opacity", 1)
  67 + .attr("y1", function(d) { return x1(d[0]); })
  68 + .attr("y2", function(d) { return x1(d[1]); });
  69 +
  70 + center.transition()
  71 + .duration(duration)
  72 + .style("opacity", 1)
  73 + .attr("y1", function(d) { return x1(d[0]); })
  74 + .attr("y2", function(d) { return x1(d[1]); });
  75 +
  76 + center.exit().transition()
  77 + .duration(duration)
  78 + .style("opacity", 1e-6)
  79 + .attr("y1", function(d) { return x1(d[0]); })
  80 + .attr("y2", function(d) { return x1(d[1]); })
  81 + .remove();
  82 +
  83 + // Update innerquartile box.
  84 + var box = g.selectAll("rect.box")
  85 + .data([quartileData]);
  86 +
  87 + box.enter().append("svg:rect")
  88 + .attr("class", "box")
  89 + .attr("x", 0)
  90 + .attr("y", function(d) { return x0(d[2]); })
  91 + .attr("width", width)
  92 + .attr("height", function(d) { return x0(d[0]) - x0(d[2]); })
  93 + .transition()
  94 + .duration(duration)
  95 + .attr("y", function(d) { return x1(d[2]); })
  96 + .attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
  97 +
  98 + box.transition()
  99 + .duration(duration)
  100 + .attr("y", function(d) { return x1(d[2]); })
  101 + .attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
  102 +
  103 + // Update median line.
  104 + var medianLine = g.selectAll("line.median")
  105 + .data([quartileData[1]]);
  106 +
  107 + medianLine.enter().append("svg:line")
  108 + .attr("class", "median")
  109 + .attr("x1", 0)
  110 + .attr("y1", x0)
  111 + .attr("x2", width)
  112 + .attr("y2", x0)
  113 + .transition()
  114 + .duration(duration)
  115 + .attr("y1", x1)
  116 + .attr("y2", x1);
  117 +
  118 + medianLine.transition()
  119 + .duration(duration)
  120 + .attr("y1", x1)
  121 + .attr("y2", x1);
  122 +
  123 + // Update whiskers.
  124 + var whisker = g.selectAll("line.whisker")
  125 + .data(whiskerData || []);
  126 +
  127 + whisker.enter().insert("svg:line", "circle, text")
  128 + .attr("class", "whisker")
  129 + .attr("x1", 0)
  130 + .attr("y1", x0)
  131 + .attr("x2", width)
  132 + .attr("y2", x0)
  133 + .style("opacity", 1e-6)
  134 + .transition()
  135 + .duration(duration)
  136 + .attr("y1", x1)
  137 + .attr("y2", x1)
  138 + .style("opacity", 1);
  139 +
  140 + whisker.transition()
  141 + .duration(duration)
  142 + .attr("y1", x1)
  143 + .attr("y2", x1)
  144 + .style("opacity", 1);
  145 +
  146 + whisker.exit().transition()
  147 + .duration(duration)
  148 + .attr("y1", x1)
  149 + .attr("y2", x1)
  150 + .style("opacity", 1e-6)
  151 + .remove();
  152 +
  153 + // Update outliers.
  154 + var outlier = g.selectAll("circle.outlier")
  155 + .data(outlierIndices, Number);
  156 +
  157 + outlier.enter().insert("svg:circle", "text")
  158 + .attr("class", "outlier")
  159 + .attr("r", 5)
  160 + .attr("cx", width / 2)
  161 + .attr("cy", function(i) { return x0(d[i]); })
  162 + .style("opacity", 1e-6)
  163 + .transition()
  164 + .duration(duration)
  165 + .attr("cy", function(i) { return x1(d[i]); })
  166 + .style("opacity", 1);
  167 +
  168 + outlier.transition()
  169 + .duration(duration)
  170 + .attr("cy", function(i) { return x1(d[i]); })
  171 + .style("opacity", 1);
  172 +
  173 + outlier.exit().transition()
  174 + .duration(duration)
  175 + .attr("cy", function(i) { return x1(d[i]); })
  176 + .style("opacity", 1e-6)
  177 + .remove();
  178 +
  179 + // Compute the tick format.
  180 + var format = tickFormat || x1.tickFormat(8);
  181 +
  182 + // Update box ticks.
  183 + var boxTick = g.selectAll("text.box")
  184 + .data(quartileData);
  185 +
  186 + boxTick.enter().append("svg:text")
  187 + .attr("class", "box")
  188 + .attr("dy", ".3em")
  189 + .attr("dx", function(d, i) { return i & 1 ? 6 : -6 })
  190 + .attr("x", function(d, i) { return i & 1 ? width : 0 })
  191 + .attr("y", x0)
  192 + .attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; })
  193 + .text(format)
  194 + .transition()
  195 + .duration(duration)
  196 + .attr("y", x1);
  197 +
  198 + boxTick.transition()
  199 + .duration(duration)
  200 + .text(format)
  201 + .attr("y", x1);
  202 +
  203 + // Update whisker ticks. These are handled separately from the box
  204 + // ticks because they may or may not exist, and we want don't want
  205 + // to join box ticks pre-transition with whisker ticks post-.
  206 + var whiskerTick = g.selectAll("text.whisker")
  207 + .data(whiskerData || []);
  208 +
  209 + whiskerTick.enter().append("svg:text")
  210 + .attr("class", "whisker")
  211 + .attr("dy", ".3em")
  212 + .attr("dx", 6)
  213 + .attr("x", width)
  214 + .attr("y", x0)
  215 + .text(format)
  216 + .style("opacity", 1e-6)
  217 + .transition()
  218 + .duration(duration)
  219 + .attr("y", x1)
  220 + .style("opacity", 1);
  221 +
  222 + whiskerTick.transition()
  223 + .duration(duration)
  224 + .text(format)
  225 + .attr("y", x1)
  226 + .style("opacity", 1);
  227 +
  228 + whiskerTick.exit().transition()
  229 + .duration(duration)
  230 + .attr("y", x1)
  231 + .style("opacity", 1e-6)
  232 + .remove();
  233 + });
  234 + }
  235 +
  236 + box.width = function(x) {
  237 + if (!arguments.length) return width;
  238 + width = x;
  239 + return box;
  240 + };
  241 +
  242 + box.height = function(x) {
  243 + if (!arguments.length) return height;
  244 + height = x;
  245 + return box;
  246 + };
  247 +
  248 + box.tickFormat = function(x) {
  249 + if (!arguments.length) return tickFormat;
  250 + tickFormat = x;
  251 + return box;
  252 + };
  253 +
  254 + box.duration = function(x) {
  255 + if (!arguments.length) return duration;
  256 + duration = x;
  257 + return box;
  258 + };
  259 +
  260 + box.domain = function(x) {
  261 + if (!arguments.length) return domain;
  262 + domain = x == null ? x : d3.functor(x);
  263 + return box;
  264 + };
  265 +
  266 + box.value = function(x) {
  267 + if (!arguments.length) return value;
  268 + value = x;
  269 + return box;
  270 + };
  271 +
  272 + box.whiskers = function(x) {
  273 + if (!arguments.length) return whiskers;
  274 + whiskers = x;
  275 + return box;
  276 + };
  277 +
  278 + box.quartiles = function(x) {
  279 + if (!arguments.length) return quartiles;
  280 + quartiles = x;
  281 + return box;
  282 + };
  283 +
  284 + return box;
  285 +};
  286 +
  287 +function d3_chart_boxWhiskers(d) {
  288 + return [0, d.length - 1];
  289 +}
  290 +
  291 +function d3_chart_boxQuartiles(d) {
  292 + var n = d.length;
  293 + return [.25, .5, .75].map(function(q) {
  294 + q *= n;
  295 + return ~~q === q ? (d[q] + d[q + 1]) / 2 : d[Math.round(q)];
  296 + });
  297 +}
2 298 // ranges (bad, satisfactory, good)
3 299 // measures (actual, forecast)
4 300 // markers (previous, goal)
2  d3.chart.min.js
... ... @@ -1 +1 @@
1   -(function(){function e(a){var b=a(0);return function(c){return Math.abs(a(c)-b)}}function d(a){return function(b){return"translate("+a(b)+",0)"}}function c(a){return a.measures}function b(a){return a.markers}function a(a){return a.ranges}d3.chart={},d3.chart.bullet=function(){function o(a){a.each(function(a,b){var c=i.call(this,a,b).slice().sort(d3.descending),f=j.call(this,a,b).slice().sort(d3.descending),o=k.call(this,a,b).slice().sort(d3.descending),p=d3.select(this),q=d3.scale.linear().domain([0,Math.max(c[0],f[0],o[0])]).range(g?[l,0]:[0,l]),r=this.__chart__||d3.scale.linear().domain([0,Infinity]).range(q.range());this.__chart__=q;var s=e(r),t=e(q),u=p.selectAll("rect.range").data(c);u.enter().append("svg:rect").attr("class",function(a,b){return"range s"+b}).attr("width",s).attr("height",m).attr("x",g?r:0).transition().duration(h).attr("width",t).attr("x",g?q:0),u.transition().duration(h).attr("x",g?q:0).attr("width",t).attr("height",m);var v=p.selectAll("rect.measure").data(o);v.enter().append("svg:rect").attr("class",function(a,b){return"measure s"+b}).attr("width",s).attr("height",m/3).attr("x",g?r:0).attr("y",m/3).transition().duration(h).attr("width",t).attr("x",g?q:0),v.transition().duration(h).attr("width",t).attr("height",m/3).attr("x",g?q:0).attr("y",m/3);var w=p.selectAll("line.marker").data(f);w.enter().append("svg:line").attr("class","marker").attr("x1",r).attr("x2",r).attr("y1",m/6).attr("y2",m*5/6).transition().duration(h).attr("x1",q).attr("x2",q),w.transition().duration(h).attr("x1",q).attr("x2",q).attr("y1",m/6).attr("y2",m*5/6);var x=n||q.tickFormat(8),y=p.selectAll("g.tick").data(q.ticks(8),function(a){return this.textContent||x(a)}),z=y.enter().append("svg:g").attr("class","tick").attr("transform",d(r)).attr("opacity",1e-6);z.append("svg:line").attr("y1",m).attr("y2",m*7/6),z.append("svg:text").attr("text-anchor","middle").attr("dy","1em").attr("y",m*7/6).text(x),z.transition().duration(h).attr("transform",d(q)).attr("opacity",1);var A=y.transition().duration(h).attr("transform",d(q)).attr("opacity",1);A.select("line").attr("y1",m).attr("y2",m*7/6),A.select("text").attr("y",m*7/6),y.exit().transition().duration(h).attr("transform",d(q)).attr("opacity",1e-6).remove()})}var f="left",g=!1,h=0,i=a,j=b,k=c,l=380,m=30,n=null;o.orient=function(a){if(!arguments.length)return f;f=a,g=f=="right"||f=="bottom";return o},o.ranges=function(a){if(!arguments.length)return i;i=a;return o},o.markers=function(a){if(!arguments.length)return j;j=a;return o},o.measures=function(a){if(!arguments.length)return k;k=a;return o},o.width=function(a){if(!arguments.length)return l;l=a;return o},o.height=function(a){if(!arguments.length)return m;m=a;return o},o.tickFormat=function(a){if(!arguments.length)return n;n=a;return o},o.duration=function(a){if(!arguments.length)return h;h=a;return o};return o}})()
  1 +(function(){function g(a){var b=a(0);return function(c){return Math.abs(a(c)-b)}}function f(a){return function(b){return"translate("+a(b)+",0)"}}function e(a){return a.measures}function d(a){return a.markers}function c(a){return a.ranges}function b(a){var b=a.length;return[.25,.5,.75].map(function(c){c*=b;return~~c===c?(a[c]+a[c+1])/2:a[Math.round(c)]})}function a(a){return[0,a.length-1]}d3.chart={},d3.chart.box=function(){function k(a){a.each(function(a,b){a=a.map(g).sort(d3.ascending);var k=d3.select(this),l=a.length,m=a[0],n=a[l-1],o=a.quartiles=i(a),p=h&&h.call(this,a,b),q=p&&p.map(function(b){return a[b]}),r=p?d3.range(0,p[0]).concat(d3.range(p[1]+1,l)):d3.range(l),s=d3.scale.linear().domain(f&&f.call(this,a,b)||[m,n]).range([d,0]),t=this.__chart__||d3.scale.linear().domain([0,Infinity]).range(s.range());this.__chart__=s;var u=k.selectAll("line.center").data(q?[q]:[]);u.enter().insert("svg:line","rect").attr("class","center").attr("x1",c/2).attr("y1",function(a){return t(a[0])}).attr("x2",c/2).attr("y2",function(a){return t(a[1])}).style("opacity",1e-6).transition().duration(e).style("opacity",1).attr("y1",function(a){return s(a[0])}).attr("y2",function(a){return s(a[1])}),u.transition().duration(e).style("opacity",1).attr("y1",function(a){return s(a[0])}).attr("y2",function(a){return s(a[1])}),u.exit().transition().duration(e).style("opacity",1e-6).attr("y1",function(a){return s(a[0])}).attr("y2",function(a){return s(a[1])}).remove();var v=k.selectAll("rect.box").data([o]);v.enter().append("svg:rect").attr("class","box").attr("x",0).attr("y",function(a){return t(a[2])}).attr("width",c).attr("height",function(a){return t(a[0])-t(a[2])}).transition().duration(e).attr("y",function(a){return s(a[2])}).attr("height",function(a){return s(a[0])-s(a[2])}),v.transition().duration(e).attr("y",function(a){return s(a[2])}).attr("height",function(a){return s(a[0])-s(a[2])});var w=k.selectAll("line.median").data([o[1]]);w.enter().append("svg:line").attr("class","median").attr("x1",0).attr("y1",t).attr("x2",c).attr("y2",t).transition().duration(e).attr("y1",s).attr("y2",s),w.transition().duration(e).attr("y1",s).attr("y2",s);var x=k.selectAll("line.whisker").data(q||[]);x.enter().insert("svg:line","circle, text").attr("class","whisker").attr("x1",0).attr("y1",t).attr("x2",c).attr("y2",t).style("opacity",1e-6).transition().duration(e).attr("y1",s).attr("y2",s).style("opacity",1),x.transition().duration(e).attr("y1",s).attr("y2",s).style("opacity",1),x.exit().transition().duration(e).attr("y1",s).attr("y2",s).style("opacity",1e-6).remove();var y=k.selectAll("circle.outlier").data(r,Number);y.enter().insert("svg:circle","text").attr("class","outlier").attr("r",5).attr("cx",c/2).attr("cy",function(b){return t(a[b])}).style("opacity",1e-6).transition().duration(e).attr("cy",function(b){return s(a[b])}).style("opacity",1),y.transition().duration(e).attr("cy",function(b){return s(a[b])}).style("opacity",1),y.exit().transition().duration(e).attr("cy",function(b){return s(a[b])}).style("opacity",1e-6).remove();var z=j||s.tickFormat(8),A=k.selectAll("text.box").data(o);A.enter().append("svg:text").attr("class","box").attr("dy",".3em").attr("dx",function(a,b){return b&1?6:-6}).attr("x",function(a,b){return b&1?c:0}).attr("y",t).attr("text-anchor",function(a,b){return b&1?"start":"end"}).text(z).transition().duration(e).attr("y",s),A.transition().duration(e).text(z).attr("y",s);var B=k.selectAll("text.whisker").data(q||[]);B.enter().append("svg:text").attr("class","whisker").attr("dy",".3em").attr("dx",6).attr("x",c).attr("y",t).text(z).style("opacity",1e-6).transition().duration(e).attr("y",s).style("opacity",1),B.transition().duration(e).text(z).attr("y",s).style("opacity",1),B.exit().transition().duration(e).attr("y",s).style("opacity",1e-6).remove()})}var c=1,d=1,e=0,f=null,g=Number,h=a,i=b,j=null;k.width=function(a){if(!arguments.length)return c;c=a;return k},k.height=function(a){if(!arguments.length)return d;d=a;return k},k.tickFormat=function(a){if(!arguments.length)return j;j=a;return k},k.duration=function(a){if(!arguments.length)return e;e=a;return k},k.domain=function(a){if(!arguments.length)return f;f=a==null?a:d3.functor(a);return k},k.value=function(a){if(!arguments.length)return g;g=a;return k},k.whiskers=function(a){if(!arguments.length)return h;h=a;return k},k.quartiles=function(a){if(!arguments.length)return i;i=a;return k};return k},d3.chart.bullet=function(){function o(a){a.each(function(a,c){var d=i.call(this,a,c).slice().sort(d3.descending),e=j.call(this,a,c).slice().sort(d3.descending),o=k.call(this,a,c).slice().sort(d3.descending),p=d3.select(this),q=d3.scale.linear().domain([0,Math.max(d[0],e[0],o[0])]).range(b?[l,0]:[0,l]),r=this.__chart__||d3.scale.linear().domain([0,Infinity]).range(q.range());this.__chart__=q;var s=g(r),t=g(q),u=p.selectAll("rect.range").data(d);u.enter().append("svg:rect").attr("class",function(a,b){return"range s"+b}).attr("width",s).attr("height",m).attr("x",b?r:0).transition().duration(h).attr("width",t).attr("x",b?q:0),u.transition().duration(h).attr("x",b?q:0).attr("width",t).attr("height",m);var v=p.selectAll("rect.measure").data(o);v.enter().append("svg:rect").attr("class",function(a,b){return"measure s"+b}).attr("width",s).attr("height",m/3).attr("x",b?r:0).attr("y",m/3).transition().duration(h).attr("width",t).attr("x",b?q:0),v.transition().duration(h).attr("width",t).attr("height",m/3).attr("x",b?q:0).attr("y",m/3);var w=p.selectAll("line.marker").data(e);w.enter().append("svg:line").attr("class","marker").attr("x1",r).attr("x2",r).attr("y1",m/6).attr("y2",m*5/6).transition().duration(h).attr("x1",q).attr("x2",q),w.transition().duration(h).attr("x1",q).attr("x2",q).attr("y1",m/6).attr("y2",m*5/6);var x=n||q.tickFormat(8),y=p.selectAll("g.tick").data(q.ticks(8),function(a){return this.textContent||x(a)}),z=y.enter().append("svg:g").attr("class","tick").attr("transform",f(r)).attr("opacity",1e-6);z.append("svg:line").attr("y1",m).attr("y2",m*7/6),z.append("svg:text").attr("text-anchor","middle").attr("dy","1em").attr("y",m*7/6).text(x),z.transition().duration(h).attr("transform",f(q)).attr("opacity",1);var A=y.transition().duration(h).attr("transform",f(q)).attr("opacity",1);A.select("line").attr("y1",m).attr("y2",m*7/6),A.select("text").attr("y",m*7/6),y.exit().transition().duration(h).attr("transform",f(q)).attr("opacity",1e-6).remove()})}var a="left",b=!1,h=0,i=c,j=d,k=e,l=380,m=30,n=null;o.orient=function(c){if(!arguments.length)return a;a=c,b=a=="right"||a=="bottom";return o},o.ranges=function(a){if(!arguments.length)return i;i=a;return o},o.markers=function(a){if(!arguments.length)return j;j=a;return o},o.measures=function(a){if(!arguments.length)return k;k=a;return o},o.width=function(a){if(!arguments.length)return l;l=a;return o},o.height=function(a){if(!arguments.length)return m;m=a;return o},o.tickFormat=function(a){if(!arguments.length)return n;n=a;return o},o.duration=function(a){if(!arguments.length)return h;h=a;return o};return o}})()
128 d3.js
... ... @@ -1,4 +1,4 @@
1   -(function(){d3 = {version: "1.10.0"}; // semver
  1 +(function(){d3 = {version: "1.11.0"}; // semver
2 2 if (!Date.now) Date.now = function() {
3 3 return +new Date();
4 4 };
@@ -24,9 +24,9 @@ try {
24 24 } catch(e) {
25 25 d3_array = d3_arrayCopy;
26 26 }
27   -function d3_functor(v) {
  27 +d3.functor = function(v) {
28 28 return typeof v == "function" ? v : function() { return v; };
29   -}
  29 +};
30 30 // A getter-setter method that preserves the appropriate `this` context.
31 31 d3.rebind = function(object, method) {
32 32 return function() {
@@ -551,6 +551,9 @@ d3.interpolateString = function(a, b) {
551 551 n, // q.length
552 552 o;
553 553
  554 + // Reset our regular expression!
  555 + d3_interpolate_number.lastIndex = 0;
  556 +
554 557 // Find all numbers in b.
555 558 for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
556 559 if (m.index) s.push(b.substring(s0, s1 = m.index));
@@ -686,7 +689,6 @@ d3.interpolateObject = function(a, b) {
686 689 }
687 690
688 691 var d3_interpolate_number = /[-+]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)(?:[eE][-]?\d+)?/g,
689   - d3_interpolate_digits = /[-+]?\d*\.?\d*(?:[eE][-]?\d+)?(.*)/,
690 692 d3_interpolate_rgb = {background: 1, fill: 1, stroke: 1};
691 693
692 694 function d3_interpolateByName(n) {
@@ -1410,24 +1412,16 @@ function d3_selection(groups) {
1410 1412 }
1411 1413
1412 1414 /** @this {Element} */
1413   - function textNull() {
1414   - while (this.lastChild) this.removeChild(this.lastChild);
1415   - }
1416   -
1417   - /** @this {Element} */
1418 1415 function textConstant() {
1419   - this.appendChild(document.createTextNode(value));
  1416 + this.textContent = value;
1420 1417 }
1421 1418
1422 1419 /** @this {Element} */
1423 1420 function textFunction() {
1424   - var x = value.apply(this, arguments);
1425   - if (x != null) this.appendChild(document.createTextNode(x));
  1421 + this.textContent = value.apply(this, arguments);
1426 1422 }
1427 1423
1428   - groups.each(textNull);
1429   - return value == null ? groups
1430   - : groups.each(typeof value == "function"
  1424 + return groups.each(typeof value == "function"
1431 1425 ? textFunction : textConstant);
1432 1426 };
1433 1427
@@ -1710,12 +1704,16 @@ function d3_transition(groups) {
1710 1704 event.start.dispatch.apply(this, arguments);
1711 1705 ik = interpolators[k] = {};
1712 1706 tx.active = transitionId;
1713   - for (tk in tweens) ik[tk] = tweens[tk].apply(this, arguments);
  1707 + for (tk in tweens) {
  1708 + if (te = tweens[tk].apply(this, arguments)) {
  1709 + ik[tk] = te;
  1710 + }
  1711 + }
1714 1712 }
1715 1713
1716 1714 // Apply the interpolators!
1717 1715 te = ease(t);
1718   - for (tk in tweens) ik[tk].call(this, te);
  1716 + for (tk in ik) ik[tk].call(this, te);
1719 1717
1720 1718 // Handle ending transitions.
1721 1719 if (t == 1) {
@@ -1822,6 +1820,15 @@ function d3_transition(groups) {
1822 1820 return transition.styleTween(name, d3_transitionTween(value), priority);
1823 1821 };
1824 1822
  1823 + transition.text = function(value) {
  1824 + tweens.text = function(d, i) {
  1825 + this.textContent = typeof value == "function"
  1826 + ? value.call(this, d, i)
  1827 + : value;
  1828 + };
  1829 + return transition;
  1830 + };
  1831 +
1825 1832 transition.select = function(query) {
1826 1833 var k, t = d3_transition(groups.select(query)).ease(ease);
1827 1834 k = -1; t.delay(function(d, i) { return delay[++k]; });
@@ -1949,10 +1956,12 @@ d3.scale.linear = function() {
1949 1956 kx = 1, // 1 / (x1 - x0)
1950 1957 ky = 1, // (x1 - x0) / (y1 - y0)
1951 1958 interpolate = d3.interpolate,
1952   - i = interpolate(y0, y1);
  1959 + i = interpolate(y0, y1),
  1960 + clamp = false;
1953 1961
1954 1962 function scale(x) {
1955   - return i((x - x0) * kx);
  1963 + x = (x - x0) * kx;
  1964 + return i(clamp ? Math.max(0, Math.min(1, x)) : x);
1956 1965 }
1957 1966
1958 1967 // Note: requires range is coercible to number!
@@ -1982,6 +1991,12 @@ d3.scale.linear = function() {
1982 1991 return scale.range(x).interpolate(d3.interpolateRound);
1983 1992 };
1984 1993
  1994 + scale.clamp = function(x) {
  1995 + if (!arguments.length) return clamp;
  1996 + clamp = x;
  1997 + return scale;
  1998 + };
  1999 +
1985 2000 scale.interpolate = function(x) {
1986 2001 if (!arguments.length) return interpolate;
1987 2002 i = (interpolate = x)(y0, y1);
@@ -2045,6 +2060,7 @@ d3.scale.log = function() {
2045 2060 scale.range = d3.rebind(scale, linear.range);
2046 2061 scale.rangeRound = d3.rebind(scale, linear.rangeRound);
2047 2062 scale.interpolate = d3.rebind(scale, linear.interpolate);
  2063 + scale.clamp = d3.rebind(scale, linear.clamp);
2048 2064
2049 2065 scale.ticks = function() {
2050 2066 var d = linear.domain(),
@@ -2118,6 +2134,7 @@ d3.scale.pow = function() {
2118 2134 scale.range = d3.rebind(scale, linear.range);
2119 2135 scale.rangeRound = d3.rebind(scale, linear.rangeRound);
2120 2136 scale.interpolate = d3.rebind(scale, linear.interpolate);
  2137 + scale.clamp = d3.rebind(scale, linear.clamp);
2121 2138 scale.ticks = tick.ticks;
2122 2139 scale.tickFormat = tick.tickFormat;
2123 2140
@@ -2389,25 +2406,25 @@ d3.svg.arc = function() {
2389 2406
2390 2407 arc.innerRadius = function(v) {
2391 2408 if (!arguments.length) return innerRadius;
2392   - innerRadius = d3_functor(v);
  2409 + innerRadius = d3.functor(v);
2393 2410 return arc;
2394 2411 };
2395 2412
2396 2413 arc.outerRadius = function(v) {
2397 2414 if (!arguments.length) return outerRadius;
2398   - outerRadius = d3_functor(v);
  2415 + outerRadius = d3.functor(v);
2399 2416 return arc;
2400 2417 };
2401 2418
2402 2419 arc.startAngle = function(v) {
2403 2420 if (!arguments.length) return startAngle;
2404   - startAngle = d3_functor(v);
  2421 + startAngle = d3.functor(v);
2405 2422 return arc;
2406 2423 };
2407 2424
2408 2425 arc.endAngle = function(v) {
2409 2426 if (!arguments.length) return endAngle;
2410   - endAngle = d3_functor(v);
  2427 + endAngle = d3.functor(v);
2411 2428 return arc;
2412 2429 };
2413 2430
@@ -2563,7 +2580,7 @@ function d3_svg_lineStepAfter(points) {
2563 2580 function d3_svg_lineCardinalClosed(points, tension) {
2564 2581 return points.length < 3
2565 2582 ? d3_svg_lineLinear(points)
2566   - : points[0] + d3_svg_lineHermite(points,
  2583 + : points[0] + d3_svg_lineHermite((points.push(points[0]), points),
2567 2584 d3_svg_lineCardinalTangents([points[points.length - 2]]
2568 2585 .concat(points, [points[1]]), tension));
2569 2586 }
@@ -2627,18 +2644,17 @@ function d3_svg_lineHermite(points, tangents) {
2627 2644 function d3_svg_lineCardinalTangents(points, tension) {
2628 2645 var tangents = [],
2629 2646 a = (1 - tension) / 2,
2630   - p0 = points[0],
2631   - p1 = points[1],
2632   - p2 = points[2],
2633   - i = 2,
  2647 + p0,
  2648 + p1 = points[0],
  2649 + p2 = points[1],
  2650 + i = 1,
2634 2651 n = points.length;
2635 2652 while (++i < n) {
2636   - tangents.push([a * (p2[0] - p0[0]), a * (p2[1] - p0[1])]);
2637 2653 p0 = p1;
2638 2654 p1 = p2;
2639 2655 p2 = points[i];
  2656 + tangents.push([a * (p2[0] - p0[0]), a * (p2[1] - p0[1])]);
2640 2657 }
2641   - tangents.push([a * (p2[0] - p0[0]), a * (p2[1] - p0[1])]);
2642 2658 return tangents;
2643 2659 }
2644 2660
@@ -2821,31 +2837,31 @@ d3.svg.chord = function() {
2821 2837
2822 2838 chord.radius = function(v) {
2823 2839 if (!arguments.length) return radius;
2824   - radius = d3_functor(v);
  2840 + radius = d3.functor(v);
2825 2841 return chord;
2826 2842 };
2827 2843
2828 2844 chord.source = function(v) {
2829 2845 if (!arguments.length) return source;
2830   - source = d3_functor(v);
  2846 + source = d3.functor(v);
2831 2847 return chord;
2832 2848 };
2833 2849
2834 2850 chord.target = function(v) {
2835 2851 if (!arguments.length) return target;
2836   - target = d3_functor(v);
  2852 + target = d3.functor(v);
2837 2853 return chord;
2838 2854 };
2839 2855
2840 2856 chord.startAngle = function(v) {
2841 2857 if (!arguments.length) return startAngle;
2842   - startAngle = d3_functor(v);
  2858 + startAngle = d3.functor(v);
2843 2859 return chord;
2844 2860 };
2845 2861
2846 2862 chord.endAngle = function(v) {
2847 2863 if (!arguments.length) return endAngle;
2848   - endAngle = d3_functor(v);
  2864 + endAngle = d3.functor(v);
2849 2865 return chord;
2850 2866 };
2851 2867
@@ -2871,6 +2887,44 @@ function d3_svg_chordStartAngle(d) {
2871 2887 function d3_svg_chordEndAngle(d) {
2872 2888 return d.endAngle;
2873 2889 }
  2890 +d3.svg.diagonal = function() {
  2891 + var source = d3_svg_chordSource,
  2892 + target = d3_svg_chordTarget,
  2893 + projection = d3_svg_diagonalProjection;
  2894 +
  2895 + function diagonal(d, i) {
  2896 + var p0 = source.call(this, d, i),
  2897 + p3 = target.call(this, d, i),
  2898 + m = (p0.y + p3.y) / 2,
  2899 + p = [p0, {x: p0.x, y: m}, {x: p3.x, y: m}, p3];
  2900 + p = p.map(projection);
  2901 + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
  2902 + }
  2903 +
  2904 + diagonal.source = function(x) {
  2905 + if (!arguments.length) return source;
  2906 + source = d3_functor(x);
  2907 + return diagonal;
  2908 + };
  2909 +
  2910 + diagonal.target = function(x) {
  2911 + if (!arguments.length) return target;
  2912 + target = d3_functor(x);
  2913 + return diagonal;
  2914 + };
  2915 +
  2916 + diagonal.projection = function(x) {
  2917 + if (!arguments.length) return projection;
  2918 + projection = x;
  2919 + return diagonal;
  2920 + };
  2921 +
  2922 + return diagonal;
  2923 +};
  2924 +
  2925 +function d3_svg_diagonalProjection(d) {
  2926 + return [d.x, d.y];
  2927 +}
2874 2928 d3.svg.mouse = function(container) {
2875 2929 var point = (container.ownerSVGElement || container).createSVGPoint();
2876 2930 if ((d3_mouse_bug44083 < 0) && (window.scrollX || window.scrollY)) {
@@ -2908,14 +2962,14 @@ d3.svg.symbol = function() {
2908 2962
2909 2963 symbol.type = function(x) {
2910 2964 if (!arguments.length) return type;
2911   - type = d3_functor(x);
  2965 + type = d3.functor(x);
2912 2966 return symbol;
2913 2967 };
2914 2968
2915 2969 // size of symbol in square pixels
2916 2970 symbol.size = function(x) {
2917 2971 if (!arguments.length) return size;
2918   - size = d3_functor(x);
  2972 + size = d3.functor(x);
2919 2973 return symbol;
2920 2974 };
2921 2975
296 d3.layout.js
@@ -739,6 +739,292 @@ function d3_layout_hierarchyValue(d) {
739 739 function d3_layout_hierarchySort(a, b) {
740 740 return b.value - a.value;
741 741 }
  742 +d3.layout.pack = function() {
  743 + var hierarchy = d3.layout.hierarchy(),
  744 + size = [1, 1];
  745 +
  746 + function pack(d, i) {
  747 + var nodes = hierarchy.call(this, d, i),
  748 + root = nodes[0];
  749 +
  750 + // Recursively compute the layout.
  751 + root.x = 0;
  752 + root.y = 0;
  753 + d3_layout_packTree(root);
  754 +
  755 + // Scale the layout to fit the requested size.
  756 + var w = size[0],
  757 + h = size[1],
  758 + k = 1 / Math.max(2 * root.r / w, 2 * root.r / h);
  759 + d3_layout_packTransform(root, w / 2, h / 2, k);
  760 +
  761 + return nodes;
  762 + }
  763 +
  764 + pack.sort = d3.rebind(pack, hierarchy.sort);
  765 + pack.children = d3.rebind(pack, hierarchy.children);
  766 + pack.value = d3.rebind(pack, hierarchy.value);
  767 +
  768 + pack.size = function(x) {
  769 + if (!arguments.length) return size;
  770 + size = x;
  771 + return pack;
  772 + };
  773 +
  774 + return pack.sort(d3_layout_packSort);
  775 +};
  776 +
  777 +function d3_layout_packSort(a, b) {
  778 + return a.value - b.value;
  779 +}
  780 +
  781 +function d3_layout_packInsert(a, b) {
  782 + var c = a._pack_next;
  783 + a._pack_next = b;
  784 + b._pack_prev = a;
  785 + b._pack_next = c;
  786 + c._pack_prev = b;
  787 +}
  788 +
  789 +function d3_layout_packSplice(a, b) {
  790 + a._pack_next = b;
  791 + b._pack_prev = a;
  792 +}
  793 +
  794 +function d3_layout_packIntersects(a, b) {
  795 + var dx = b.x - a.x,
  796 + dy = b.y - a.y,
  797 + dr = a.r + b.r;
  798 + return (dr * dr - dx * dx - dy * dy) > .001; // within epsilon
  799 +}
  800 +
  801 +function d3_layout_packCircle(nodes) {
  802 + var xMin = Infinity,
  803 + xMax = -Infinity,
  804 + yMin = Infinity,
  805 + yMax = -Infinity,
  806 + n = nodes.length,
  807 + a, b, c, j, k;
  808 +
  809 + function bound(node) {
  810 + xMin = Math.min(node.x - node.r, xMin);
  811 + xMax = Math.max(node.x + node.r, xMax);
  812 + yMin = Math.min(node.y - node.r, yMin);
  813 + yMax = Math.max(node.y + node.r, yMax);
  814 + }
  815 +
  816 + // Create node links.
  817 + nodes.forEach(d3_layout_packLink);
  818 +
  819 + // Create first node.
  820 + a = nodes[0];
  821 + a.x = -a.r;
  822 + a.y = 0;
  823 + bound(a);
  824 +
  825 + // Create second node.
  826 + if (n > 1) {
  827 + b = nodes[1];
  828 + b.x = b.r;
  829 + b.y = 0;
  830 + bound(b);
  831 +
  832 + // Create third node and build chain.
  833 + if (n > 2) {
  834 + c = nodes[2];
  835 + d3_layout_packPlace(a, b, c);
  836 + bound(c);
  837 + d3_layout_packInsert(a, c);
  838 + a._pack_prev = c;
  839 + d3_layout_packInsert(c, b);
  840 + b = a._pack_next;
  841 +
  842 + // Now iterate through the rest.
  843 + for (var i = 3; i < n; i++) {
  844 + d3_layout_packPlace(a, b, c = nodes[i]);
  845 +
  846 + // Search for the closest intersection.
  847 + var isect = 0, s1 = 1, s2 = 1;
  848 + for (j = b._pack_next; j != b; j = j._pack_next, s1++) {
  849 + if (d3_layout_packIntersects(j, c)) {
  850 + isect = 1;
  851 + break;
  852 + }
  853 + }
  854 + if (isect == 1) {
  855 + for (k = a._pack_prev; k != j._pack_prev; k = k._pack_prev, s2++) {
  856 + if (d3_layout_packIntersects(k, c)) {
  857 + if (s2 < s1) {
  858 + isect = -1;
  859 + j = k;
  860 + }
  861 + break;
  862 + }
  863 + }
  864 + }
  865 +
  866 + // Update node chain.
  867 + if (isect == 0) {
  868 + d3_layout_packInsert(a, c);
  869 + b = c;
  870 + bound(c);
  871 + } else if (isect > 0) {
  872 + d3_layout_packSplice(a, j);
  873 + b = j;
  874 + i--;
  875 + } else { // isect < 0
  876 + d3_layout_packSplice(j, b);
  877 + a = j;
  878 + i--;
  879 + }
  880 + }
  881 + }
  882 + }
  883 +
  884 + // Re-center the circles and return the encompassing radius.
  885 + var cx = (xMin + xMax) / 2,
  886 + cy = (yMin + yMax) / 2,
  887 + cr = 0;
  888 + for (var i = 0; i < n; i++) {
  889 + var node = nodes[i];
  890 + node.x -= cx;
  891 + node.y -= cy;
  892 + cr = Math.max(cr, node.r + Math.sqrt(node.x * node.x + node.y * node.y));
  893 + }
  894 +
  895 + // Remove node links.
  896 + nodes.forEach(d3_layout_packUnlink);
  897 +
  898 + return cr;
  899 +}
  900 +
  901 +function d3_layout_packLink(node) {
  902 + node._pack_next = node._pack_prev = node;
  903 +}
  904 +
  905 +function d3_layout_packUnlink(node) {
  906 + delete node._pack_next;
  907 + delete node._pack_prev;
  908 +}
  909 +
  910 +function d3_layout_packTree(node) {
  911 + var children = node.children;
  912 + if (children) {
  913 + children.forEach(d3_layout_packTree);
  914 + node.r = d3_layout_packCircle(children);
  915 + } else {
  916 + node.r = Math.sqrt(node.value);
  917 + }
  918 +}
  919 +
  920 +function d3_layout_packTransform(node, x, y, k) {
  921 + var children = node.children;
  922 + node.x = (x += k * node.x);
  923 + node.y = (y += k * node.y);
  924 + node.r *= k;
  925 + if (children) {
  926 + var i = -1, n = children.length;
  927 + while (++i < n) d3_layout_packTransform(children[i], x, y, k);
  928 + }
  929 +}
  930 +
  931 +function d3_layout_packPlace(a, b, c) {
  932 + var da = b.r + c.r,
  933 + db = a.r + c.r,
  934 + dx = b.x - a.x,
  935 + dy = b.y - a.y,
  936 + dc = Math.sqrt(dx * dx + dy * dy),
  937 + cos = (db * db + dc * dc - da * da) / (2 * db * dc),
  938 + theta = Math.acos(cos),
  939 + x = cos * db,