D3.jsでバーンダウンチャートを書く

D3.jsを使ってバーンダウンチャートを書いてみた

```js:burndownchart.js
function burndownchart(idealData, actualData) {
  var margin = {
    top: 10,
    bottom: 50,
    left: 50,
    right: 30
  };

  var screen = {
    width: 500,
    height: 500
  };

  var xScale = d3.time.scale()
                 .domain(d3.extent(idealData, function(d) { return d.date }))
                 .range([margin.left, screen.width - margin.right])
                 ;
  var yScale = d3.scale.linear()
                 .domain([0, d3.max(idealData, function(d) { return d.value })])
                 .range([screen.height - margin.bottom, margin.top])
                 ;

  var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom")
    .tickFormat(d3.time.format("%Y-%m-%d"))
    ;

  var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient("left")
    .ticks(5)
    ;

  var svg = d3.select("body")
              .append("svg")
              .attr("width", screen.width)
              .attr("height", screen.height)
              ;

  svg.append("g")
     .attr("class", "axis")
     .attr("transform", "translate(0, " + (screen.height - margin.bottom) + ")")
     .call(xAxis)
     .selectAll("text")
     .style("text-anchor", "end")
     .attr("transform", "rotate(-30)")
     ;

  svg.append("g")
     .attr("class", "axis")
     .attr("transform", "translate(" + margin.left + ", 0)")
     .call(yAxis)
     ;

  var idealLine = d3.svg.line()
                    .x(function(d) { return xScale(d.date) })
                    .y(function(d) { return yScale(d.value) })
                    ;

  var actualLine = d3.svg.line()
                    .x(function(d) { return xScale(d.date) })
                    .y(function(d) { return yScale(d.value) })
                    ;

  svg.selectAll("circle.point.actual")
     .data(actualData)
     .enter()
     .append("circle")
     .attr("cx", function(d) { return xScale(d.date)})
     .attr("cy", function(d) { return yScale(d.value) })
     .attr("r", 2)
     .attr("class", "point actual")
     ;

  svg.selectAll("circle.point.ideal")
     .data(idealData)
     .enter()
     .append("circle")
     .attr("cx", function(d) { return xScale(d.date)})
     .attr("cy", function(d) { return yScale(d.value) })
     .attr("r", 2)
     .attr("class", "point ideal")
     ;

  svg.append("path")
     .datum(idealData)
     .attr("class", "line ideal")
     .attr("d", idealLine)
     ;

  svg.append("path")
     .datum(actualData)
     .attr("class", "line actual")
     .attr("d", actualLine)
     ;
}
```

```css:burndownchart.css
.axis path,
.axis line {
  fill: none;
  stroke: black;
  shape-rendering: crispEdges;
  stroke-width: 1.5px;
}
.axis text {
  font-family: sans-serif;
  font-size: 11px
}

.point {
  stroke-width: 1.5px;
}

.point.ideal {
  fill: blue;
  stroke: blue;
}
.point.actual {
  fill: orange;
  stroke: orange;
}

.line {
  fill: none;
  stroke-width: 1.5px;
}

.line.ideal {
  stroke: blue;
}
.line.actual {
  stroke: orange;
}
```

```html:sample.html
<!DOCTYPE html>
   <html lang="en">
      <head>
         <meta charset="utf-8">
         <title>Burndown Chart Sample</title>
         <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
         <script type="text/javascript" src="burndownchart.js"></script>
         <link rel="stylesheet" type="text/css" href="burndownchart.css">
      </head>

      <body>
         <script type="text/javascript">
           var parseDate = d3.time.format("%Y/%m/%d").parse;

           var idealdata = [
              {date: parseDate("2014/1/1"), value: 50},
              {date: parseDate("2014/1/2"), value: 45},
              {date: parseDate("2014/1/3"), value: 40},
              {date: parseDate("2014/1/4"), value: 35},
              {date: parseDate("2014/1/5"), value: 30},
              {date: parseDate("2014/1/6"), value: 25},
              {date: parseDate("2014/1/7"), value: 20},
              {date: parseDate("2014/1/8"), value: 15},
              {date: parseDate("2014/1/9"), value: 10},
              {date: parseDate("2014/1/10"),value:  5},
              {date: parseDate("2014/1/11"),value:  0}
           ];

           var actualdata = [
              {date: parseDate("2014/1/1"), value: 45},
              {date: parseDate("2014/1/2"), value: 39},
              {date: parseDate("2014/1/4"), value: 32},
              {date: parseDate("2014/1/5"), value: 28},
              {date: parseDate("2014/1/7"), value: 26}
           ];

           burndownchart(idealdata, actualdata);
         </script>
      </body>
</html>
```
![sample.png](https://qiita-image-store.s3.amazonaws.com/0/44797/4f9eb50b-643b-2e3f-3cdc-149ecafc13e7.png)