block by denisemauldin c0dc9715d60b33fda510dc57ed892702

c0dc9715d60b33fda510

Full Screen

forked from BenjiFischman‘s block:

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Benji's First Block</title>
  <script src="https://d3js.org/d3.v4.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="local.js"></script>
  <link rel='stylesheet' href='style.css'/>
</head>
<body>



     <div class="graph-wrapper" id="one"></div>



</body>
</html> 

local.js

$(function(){
 var parseDate = d3.timeParse("%b %d, '%y");
     var yObjs = {
      "Engagment" : {column: "Engagment"},
      "Diversity" : {column: "Diversity"},
      "Daily_Message" : {column: "Daily_Message"},
      "Relapses" : {column: "Relapses"}
    }

    var axisLabels = {xAxis: 'Time', yAxis: 'Usage'};

    var xName = "Time";
    var parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S");

    d3.json('output.json', function(err, data){
       data.forEach(function (d) {
        d.Time = d.Time
          switch(d.dCode){
            case "RELAPSE_DURATION_1-10":
              d.relapse = 1;
              break;
            case "RELAPSE_DURATION_11-30":
              d.relapse = 2;
              break;
            case "RELAPSE_DURATION_30+":
              d.relapse = 3;
              break;
            default:
            d.relapse = 0;
          }
          d.Time = parseTime(d.Time);
          d.Engagment = +d.Engagment;
          d.Diversity = +d.aDiversity;
          d.Daily_Message = +d.dailyMsg;
          d.relapse = d.relapse / 3;
          d.Relapses = d.relapse;

        })

     var graphOne = createGraph(data, xName, yObjs, axisLabels);
     graphOne.bind("#one");
     graphOne.render();
});

});

