block by jeremycflin b6c4d1d08ee3bf6caee9d0a8c524dcb1

Reusable Area Chart: Ladybug group interactions

Full Screen

This example is code originally written by Mike Bostock in 2012 as part of his tutorial Towards Reusable Charts. Curran put together a bl.ock Towards Reusable Charts Example based on the post which I forked from to create this bl.ock and learn more about re-usable charts and a step forward to write Ladybug for web.

Here are some learning resources related to this example from Curran’s bl.ock:

forked from mostaphaRoudsari‘s block: Reusable Area Chart: Ladybug group interactions

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Reusable Chart Example</title>
    <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="time-series-chart.js"></script>
    <style>

      .axis text {
        font: 10px sans-serif;
      }

      .axis path,
      .axis line {
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
      }

      .line {
        fill: none;
        stroke: #000;
        stroke-width: 0.5px;
      }

      .area {
        fill: #ffbb8e;
      }

    </style>
  </head>
  <body>
    <p id="example">
    <script>

      var chart = timeSeriesChart()
          .x(function(d) { return formatDate(d.dt); })
          .y(function(d) { return +d.total; })
      		.width(940)
					.height(420)
      		.margin({top: 40, right: 30, bottom: 20, left: 30});
      
      var formatDate = d3.time.format("%Y-%m-%d %I:00:00").parse;
    
      d3.json("interactions.json", function(error, data) {
        
        data.forEach(function(d){
          // calculate total interactions
          d['total'] = d.reps + d.cmnts + d.dscs;
        });
        
        d3.select("#example")
            .datum(data)
            .call(chart);
      });

    </script>
  </body>
</html>

time-series-chart.js

function timeSeriesChart() {
  var margin = {top: 20, right: 20, bottom: 20, left: 20},
      width = 760,
      height = 120,
      xValue = function(d) { return d[0]; },
      yValue = function(d) { return d[1]; },
      xScale = d3.time.scale(),
      yScale = d3.scale.linear(),
      xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 0),
			yAxis = d3.svg.axis().scale(yScale).orient("left"),
      area = d3.svg.area().interpolate('step').x(X).y1(Y),
      line = d3.svg.line().interpolate('step').x(X).y(Y);

  function chart(selection) {
    selection.each(function(data) {

      // Convert data to standard representation greedily;
      // this is needed for nondeterministic accessors.
      data = data.map(function(d, i) {
        return [xValue.call(data, d, i), yValue.call(data, d, i)];
      });

      // Update the x-scale.
      xScale
          .domain(d3.extent(data, function(d) { return d[0]; }))
          .range([0, width - margin.left - margin.right]);

      // Update the y-scale.
      yScale
          .domain([0, d3.max(data, function(d) { return d[1]; })])
          .range([height - margin.top - margin.bottom, 0]);

      // Select the svg element, if it exists.
      var svg = d3.select(this).selectAll("svg").data([data]);

      // Otherwise, create the skeletal chart.
      var gEnter = svg.enter().append("svg").append("g");
      gEnter.append("path").attr("class", "area");
      gEnter.append("path").attr("class", "line");
      gEnter.append("g").attr("class", "x axis");
			gEnter.append("g").attr("class", "y axis");

      // Update the outer dimensions.
      svg .attr("width", width)
          .attr("height", height);

      // Update the inner dimensions.
      var g = svg.select("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

      // Update the area path.
      g.select(".area")
          .attr("d", area.y0(yScale.range()[0]));

      // Update the line path.
      g.select(".line")
          .attr("d", line);

      // Update the x-axis.
      g.select(".x.axis")
          .attr("transform", "translate(0," + yScale.range()[0] + ")")
          .call(xAxis);
      
      // Update the y-axis.
      g.select(".y.axis")
          .call(yAxis);
    });
  }

  // The x-accessor for the path generator; xScale ∘ xValue.
  function X(d) {
    return xScale(d[0]);
  }

  // The x-accessor for the path generator; yScale ∘ yValue.
  function Y(d) {
    return yScale(d[1]);
  }

  chart.margin = function(_) {
    if (!arguments.length) return margin;
    margin = _;
    return chart;
  };

  chart.width = function(_) {
    if (!arguments.length) return width;
    width = _;
    return chart;
  };

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

  chart.x = function(_) {
    if (!arguments.length) return xValue;
    xValue = _;
    return chart;
  };

  chart.y = function(_) {
    if (!arguments.length) return yValue;
    yValue = _;
    return chart;
  };

  return chart;
}