Skip to content

Commit

Permalink
Add bullet.orient(top | bottom). Fixes d3#63.
Browse files Browse the repository at this point in the history
  • Loading branch information
jasondavies committed Apr 24, 2013
1 parent c4b8468 commit c0c9e10
Showing 1 changed file with 51 additions and 87 deletions.
138 changes: 51 additions & 87 deletions bullet/bullet.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,42 @@
// based on the work of Clint Ivy, Jamie Love, and Jason Davies.
// http://projects.instantcognition.com/protovis/bulletchart/
d3.bullet = function() {
var orient = "left", // TODO top & bottom
var orient = "left",
reverse = false,
vertical = false,
duration = 0,
ranges = bulletRanges,
markers = bulletMarkers,
measures = bulletMeasures,
width = 380,
height = 30,
tickFormat = null;
xAxis = d3.svg.axis();

// For each small multiple…
function bullet(g) {
g.each(function(d, i) {
var rangez = ranges.call(this, d, i).slice().sort(d3.descending),
markerz = markers.call(this, d, i).slice().sort(d3.descending),
measurez = measures.call(this, d, i).slice().sort(d3.descending),
g = d3.select(this);
g = d3.select(this),
extentX,
extentY;

var wrap = g.select("g.wrap");
if (wrap.empty()) wrap = g.append("g").attr("class", "wrap");

if (vertical) {
extentX = height, extentY = width;
wrap.attr("transform", "rotate(90)translate(0," + -width + ")");
} else {
extentX = width, extentY = height;
wrap.attr("transform", "translate(0)");
}

// Compute the new x-scale.
var x1 = d3.scale.linear()
.domain([0, Math.max(rangez[0], markerz[0], measurez[0])])
.range(reverse ? [width, 0] : [0, width]);
.range(reverse ? [extentX, 0] : [0, extentX]);

// Retrieve the old x-scale, if this is an update.
var x0 = this.__chart__ || d3.scale.linear()
Expand All @@ -40,13 +54,13 @@ d3.bullet = function() {
w1 = bulletWidth(x1);

// Update the range rects.
var range = g.selectAll("rect.range")
var range = wrap.selectAll("rect.range")
.data(rangez);

range.enter().append("rect")
.attr("class", function(d, i) { return "range s" + i; })
.attr("width", w0)
.attr("height", height)
.attr("height", extentY)
.attr("x", reverse ? x0 : 0)
.transition()
.duration(duration)
Expand All @@ -57,18 +71,18 @@ d3.bullet = function() {
.duration(duration)
.attr("x", reverse ? x1 : 0)
.attr("width", w1)
.attr("height", height);
.attr("height", extentY);

// Update the measure rects.
var measure = g.selectAll("rect.measure")
var measure = wrap.selectAll("rect.measure")
.data(measurez);

measure.enter().append("rect")
.attr("class", function(d, i) { return "measure s" + i; })
.attr("width", w0)
.attr("height", height / 3)
.attr("height", extentY / 3)
.attr("x", reverse ? x0 : 0)
.attr("y", height / 3)
.attr("y", extentY / 3)
.transition()
.duration(duration)
.attr("width", w1)
Expand All @@ -77,20 +91,20 @@ d3.bullet = function() {
measure.transition()
.duration(duration)
.attr("width", w1)
.attr("height", height / 3)
.attr("height", extentY / 3)
.attr("x", reverse ? x1 : 0)
.attr("y", height / 3);
.attr("y", extentY / 3);

// Update the marker lines.
var marker = g.selectAll("line.marker")
var marker = wrap.selectAll("line.marker")
.data(markerz);

marker.enter().append("line")
.attr("class", "marker")
.attr("x1", x0)
.attr("x2", x0)
.attr("y1", height / 6)
.attr("y2", height * 5 / 6)
.attr("y1", extentY / 6)
.attr("y2", extentY * 5 / 6)
.transition()
.duration(duration)
.attr("x1", x1)
Expand All @@ -100,117 +114,67 @@ d3.bullet = function() {
.duration(duration)
.attr("x1", x1)
.attr("x2", x1)
.attr("y1", height / 6)
.attr("y2", height * 5 / 6);

// Compute the tick format.
var format = tickFormat || x1.tickFormat(8);

// Update the tick groups.
var tick = g.selectAll("g.tick")
.data(x1.ticks(8), function(d) {
return this.textContent || format(d);
});

// Initialize the ticks with the old scale, x0.
var tickEnter = tick.enter().append("g")
.attr("class", "tick")
.attr("transform", bulletTranslate(x0))
.style("opacity", 1e-6);

tickEnter.append("line")
.attr("y1", height)
.attr("y2", height * 7 / 6);

tickEnter.append("text")
.attr("text-anchor", "middle")
.attr("dy", "1em")
.attr("y", height * 7 / 6)
.text(format);

// Transition the entering ticks to the new scale, x1.
tickEnter.transition()
.duration(duration)
.attr("transform", bulletTranslate(x1))
.style("opacity", 1);

// Transition the updating ticks to the new scale, x1.
var tickUpdate = tick.transition()
.duration(duration)
.attr("transform", bulletTranslate(x1))
.style("opacity", 1);
.attr("y1", extentY / 6)
.attr("y2", extentY * 5 / 6);

tickUpdate.select("line")
.attr("y1", height)
.attr("y2", height * 7 / 6);

tickUpdate.select("text")
.attr("y", height * 7 / 6);

// Transition the exiting ticks to the new scale, x1.
tick.exit().transition()
var axis = g.selectAll("g.axis").data([0]);
axis.enter().append("g").attr("class", "axis");
axis.transition()
.duration(duration)
.attr("transform", bulletTranslate(x1))
.style("opacity", 1e-6)
.remove();
.call(xAxis.scale(x1));
});
d3.timer.flush();
}

// left, right, top, bottom
bullet.orient = function(x) {
bullet.orient = function(_) {
if (!arguments.length) return orient;
orient = x;
orient = _ + "";
reverse = orient == "right" || orient == "bottom";
xAxis.orient((vertical = orient == "top" || orient == "bottom") ? "left" : "bottom");
return bullet;
};

// ranges (bad, satisfactory, good)
bullet.ranges = function(x) {
bullet.ranges = function(_) {
if (!arguments.length) return ranges;
ranges = x;
ranges = _;
return bullet;
};

// markers (previous, goal)
bullet.markers = function(x) {
bullet.markers = function(_) {
if (!arguments.length) return markers;
markers = x;
markers = _;
return bullet;
};

// measures (actual, forecast)
bullet.measures = function(x) {
bullet.measures = function(_) {
if (!arguments.length) return measures;
measures = x;
measures = _;
return bullet;
};

bullet.width = function(x) {
bullet.width = function(_) {
if (!arguments.length) return width;
width = x;
width = +_;
return bullet;
};

bullet.height = function(x) {
bullet.height = function(_) {
if (!arguments.length) return height;
height = x;
return bullet;
};

bullet.tickFormat = function(x) {
if (!arguments.length) return tickFormat;
tickFormat = x;
height = +_;
return bullet;
};

bullet.duration = function(x) {
bullet.duration = function(_) {
if (!arguments.length) return duration;
duration = x;
duration = +_;
return bullet;
};

return bullet;
return d3.rebind(bullet, xAxis, "tickFormat");
};

function bulletRanges(d) {
Expand Down

0 comments on commit c0c9e10

Please sign in to comment.