function createGraph(dataset, xName, yObjs, axisLables){
 var color = d3.scaleOrdinal(d3.schemeCategory10);
    var graphObj = {};
    var relapse_cols = ["#ff0000", "#ab0000", "#460000"];
    graphObj.relapse_cols = d3.scaleOrdinal().range(relapse_cols);
    graphObj.data = dataset;
    graphObj.relapse_data = [];
    graphObj.data.forEach(function(d){
      if(d.relapse != 0){
        var x = d;
        d.y = 1;
        graphObj.relapse_data.push(x);

    }
    });

    graphObj.xAxisLable = axisLables.xAxis;
    graphObj.yAxisLable = axisLables.yAxis;
    var marigin = {top: 30,
      right: 20,
      bottom: 30, 
      left: 50};

      graphObj.marigin = marigin;

      var width = 1000 - marigin.left - marigin.right;
      graphObj.width = width;
      var height = 300 - marigin.top - marigin.bottom;
      graphObj.height = height;

      var parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S");



  // So we can pass the x and y as strings when creating the function
  graphObj.xFunct = function(d){return d[xName]};

  // For each yObjs argument, create a yFunction
  function getYFn(column) {
    return function (d) {
      return d[column];
    };
  }

    // Object instead of array
    graphObj.yFuncts = [];
    for (var y  in yObjs) {
      yObjs[y].name = y;
        yObjs[y].yFunct = getYFn(yObjs[y].column); //Need this  list for the ymax function
        graphObj.yFuncts.push(yObjs[y].yFunct);
      }

      graphObj.formatAsNumber = d3.format(".0f");
      graphObj.formatAsDecimal = d3.format(".2f");
      graphObj.formatAsLongDecimal = d3.format(".4f");
      graphObj.formatAsTime = d3.timeFormat("%b %d, '%y");
      graphObj.formatAsFloat = function (d) {
        if (d % 1 !== 0) {
          return d3.format(".2f")(d);
        } else {
          return d3.format(".0f")(d);
        }
        
      };

      graphObj.xFormatter = graphObj.formatAsTime;
      graphObj.yFormatter = graphObj.formatAsLongDecimal;

     graphObj.bisectYear = d3.bisector(graphObj.xFunct).left; //< Can be overridden in definition

//Create scale functions
    graphObj.xScale = d3.scaleTime().range([0, graphObj.width]).domain(d3.extent(graphObj.data, graphObj.xFunct)); //< Can be overridden in definition

// Get the max of every yFunct
graphObj.max = function (fn) {
  return d3.max(graphObj.data, fn);
};
var maxDomain = d3.max(graphObj.yFuncts.map(graphObj.max));
//compute max for each variable and divide  each series by its max value
graphObj.yScale = d3.scaleLinear().range([graphObj.height, 0]).domain([0, maxDomain]);

    graphObj.formatAsYear = d3.format("");  //<---------- might need to adjust this fpr axis labels

    graphObj.xAxis = d3.axisBottom().scale(graphObj.xScale).tickFormat(graphObj.xFormatter);

    graphObj.yAxis = d3.axisLeft().scale(graphObj.yScale).tickFormat(graphObj.yFormatter);

    // Build line building functions
    function getYScaleFn(yObj) {
      return function (d) {
        if (d.relapse > 0) {          
          return graphObj.yScale(maxDomain);
        } else {
        return graphObj.yScale(yObjs[yObj].yFunct(d));
        }
      };
    }
    for (var yObj in yObjs) {
     if (yObj == "Relapses"){
      yObjs[yObj].line = d3.line()
                         .x(function (d) {
                           return graphObj.xScale(graphObj.xFunct(d));
                         })
                         .y(getYScaleFn(yObj))
                         .curve(d3.curveBasis);
       
       
       
      }else{
        yObjs[yObj].line = d3.line()
                              .x(function (d) {
                                  return graphObj.xScale(graphObj.xFunct(d));
                              })
                              .y(getYScaleFn(yObj))
                              .curve(d3.curveBasis);
      }}

    graphObj.svg;
    
// Change graph size according to window size

graphObj.update_svg_size = function () {
  graphObj.width = parseInt(graphObj.graphDiv.style("width"), 10) - (graphObj.marigin.left + graphObj.marigin.right);

  graphObj.height = parseInt(graphObj.graphDiv.style("height"), 10) - (graphObj.marigin.top + graphObj.marigin.bottom);

  /* Update the range of the scale with new width/height */
  graphObj.xScale.range([0, graphObj.width]);
  graphObj.yScale.range([graphObj.height, 0]);

  if (!graphObj.svg) {return false;}

  /* Else Update the axis with the new scale */
  graphObj.svg.select('.x.axis').attr("transform", "translate(0," + graphObj.height + ")").call(graphObj.xAxis);
  graphObj.svg.select('.x.axis .label').attr("x", graphObj.width / 2);

  graphObj.svg.select('.y.axis').call(graphObj.yAxis);
  graphObj.svg.select('.y.axis .label').attr("x", -graphObj.height / 2);

  /* Force D3 to recalculate and update the line */
  for (var y  in yObjs) {
    yObjs[y].path.attr("d", yObjs[y].line);
    console.log("y check"+ JSON.stringify(y));
  }


  d3.selectAll(".focus.line").attr("y2", graphObj.height);

  graphObj.graphDiv.select('svg').attr("width", graphObj.width + (graphObj.marigin.left + graphObj.marigin.right)).attr("height", graphObj.height + (graphObj.marigin.top + graphObj.marigin.bottom));

  graphObj.svg.select(".overlay").attr("width", graphObj.width).attr("height", graphObj.height);
  return graphObj;
};

graphObj.bind = function (selector) {
  graphObj.mainDiv = d3.select(selector);
        // Add all the divs to make it centered and responsive
        graphObj.mainDiv.append("div").attr("class", "inner-wrapper").append("div").attr("class", "outer-box").append("div").attr("class", "inner-box");
        graphSelector = selector + " .inner-box";
        graphObj.graphDiv = d3.select(graphSelector);
        d3.select(window).on('resize.' + graphSelector, graphObj.update_svg_size);
        graphObj.update_svg_size();
        return graphObj;
      };

    graphObj.render = function () {
        //Create SVG element
        graphObj.svg = graphObj.graphDiv.append("svg").attr("class", "graph-area").attr("width", graphObj.width + (graphObj.marigin.left + graphObj.marigin.right)).attr("height", graphObj.height + (graphObj.marigin.top + graphObj.marigin.bottom)).append("g").attr("transform", "translate(" + graphObj.marigin.left + "," + graphObj.marigin.top + ")");
        // Draw Lines
        for (var y  in yObjs) {
          if(y == "Relapses"){

          //standard approach
          //Relapse logic handled in line generator
          //if else statment left for debugging purposes
          yObjs[y].path = graphObj.svg.append("path").datum(graphObj.data).attr("class", "line").attr("d", yObjs[y].line).style("stroke-width", "2px").style("stroke", color(y)).attr("data-series", y).on("mouseover", function () {
            focus.style("display", null);
          }).on("mouseout", function () {
            focus.transition().delay(700).style("display", "none");
          }).on("mousemove", mousemove);

          } else{
          yObjs[y].path = graphObj.svg.append("path").datum(graphObj.data).attr("class", "line").attr("d", yObjs[y].line).style("stroke", color(y)).attr("data-series", y).on("mouseover", function () {
            focus.style("display", null);
          }).on("mouseout", function () {
            focus.transition().delay(700).style("display", "none");
          }).on("mousemove", mousemove);
        }}
        // Draw Axis
        graphObj.svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + graphObj.height + ")").call(graphObj.xAxis).append("text").attr("class", "label").attr("x", graphObj.width / 2).attr("y", 30).style("text-anchor", "middle").text(graphObj.xAxisLable);

        graphObj.svg.append("g").attr("class", "y axis").call(graphObj.yAxis).append("text").attr("class", "label").attr("transform", "rotate(-90)").attr("y", -42).attr("x", -graphObj.height / 2).attr("dy", ".71em").style("text-anchor", "middle").text(graphObj.yAxisLable);

        //Draw tooltips
        var focus = graphObj.svg.append("g").attr("class", "focus").style("display", "none");

        for (var y  in yObjs) {
          yObjs[y].tooltip = focus.append("g");
          yObjs[y].tooltip.append("circle").attr("r", 5);
          yObjs[y].tooltip.append("rect").attr("x", 8).attr("y","-5").attr("width",22).attr("height",'0.75em');
          yObjs[y].tooltip.append("text").attr("x", 9).attr("dy", ".35em");
        }

        // Year label
        focus.append("text").attr("class", "focus year").attr("x", 9).attr("y", 7);
        // Focus line
        focus.append("line").attr("class", "focus line").attr("y1", 0).attr("y2", graphObj.height);

        //Draw legend
        var legend = graphObj.mainDiv.append('div').attr("class", "legend");
        for (var y  in yObjs) {
          series = legend.append('div');
          series.append('div').attr("class", "series-marker").style("background-color", color(y));
          series.append('p').text(y);
          yObjs[y].legend = series;
        }

        // Overlay to capture hover
        graphObj.svg.append("rect").attr("class", "overlay").attr("width", graphObj.width).attr("height", graphObj.height).on("mouseover", function () {
          focus.style("display", null);
        }).on("mouseout", function () {
          focus.style("display", "none");
        }).on("mousemove", mousemove);

        return graphObj;
        function mousemove() {
          //this is wht the NAN error is happening
          var x0 = graphObj.xScale.invert(d3.mouse(this)[0]), i = graphObj.bisectYear(dataset, x0, 1), d0 = graphObj.data[i - 1], d1 = graphObj.data[i];
          try {
            var d = x0 - graphObj.xFunct(d0) > graphObj.xFunct(d1) - x0 ? d1 : d0;
          } catch (e) { return;}
          minY = graphObj.height;
          for (var y  in yObjs) {
        //    console.log("tooltip y check "+ y);
            yObjs[y].tooltip.attr("transform", "translate(" + graphObj.xScale(graphObj.xFunct(d)) + "," + graphObj.yScale(yObjs[y].yFunct(d)) + ")");
            yObjs[y].tooltip.select("text").text(graphObj.yFormatter(yObjs[y].yFunct(d)));
            minY = Math.min(minY, graphObj.yScale(yObjs[y].yFunct(d)));
          }
          //console.log(minY);
          focus.select(".focus.line").attr("transform", "translate(" + graphObj.xScale(graphObj.xFunct(d)) + ")").attr("y1", minY);
          focus.select(".focus.year").text("Date: " + graphObj.xFormatter(graphObj.xFunct(d)));
        }

      };
      return graphObj;
    }

