Permalink
Browse files

More convenient pies.

This adds d3.layout.pie, which can be used to compute the start and end angles
for arcs given an arbitrary array of data. In addition, d3.svg.arc now has a
`centroid` method that computes the center of the arc, useful for labeling.
Together these changes greatly simplify the donut & pie examples.

This commit also includes a `map` method for selections, which is similar to the
`filter` method. This allows you to map the data bound to the current selection.
I'm not currently using it, but it seems like a useful feature for those cases
where you want to rebind the current selection to different (but related) data.
  • Loading branch information...
1 parent 23dc44e commit ade083dd56f7e795767a0e00d330a7ef5bfd3795 @mbostock mbostock committed Feb 24, 2011
Showing with 366 additions and 236 deletions.
  1. +1 −0 Makefile
  2. +26 −6 d3.js
  3. +97 −11 d3.layout.js
  4. +7 −6 d3.layout.min.js
  5. +68 −67 d3.min.js
  6. +31 −29 examples/donut/donut.html
  7. +6 −52 examples/pie/pie-transition.html
  8. +7 −48 examples/pie/pie.html
  9. +1 −1 src/core/core.js
  10. +12 −0 src/core/selection.js
  11. +11 −11 src/layout/chord.js
  12. +86 −0 src/layout/pie.js
  13. +13 −5 src/svg/arc.js
View
@@ -94,6 +94,7 @@ d3.layout.js: \
src/start.js \
src/layout/layout.js \
src/layout/chord.js \
+ src/layout/pie.js \
src/layout/stack.js \
src/end.js
View
32 d3.js
@@ -1,4 +1,4 @@
-(function(){d3 = {version: "1.1.0"}; // semver
+(function(){d3 = {version: "1.2.0"}; // semver
if (!Date.now) Date.now = function() {
return +new Date();
};
@@ -1039,6 +1039,18 @@ function d3_selection(groups) {
return d3_selection(subgroups);
};
+ groups.map = function(map) {
+ var group,
+ node;
+ for (var j = 0, m = groups.length; j < m; j++) {
+ group = groups[j];
+ for (var i = 0, n = group.length; i < n; i++) {
+ if (node = group[i]) node.__data__ = map.call(node, node.__data__, i);
+ }
+ }
+ return groups;
+ };
+
// TODO data(null) for clearing data?
groups.data = function(data, join) {
var enter = [],
@@ -2261,11 +2273,11 @@ d3.svg.arc = function() {
startAngle = d3_svg_arcStartAngle,
endAngle = d3_svg_arcEndAngle;
- function arc(d, i) {
- var r0 = innerRadius.call(this, d, i),
- r1 = outerRadius.call(this, d, i),
- a0 = startAngle.call(this, d, i) + d3_svg_arcOffset,
- a1 = endAngle.call(this, d, i) + d3_svg_arcOffset,
+ function arc() {
+ var r0 = innerRadius.apply(this, arguments),
+ r1 = outerRadius.apply(this, arguments),
+ a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset,
+ a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset,
da = a1 - a0,
df = da < Math.PI ? "0" : "1",
c0 = Math.cos(a0),
@@ -2321,6 +2333,14 @@ d3.svg.arc = function() {
return arc;
};
+ arc.centroid = function() {
+ var r = (innerRadius.apply(this, arguments)
+ + outerRadius.apply(this, arguments)) / 2,
+ a = (startAngle.apply(this, arguments)
+ + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
+ return [Math.cos(a) * r, Math.sin(a) * r];
+ };
+
return arc;
};
View
@@ -62,18 +62,18 @@ d3.layout.chord = function() {
dj = subgroupIndex[i][j],
v = matrix[di][dj];
subgroups[di + "-" + dj] = {
- "index": di,
- "subindex": dj,
- "startAngle": x,
- "endAngle": x += v * k,
- "value": v
+ index: di,
+ subindex: dj,
+ startAngle: x,
+ endAngle: x += v * k,
+ value: v
};
}
groups.push({
- "index": di,
- "startAngle": x0,
- "endAngle": x,
- "value": (x - x0) / k
+ index: di,
+ startAngle: x0,
+ endAngle: x,
+ value: (x - x0) / k
});
x += padding;
}
@@ -85,8 +85,8 @@ d3.layout.chord = function() {
target = subgroups[j + "-" + i];
if (source.value || target.value) {
chords.push({
- "source": source,
- "target": target
+ source: source,
+ target: target
})
}
}
@@ -150,6 +150,92 @@ d3.layout.chord = function() {
return chord;
};
+d3.layout.pie = function() {
+ var value = Number,
+ sort = null,
+ startAngle = 0,
+ endAngle = 2 * Math.PI;
+
+ function pie(data, i) {
+
+ // Compute the start angle.
+ var a = +(typeof startAngle == "function"
+ ? startAngle.apply(this, arguments)
+ : startAngle);
+
+ // Compute the angular range (end - start).
+ var k = (typeof endAngle == "function"
+ ? endAngle.apply(this, arguments)
+ : endAngle) - startAngle;
+
+ // Optionally sort (a copy of) the data.
+ if (sort != null) data = data.slice().sort(sort);
+
+ // Compute the numeric values for each data element.
+ var values = data.map(value);
+
+ // Convert k into a scale factor from value to angle, using the sum.
+ k /= values.reduce(function(p, d) { return p + d; }, 0);
+
+ // Compute the arcs!
+ return values.map(function(d, i) {
+ return {
+ value: d,
+ startAngle: a,
+ endAngle: a += d * k
+ };
+ });
+ }
+
+ /**
+ * Specifies the value function *x*, which returns a nonnegative numeric value
+ * for each datum. The default value function is `Number`. The value function
+ * is passed two arguments: the current datum and the current index.
+ */
+ pie.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return pie;
+ };
+
+ /**
+ * Specifies a sort comparison operator *x*. The comparator is passed two data
+ * elements from the data array, a and b; it returns a negative value if a is
+ * less than b, a positive value if a is greater than b, and zero if a equals
+ * b.
+ */
+ pie.sort = function(x) {
+ if (!arguments.length) return sort;
+ sort = x;
+ return pie;
+ };
+
+ /**
+ * Specifies the overall start angle of the pie chart. Defaults to 0. The
+ * start angle can be specified either as a constant or as a function; in the
+ * case of a function, it is evaluated once per array (as opposed to per
+ * element).
+ */
+ pie.startAngle = function(x) {
+ if (!arguments.length) return startAngle;
+ startAngle = x;
+ return pie;
+ };
+
+ /**
+ * Specifies the overall end angle of the pie chart. Defaults to 2π. The
+ * end angle can be specified either as a constant or as a function; in the
+ * case of a function, it is evaluated once per array (as opposed to per
+ * element).
+ */
+ pie.endAngle = function(x) {
+ if (!arguments.length) return endAngle;
+ endAngle = x;
+ return pie;
+ };
+
+ return pie;
+};
// data is two-dimensional array of x,y; we populate y0
// TODO perhaps make the `x`, `y` and `y0` structure customizable
d3.layout.stack = function() {
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit ade083d

Please sign in to comment.