diff --git a/src/burnify.css b/src/burnify.css
index 09702b4..6ddcf16 100644
--- a/src/burnify.css
+++ b/src/burnify.css
@@ -39,6 +39,18 @@
cursor: pointer;
}
+.burnify .barPlanned {
+ fill: oldlace;
+}
+
+.burnify .barPlanned:hover {
+ fill: ivory;
+ stroke-width: 1px;
+ stroke-dasharray: 4, 4;
+ stroke: yellow;
+ cursor: pointer;
+}
+
.burnify .line {
stroke: #1d7fb3;
stroke-width: 2px;
diff --git a/src/burnify.js b/src/burnify.js
index f4b4cd0..9a151c8 100644
--- a/src/burnify.js
+++ b/src/burnify.js
@@ -14,10 +14,10 @@ Burnify = function(selector, project, width, height) {
this.chartTargetSelector = selector;
this.chartMargins = { top: 40, right: 30, bottom: 20, left: 30 }
this.setDimensions(width, height);
-
+ this.setStyle('scope');
+
// Chart rendering
return this;
-
};
/*
@@ -38,10 +38,10 @@ Burnify.prototype.getDimensions = function() {
Burnify.prototype.setDimensions = function(width, height, margins) {
if (margins) {
- this.chartMarginss.top = margins.top || this.chartMarginss.top;
- this.chartMarginss.left = margins.left || this.chartMarginss.left;
- this.chartMarginss.right = margins.right || this.chartMarginss.right;
- this.chartMarginss.bottom = margins.bottom || this.chartMarginss.bottom;
+ this.chartMargins.top = margins.top || this.chartMargins.top;
+ this.chartMargins.left = margins.left || this.chartMargins.left;
+ this.chartMargins.right = margins.right || this.chartMargins.right;
+ this.chartMargins.bottom = margins.bottom || this.chartMargins.bottom;
}
this.chartDimensions = {
@@ -49,16 +49,26 @@ Burnify.prototype.setDimensions = function(width, height, margins) {
height: height - this.chartMargins.top - this.chartMargins.bottom,
margin: this.chartMargins
}
+
+ return this;
+}
+
+Burnify.prototype.setStyle = function(style) {
+ if (!(style in ['scope', 'sprint', 'cross', 'plain'])) {
+ style = 'scope';
+ }
+ this.chartStyle = style;
}
Burnify.prototype.draw = function() {
this.burnify(this);
}
-Burnify.prototype.onSprintBarClick = function(sprintNumber, sprint) { }
-Burnify.prototype.onFullScopeAreaClick = function(burnifyProject) { console.log('Full scope area clicked'); console.log(burnifyProject) }
-Burnify.prototype.onDoneScopeAreaClick = function(burnifyProject) { console.log('Done scope area clicked'); }
-Burnify.prototype.onOutScopeAreaClick = function(burnifyProject) { console.log('Out scope area clicked'); }
+Burnify.prototype.onPlannedSprintBarClick = function(sprintNumber, sprint) { }
+Burnify.prototype.onDoneSprintBarClick = function(sprintNumber, sprint) { }
+Burnify.prototype.onFullScopeAreaClick = function(burnifyProject) { }
+Burnify.prototype.onDoneScopeAreaClick = function(burnifyProject) { }
+Burnify.prototype.onOutScopeAreaClick = function(burnifyProject) { }
/*
* Functional structure
@@ -75,9 +85,11 @@ Burnify.prototype.burnify = function(meta) {
var x = createX();
var y0 = createY0();
var y1 = createY1();
+ var y2 = createY2();
renderScopeArea(x, y0);
- renderDoneBars(x, y1);
+ renderSprintPlannedBars(x, y1);
+ renderSprintDoneBars(x, y2);
renderProjectLimit(x, y0);
renderProjectMVP(x, y0);
renderProductBurnLines(x, y0);
@@ -129,7 +141,7 @@ Burnify.prototype.burnify = function(meta) {
function createY1() {
var min = 0;
var max = d3.max(data, function (d) {
- return d.done;
+ return d.planned == undefined ? 0 : d.planned;
}) * 1.5;
var y1 = d3.scale.linear().domain([min, max]).range([dim.height, 0]);
@@ -150,6 +162,30 @@ Burnify.prototype.burnify = function(meta) {
return y1;
}
+ function createY2() {
+ var min = 0;
+ var max = d3.max(data, function (d) {
+ return d.done == undefined ? 0 : d.done;
+ }) * 1.5;
+
+ var y2 = d3.scale.linear().domain([min, max]).range([dim.height, 0]);
+
+ function dontcall() {
+ var yAxisRight = d3.svg.axis()
+ .scale(y2)
+ .ticks(8)
+ .outerTickSize(0)
+ .orient("right");
+
+ svg.append("g")
+ .attr("class", "y axis axisRight")
+ .attr("transform", "translate(" + (dim.width) + ",0)")
+ .call(yAxisRight);
+ }
+
+ return y2;
+ }
+
function renderProductBurnLines(x, y0) {
var dotOffset = 4;
@@ -251,11 +287,11 @@ Burnify.prototype.burnify = function(meta) {
return lines;
}
- function renderDoneBars(x, y1) {
+ function renderSprintBars(x, y, field, clazz, onClickCallback) {
var bars = svg.selectAll(".bar").data(data).enter();
bars.append("rect")
- .attr("class", "bar")
+ .attr("class", clazz)
.attr("x", function (d) {
return x(d.sprint);
})
@@ -263,8 +299,8 @@ Burnify.prototype.burnify = function(meta) {
.attr("y", dim.height)
.attr("height", 0)
.on("click", function(d) {
- meta.onSprintBarClick(d.index, d);
- })
+ onClickCallback(d.index, d);
+ })
.transition()
.ease("linear")
.delay(function (d, i) {
@@ -272,13 +308,21 @@ Burnify.prototype.burnify = function(meta) {
})
.duration(500)
.attr("y", function (d) {
- return y1(d.done);
+ var pts = (d[field] == undefined ? 0 : d[field]);
+ return y(pts);
})
.attr("height", function (d, i, j) {
- return dim.height - y1(d.done);
+ var pts = (d[field] == undefined ? 0 : d[field]);
+ return dim.height - y(pts);
});
+ }
- return bars;
+ function renderSprintPlannedBars(x, y) {
+ renderSprintBars(x, y, 'planned', 'barPlanned', meta.onPlannedSprintBarClick);
+ }
+
+ function renderSprintDoneBars(x, y) {
+ renderSprintBars(x, y, 'done', 'bar', meta.onDoneSprintBarClick);
}
function renderScopeArea(x, y0) {
@@ -350,7 +394,6 @@ Burnify.prototype.burnify = function(meta) {
}
});
-
svg.selectAll("." + clazz)
.data(stack)
.transition()
@@ -378,7 +421,7 @@ Burnify.prototype.burnify = function(meta) {
});
var doneStack = scopeStack(stack, data, 0, 0, function (d) {
- return d.totalDone;
+ return d.totalDone == undefined ? 0 : d.totalDone;
});
var outData = filterOut(data);
@@ -486,13 +529,18 @@ Burnify.prototype.burnify = function(meta) {
var added = sprint.added ? sprint.added : 0;
var removed = sprint.removed ? sprint.removed : 0;
- remaining = remaining - sprint.done + added - removed;
+ var hasPlannedPoints = (sprint.planned != undefined && sprint.planned > 0);
+ var hasDonePoints = (sprint.done != undefined && sprint.done > 0);
+ var pointsTaken = hasDonePoints ? sprint.done : (hasPlannedPoints ? sprint.planned : 0);
+
+ remaining = remaining - pointsTaken + added - removed;
points = points + added - removed;
- totalDone += sprint.done;
+ totalDone += (sprint.done == undefined ? 0 : sprint.done);
return {
index: i,
sprint: '' + (i + 1),
+ planned: sprint.planned,
done: sprint.done,
remaining: remaining,
points: points,
@@ -502,7 +550,8 @@ Burnify.prototype.burnify = function(meta) {
});
var mean = d3.mean(data, function (d) {
- return d.done;
+ var donePts = d.done == undefined ? 0 : d.done;
+ return donePts;
});
do {
diff --git a/test/products.html b/test/products.html
index 1f958e2..0fc85b8 100755
--- a/test/products.html
+++ b/test/products.html
@@ -13,15 +13,15 @@
-->
-
+
-
+