style.css

body {
  padding: 50px;
  font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}

a {
  color: #00B7FF;
}

ul {
list-style-type:none;
}

#user-wrapper {
	position:relative;
	margin: 5% auto 5% auto;
	min-height: 250px;
	overflow: hidden;

}


#summary-wrapper{
	float: left;
	min-height: 250px;
	width:20%;
	overflow: hidden;
}

.graph-wrapper{
	float:right;
	overflow: hidden;
	min-height: 250px;
	width:80%;
}




.tooltip {
  background: #eee;
  box-shadow: 0 0 5px #999999;
  color: #333;
  display: none;
  font-size: 12px;
  left: 130px;
  padding: 10px;
  position: absolute;
  text-align: center;
  top: 95px;
  width: 80px;
  z-index: 10;
}
.axis { font: 14px sans-serif; }

/*.line {
  fill: none;
  stroke: steelblue;
  shape-rendering: crispEdges;
  stroke-width: 2px;
}*/

/*#dailyMsg_plot {
  fill: none;
  stroke: "#28d41c" !important;
  shape-rendering: crispEdges;
  stroke-width: 2px;
}

#diversity_plot {
  fill: none;
  stroke: "#7721d9" !important;
  shape-rendering: crispEdges;
  stroke-width: 2px;
}
*/

.graph-wrapper {
    float:center;
    max-width: 950px;
    min-width: 304px;
    margin: 0 auto;
    background-color: #FAF7F7;
}

.graph-wrapper .inner-wrapper {
    position: relative;
    padding-bottom: 50%;
    width: 100%;
}

.graph-wrapper .outer-box {
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
}

.graph-wrapper .inner-box {
    width: 100%;
    height: 100%;
}

.graph-wrapper text {
  font-family: sans-serif;
  font-size: 11px;
}

.graph-wrapper y-axis text {
	rotate: -65;
}

.graph-wrapper p {
    font-size: 16px;
    margin-top:5px;
    margin-bottom: 40px;
}

.graph-wrapper .axis path,
.graph-wrapper .axis line {
    fill: none;
    stroke: #1F1F2E;
    stroke-opacity: 0.7;
    shape-rendering: crispEdges;

}
.graph-wrapper .axis path {
  stroke-width: 2px;
}

.graph-wrapper .line {
  fill: none;
  stroke: steelblue;
  stroke-width: 5px;
}

.graph-wrapper .legend  {
    min-width: 200px;
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    font-size: 16px;
    padding: 10px 40px;
}
.graph-wrapper .legend > div {
    margin: 0px 25px 10px 0px;
    flex-grow: 0;
}
.graph-wrapper .legend p {
    display:inline;
    font-size: 0.8em;
    font-family: sans-serif;
    font-weight: 600;
}
.graph-wrapper .legend .series-marker {
    height: 1em;
    width: 1em;
    border-radius: 35%;
    background-color: crimson;
    display: inline-block;
    margin-right: 4px;
    margin-bottom: -0.16rem;
}

.graph-wrapper .overlay {
  fill: none;
  pointer-events: all;
}

.graph-wrapper .focus circle {
  fill: black;
  stroke: black;
  stroke-width: 2px;
  fill-opacity: 15%;
}
.graph-wrapper .focus rect {
    fill: lightblue;
    opacity: 0.4;
    border-radius: 2px;
}
.graph-wrapper .focus.line {
    stroke: steelblue;
    stroke-dasharray: 2,5;
    stroke-width: 2;
    opacity: 0.5;
}
@media (max-width:500px){
    .graph-wrapper .line {stroke-width: 3px;}
    .graph-wrapper .legend {font-size: 14px;}
}